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, 5 Jun 2015 10:42:11 +0000 (20:12 +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 4001dce8a3220231e26038995c21a211e261015f..d7ba09b75473156bbec654aedded412a2ccec116 100644 (file)
@@ -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
index 663a8713a72b63e7ce9416e6bebcbbe455619253..a947e8ef41dc519678cdbfe874ef7659f9d7af4b 100644 (file)
@@ -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;
index fe629902c132150b4c685777d114065370ca1d1b..e51f16b48e25edd1eff9b83a59b01972aa504eaf 100644 (file)
@@ -1,3 +1,11 @@
+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-06-02  Jiong Wang  <jiong.wang@arm.com>
 
        * ld-aarch64/emit-relocs-313.s: Use gotpage_lo15.
index 48aec4ae4fc1f6b6043cfc4112f90dbd8d60f0d9..976e89bc013afa82ed038b281121374e0df12ac5 100644 (file)
@@ -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 (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
This page took 0.055477 seconds and 4 git commands to generate.