summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlan Modra <amodra@gmail.com>2015-06-05 18:35:40 +0930
committerAlan Modra <amodra@gmail.com>2015-07-10 19:57:37 +0930
commit2bc6144cb70a4bd4129d12afe3313a20235fc31e (patch)
treeefa370fc907752efe1a9f0a07f24de20c570e9fa
parent21d697be19adab1b6df7090f05c629b0003adfa4 (diff)
downloadbinutils-gdb-2bc6144cb70a4bd4129d12afe3313a20235fc31e.tar.gz
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.
-rw-r--r--bfd/ChangeLog5
-rw-r--r--bfd/elf32-ppc.c52
-rw-r--r--ld/testsuite/ChangeLog7
-rw-r--r--ld/testsuite/ld-powerpc/powerpc.exp3
-rw-r--r--ld/testsuite/ld-powerpc/ppc476-shared.d30
-rw-r--r--ld/testsuite/ld-powerpc/ppc476-shared.lnk6
-rw-r--r--ld/testsuite/ld-powerpc/ppc476-shared.s13
-rw-r--r--ld/testsuite/ld-powerpc/ppc476-shared2.d12
8 files changed, 128 insertions, 0 deletions
diff --git a/bfd/ChangeLog b/bfd/ChangeLog
index 0893d392dc6..ab2bb509ca1 100644
--- a/bfd/ChangeLog
+++ b/bfd/ChangeLog
@@ -1,6 +1,11 @@
2015-07-10 Alan Modra <amodra@gmail.com>
Apply from master
+ 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-04-23 Alan Modra <amodra@gmail.com>
* elf64-ppc.c (TOC_BASE_ALIGN): Define.
(ppc64_elf_next_toc_section): Align multi-got toc base.
diff --git a/bfd/elf32-ppc.c b/bfd/elf32-ppc.c
index d0559d1f728..ed199722e38 100644
--- a/bfd/elf32-ppc.c
+++ b/bfd/elf32-ppc.c
@@ -9428,6 +9428,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. */
@@ -9440,6 +9442,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;
diff --git a/ld/testsuite/ChangeLog b/ld/testsuite/ChangeLog
index c0be981bde3..7e9895da6c7 100644
--- a/ld/testsuite/ChangeLog
+++ b/ld/testsuite/ChangeLog
@@ -1,6 +1,13 @@
2015-07-10 Alan Modra <amodra@gmail.com>
Apply from master
+ 2015-06-05 Alan Modra <amodra@gmail.com>
+ * 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.
+
2015-04-23 Alan Modra <amodra@gmail.com>
* ld-powerpc/ambiguousv1.d: Update for aligned .got.
* ld-powerpc/ambiguousv1b.d: Likewise.
diff --git a/ld/testsuite/ld-powerpc/powerpc.exp b/ld/testsuite/ld-powerpc/powerpc.exp
index 8fc261eb65a..239aa9130ec 100644
--- a/ld/testsuite/ld-powerpc/powerpc.exp
+++ b/ld/testsuite/ld-powerpc/powerpc.exp
@@ -323,3 +323,6 @@ run_dump_test "attr-gnu-12-11"
run_dump_test "attr-gnu-12-21"
run_dump_test "vle-multiseg-6"
+
+run_dump_test "ppc476-shared"
+run_dump_test "ppc476-shared2"
diff --git a/ld/testsuite/ld-powerpc/ppc476-shared.d b/ld/testsuite/ld-powerpc/ppc476-shared.d
new file mode 100644
index 00000000000..8fda847b338
--- /dev/null
+++ b/ld/testsuite/ld-powerpc/ppc476-shared.d
@@ -0,0 +1,30 @@
+#source: ppc476-shared.s
+#as: -a32
+#ld: -melf32ppc -q -shared --ppc476-workaround -T ppc476-shared.lnk
+#objdump: -dr
+#target: powerpc*-*-*
+
+.*: file format .*
+
+Disassembly of section \.text:
+
+0+fffc <\.text>:
+ fffc: (48 01 00 04|04 00 01 48) b 20000 .*
+ 10000: (38 63 00 00|00 00 63 38) addi r3,r3,0
+ 1000[02]: R_PPC_ADDR16_LO .bss
+ \.\.\.
+ 1fff0: (42 9f 00 05|05 00 9f 42) bcl .*
+ 1fff4: (7d 28 02 a6|a6 02 28 7d) mflr r9
+ 1fff8: (3d 29 00 00|00 00 29 3d) addis r9,r9,0
+ 1fff[8a]: R_PPC_REL16_HA .bss\+0x[46]
+ 1fffc: (48 00 00 14|14 00 00 48) b 20010 .*
+ 20000: (3c 60 00 00|00 00 60 3c) lis r3,0
+ 2000[02]: R_PPC_ADDR16_HA .bss
+ 20004: (4b fe ff fc|fc ff fe 4b) b 10000 .*
+ 20008: (48 00 00 02|02 00 00 48) ba 0 .*
+ 2000c: (48 00 00 02|02 00 00 48) ba 0 .*
+ 20010: (39 29 01 00|00 01 29 39) addi r9,r9,256
+ 2001[02]: R_PPC_REL16_LO .bss\+0x1[ce]
+ 20014: (4b ff ff ec|ec ff ff 4b) b 20000 .*
+ 20018: (48 00 00 02|02 00 00 48) ba 0 .*
+ 2001c: (48 00 00 02|02 00 00 48) ba 0 .*
diff --git a/ld/testsuite/ld-powerpc/ppc476-shared.lnk b/ld/testsuite/ld-powerpc/ppc476-shared.lnk
new file mode 100644
index 00000000000..5339358dbdf
--- /dev/null
+++ b/ld/testsuite/ld-powerpc/ppc476-shared.lnk
@@ -0,0 +1,6 @@
+SECTIONS
+{
+ . = 0xfffc;
+ .text : { *(.text) }
+ .bss : { *(.bss) }
+}
diff --git a/ld/testsuite/ld-powerpc/ppc476-shared.s b/ld/testsuite/ld-powerpc/ppc476-shared.s
new file mode 100644
index 00000000000..6774badb17b
--- /dev/null
+++ b/ld/testsuite/ld-powerpc/ppc476-shared.s
@@ -0,0 +1,13 @@
+ .text
+ lis 3,x@ha
+ addi 3,3,x@l
+
+ .org 0xfff4
+ bcl 20,31,.+4
+0:
+ mflr 9
+ addis 9,9,x-0b@ha
+ addi 9,9,x-0b@l
+
+ .section .bss,"aw",@nobits
+x: .space 4
diff --git a/ld/testsuite/ld-powerpc/ppc476-shared2.d b/ld/testsuite/ld-powerpc/ppc476-shared2.d
new file mode 100644
index 00000000000..ebb8bf19ff7
--- /dev/null
+++ b/ld/testsuite/ld-powerpc/ppc476-shared2.d
@@ -0,0 +1,12 @@
+#source: ppc476-shared.s
+#as: -a32
+#ld: -melf32ppc -shared --ppc476-workaround -T ppc476-shared.lnk
+#objdump: -R
+#target: powerpc*-*-*
+
+.*: file format .*
+
+DYNAMIC RELOCATION RECORDS
+OFFSET TYPE VALUE
+0001000[02] R_PPC_ADDR16_LO \.text\+0x000200f4
+0002000[02] R_PPC_ADDR16_HA \.text\+0x000200f4