aboutsummaryrefslogtreecommitdiff
path: root/bfd
diff options
context:
space:
mode:
authorAlan Modra <amodra@gmail.com>2015-06-05 18:35:40 +0930
committerAlan Modra <amodra@gmail.com>2015-06-05 20:12:11 +0930
commitf8b447819b3d65c3bea65dee860110aa198c081e (patch)
tree9d43b6357d2341e839d71ee5b6b3babf64366a62 /bfd
parentbdd2d2b7e6fbe90a07bd631cb599266fc6e12b5e (diff)
downloadfsf-binutils-gdb-f8b447819b3d65c3bea65dee860110aa198c081e.zip
fsf-binutils-gdb-f8b447819b3d65c3bea65dee860110aa198c081e.tar.gz
fsf-binutils-gdb-f8b447819b3d65c3bea65dee860110aa198c081e.tar.bz2
ppc476 linker workaround shared lib fixes
When building a shared lib from non-PIC objects, we'll get dynamic text relocations. These need to move with any insns we move. Otherwise the dynamic reloc will modify the branch, resulting in crashes and other unpleasant behaviour. Also, ld -r --ppc476-workaround used with sufficiently aligned PIC objects needs a fix for emitted REL16 relocs. bfd/ * elf64-ppc.c (ppc_elf_relocate_section): Move dynamic text relocs with insns moved by --ppc476-workaround. Correct output of REL16 relocs. ld/testsuite/ * ld-powerpc/ppc476-shared.s, * ld-powerpc/ppc476-shared.lnk, * ld-powerpc/ppc476-shared.d, * ld-powerpc/ppc476-shared2.d: New tests. * ld-powerpc/powerpc.exp: Run them.
Diffstat (limited to 'bfd')
-rw-r--r--bfd/ChangeLog6
-rw-r--r--bfd/elf32-ppc.c52
2 files changed, 58 insertions, 0 deletions
diff --git a/bfd/ChangeLog b/bfd/ChangeLog
index 4001dce..d7ba09b 100644
--- a/bfd/ChangeLog
+++ b/bfd/ChangeLog
@@ -1,3 +1,9 @@
+2015-06-05 Alan Modra <amodra@gmail.com>
+
+ * elf64-ppc.c (ppc_elf_relocate_section): Move dynamic text
+ relocs with insns moved by --ppc476-workaround. Correct
+ output of REL16 relocs.
+
2015-06-01 Jiong Wang <jiong.wang@arm.com>
* elfnn-aarch64.c (aarch64_reloc_got_type): Support
diff --git a/bfd/elf32-ppc.c b/bfd/elf32-ppc.c
index 663a871..a947e8e 100644
--- a/bfd/elf32-ppc.c
+++ b/bfd/elf32-ppc.c
@@ -9608,6 +9608,8 @@ ppc_elf_relocate_section (bfd *output_bfd,
&& rel->r_offset >= offset
&& rel->r_offset < offset + 4)
{
+ asection *sreloc;
+
/* If the insn we are patching had a reloc, adjust the
reloc r_offset so that the reloc applies to the moved
location. This matters for -r and --emit-relocs. */
@@ -9620,6 +9622,56 @@ ppc_elf_relocate_section (bfd *output_bfd,
relend[-1] = tmp;
}
relend[-1].r_offset += patch_off - offset;
+
+ /* Adjust REL16 addends too. */
+ switch (ELF32_R_TYPE (relend[-1].r_info))
+ {
+ case R_PPC_REL16:
+ case R_PPC_REL16_LO:
+ case R_PPC_REL16_HI:
+ case R_PPC_REL16_HA:
+ relend[-1].r_addend += patch_off - offset;
+ break;
+ default:
+ break;
+ }
+
+ /* If we are building a PIE or shared library with
+ non-PIC objects, perhaps we had a dynamic reloc too?
+ If so, the dynamic reloc must move with the insn. */
+ sreloc = elf_section_data (input_section)->sreloc;
+ if (sreloc != NULL)
+ {
+ bfd_byte *slo, *shi, *srelend;
+ bfd_vma soffset;
+
+ slo = sreloc->contents;
+ shi = srelend
+ = slo + sreloc->reloc_count * sizeof (Elf32_External_Rela);
+ soffset = (offset + input_section->output_section->vma
+ + input_section->output_offset);
+ while (slo < shi)
+ {
+ bfd_byte *srel = slo + (shi - slo) / 2;
+ bfd_elf32_swap_reloca_in (output_bfd, srel, &outrel);
+ if (outrel.r_offset < soffset)
+ slo = srel + 1;
+ else if (outrel.r_offset > soffset + 3)
+ shi = srel;
+ else
+ {
+ bfd_byte *nextr = srel + sizeof (Elf32_External_Rela);
+ if (nextr != srelend)
+ {
+ memmove (srel, nextr, srelend - nextr);
+ srel = srelend - sizeof (Elf32_External_Rela);
+ }
+ outrel.r_offset += patch_off - offset;
+ bfd_elf32_swap_reloca_out (output_bfd, &outrel, srel);
+ break;
+ }
+ }
+ }
}
else
rel = NULL;