This is the mail archive of the
binutils@sourceware.org
mailing list for the binutils project.
ppc476 linker workaround shared lib fixes
- From: Alan Modra <amodra at gmail dot com>
- To: binutils at sourceware dot org
- Date: Fri, 5 Jun 2015 20:11:30 +0930
- Subject: ppc476 linker workaround shared lib fixes
- Authentication-results: sourceware.org; auth=none
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.
diff --git a/bfd/elf32-ppc.c b/bfd/elf32-ppc.c
index 663a871..48b120e 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;
diff --git a/ld/testsuite/ld-powerpc/powerpc.exp b/ld/testsuite/ld-powerpc/powerpc.exp
index 48aec4a..976e89b 100644
--- a/ld/testsuite/ld-powerpc/powerpc.exp
+++ b/ld/testsuite/ld-powerpc/powerpc.exp
@@ -325,3 +325,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 0000000..8fda847
--- /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 0000000..5339358
--- /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 0000000..6774bad
--- /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 0000000..ebb8bf1
--- /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
--
Alan Modra
Australia Development Lab, IBM