diff --git a/bfd/ChangeLog b/bfd/ChangeLog index 4001dce8a3..d7ba09b754 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,9 @@ +2015-06-05 Alan Modra + + * 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 * elfnn-aarch64.c (aarch64_reloc_got_type): Support diff --git a/bfd/elf32-ppc.c b/bfd/elf32-ppc.c index 663a8713a7..a947e8ef41 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/ChangeLog b/ld/testsuite/ChangeLog index fe629902c1..e51f16b48e 100644 --- a/ld/testsuite/ChangeLog +++ b/ld/testsuite/ChangeLog @@ -1,3 +1,11 @@ +2015-06-05 Alan Modra + + * 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 * ld-aarch64/emit-relocs-313.s: Use gotpage_lo15. diff --git a/ld/testsuite/ld-powerpc/powerpc.exp b/ld/testsuite/ld-powerpc/powerpc.exp index 48aec4ae4f..976e89bc01 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 0000000000..8fda847b33 --- /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 0000000000..5339358dbd --- /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 0000000000..6774badb17 --- /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 0000000000..ebb8bf19ff --- /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