]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
ppc476 linker workaround shared lib fixes
authorAlan Modra <amodra@gmail.com>
Fri, 5 Jun 2015 09:05:40 +0000 (18:35 +0930)
committerAlan Modra <amodra@gmail.com>
Fri, 10 Jul 2015 10:27:37 +0000 (19:57 +0930)
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.

bfd/ChangeLog
bfd/elf32-ppc.c
ld/testsuite/ChangeLog
ld/testsuite/ld-powerpc/powerpc.exp
ld/testsuite/ld-powerpc/ppc476-shared.d [new file with mode: 0644]
ld/testsuite/ld-powerpc/ppc476-shared.lnk [new file with mode: 0644]
ld/testsuite/ld-powerpc/ppc476-shared.s [new file with mode: 0644]
ld/testsuite/ld-powerpc/ppc476-shared2.d [new file with mode: 0644]

index 0893d392dc6ea94206619b7b47422edab2e77780..ab2bb509ca152691dcd03bead741b02b68a7116f 100644 (file)
@@ -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.
index d0559d1f728bee3f5d96d7e2370b14352d6ec694..ed199722e38f64d7ce78d95edca8d16f5e22bdda 100644 (file)
@@ -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;
index c0be981bde3dd0e01061ce874a7c9b4379e6a04c..7e9895da6c7a9c0cd12eba76fb58d097f28db643 100644 (file)
@@ -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.
index 8fc261eb65a5906fbff6f8c1be8c451a67a2b1da..239aa9130ecfc07a2fe08e74c94a6d1cbdb24a60 100644 (file)
@@ -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 (file)
index 0000000..8fda847
--- /dev/null
@@ -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 (file)
index 0000000..5339358
--- /dev/null
@@ -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 (file)
index 0000000..6774bad
--- /dev/null
@@ -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 (file)
index 0000000..ebb8bf1
--- /dev/null
@@ -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