diff options
-rw-r--r-- | bfd/ChangeLog | 9 | ||||
-rw-r--r-- | bfd/elf64-ppc.c | 117 | ||||
-rw-r--r-- | ld/testsuite/ChangeLog | 5 | ||||
-rw-r--r-- | ld/testsuite/ld-powerpc/powerpc.exp | 2 |
4 files changed, 95 insertions, 38 deletions
diff --git a/bfd/ChangeLog b/bfd/ChangeLog index 1bd89b7..93f8ff9 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,12 @@ +2011-11-08 Alan Modra <amodra@gmail.com> + + * elf64-ppc.c (struct ppc64_elf_obj_tdata): Rename + ha_relocs_not_using_r2 to unexpected_toc_insn. + (ok_lo_toc_insn): New function. + (ppc64_elf_edit_toc): Check insn on lo toc reloc. Emit warning. + (ppc64_elf_relocate_section): Don't check insn on lo toc reloc here. + Handle addic on lo toc reloc. + 2011-10-25 Alan Modra <amodra@gmail.com> Apply mainline patches diff --git a/bfd/elf64-ppc.c b/bfd/elf64-ppc.c index 837568c..93d1314 100644 --- a/bfd/elf64-ppc.c +++ b/bfd/elf64-ppc.c @@ -2614,8 +2614,9 @@ struct ppc64_elf_obj_tdata the reloc to be in the range -32768 to 32767. */ unsigned int has_small_toc_reloc : 1; - /* Set if toc/got ha relocs detected not using r2. */ - unsigned int ha_relocs_not_using_r2 : 1; + /* Set if toc/got ha relocs detected not using r2, or lo reloc + instruction not one we handle. */ + unsigned int unexpected_toc_insn : 1; }; #define ppc64_elf_tdata(bfd) \ @@ -8016,6 +8017,32 @@ adjust_toc_syms (struct elf_link_hash_entry *h, void *inf) return TRUE; } +/* Return TRUE iff INSN is one we expect on a _LO variety toc/got reloc. */ + +static bfd_boolean +ok_lo_toc_insn (unsigned int insn) +{ + return ((insn & (0x3f << 26)) == 14u << 26 /* addi */ + || (insn & (0x3f << 26)) == 32u << 26 /* lwz */ + || (insn & (0x3f << 26)) == 34u << 26 /* lbz */ + || (insn & (0x3f << 26)) == 36u << 26 /* stw */ + || (insn & (0x3f << 26)) == 38u << 26 /* stb */ + || (insn & (0x3f << 26)) == 40u << 26 /* lhz */ + || (insn & (0x3f << 26)) == 42u << 26 /* lha */ + || (insn & (0x3f << 26)) == 44u << 26 /* sth */ + || (insn & (0x3f << 26)) == 46u << 26 /* lmw */ + || (insn & (0x3f << 26)) == 47u << 26 /* stmw */ + || (insn & (0x3f << 26)) == 48u << 26 /* lfs */ + || (insn & (0x3f << 26)) == 50u << 26 /* lfd */ + || (insn & (0x3f << 26)) == 52u << 26 /* stfs */ + || (insn & (0x3f << 26)) == 54u << 26 /* stfd */ + || ((insn & (0x3f << 26)) == 58u << 26 /* lwa,ld,lmd */ + && (insn & 3) != 1) + || ((insn & (0x3f << 26)) == 62u << 26 /* std, stmd */ + && ((insn & 3) == 0 || (insn & 3) == 3)) + || (insn & (0x3f << 26)) == 12u << 26 /* addic */); +} + /* Examine all relocs referencing .toc sections in order to remove unused .toc entries. */ @@ -8270,11 +8297,13 @@ ppc64_elf_edit_toc (struct bfd_link_info *info) struct elf_link_hash_entry *h; Elf_Internal_Sym *sym; bfd_vma val; + enum {no_check, check_lo, check_ha} insn_check; r_type = ELF64_R_TYPE (rel->r_info); switch (r_type) { default: + insn_check = no_check; break; case R_PPC64_GOT_TLSLD16_HA: @@ -8283,24 +8312,49 @@ ppc64_elf_edit_toc (struct bfd_link_info *info) case R_PPC64_GOT_DTPREL16_HA: case R_PPC64_GOT16_HA: case R_PPC64_TOC16_HA: - { - bfd_vma off = rel->r_offset & ~3; - unsigned char buf[4]; - unsigned int insn; + insn_check = check_ha; + break; - if (!bfd_get_section_contents (ibfd, sec, buf, off, 4)) - { - free (used); - goto error_ret; - } - insn = bfd_get_32 (ibfd, buf); - if ((insn & ((0x3f << 26) | 0x1f << 16)) - != ((15u << 26) | (2 << 16)) /* addis rt,2,imm */) - ppc64_elf_tdata (ibfd)->ha_relocs_not_using_r2 = 1; - } + case R_PPC64_GOT_TLSLD16_LO: + case R_PPC64_GOT_TLSGD16_LO: + case R_PPC64_GOT_TPREL16_LO_DS: + case R_PPC64_GOT_DTPREL16_LO_DS: + case R_PPC64_GOT16_LO: + case R_PPC64_GOT16_LO_DS: + case R_PPC64_TOC16_LO: + case R_PPC64_TOC16_LO_DS: + insn_check = check_lo; break; } + if (insn_check != no_check) + { + bfd_vma off = rel->r_offset & ~3; + unsigned char buf[4]; + unsigned int insn; + + if (!bfd_get_section_contents (ibfd, sec, buf, off, 4)) + { + free (used); + goto error_ret; + } + insn = bfd_get_32 (ibfd, buf); + if (insn_check == check_lo + ? !ok_lo_toc_insn (insn) + : ((insn & ((0x3f << 26) | 0x1f << 16)) + != ((15u << 26) | (2 << 16)) /* addis rt,2,imm */)) + { + char str[12]; + + ppc64_elf_tdata (ibfd)->unexpected_toc_insn = 1; + sprintf (str, "%#08x", insn); + info->callbacks->einfo + (_("%P: %H: toc optimization is not supported for" + " %s instruction.\n"), + ibfd, sec, rel->r_offset & ~3, str); + } + } + switch (r_type) { case R_PPC64_TOC16: @@ -13322,7 +13376,7 @@ ppc64_elf_relocate_section (bfd *output_bfd, case R_PPC64_GOT16_HA: case R_PPC64_TOC16_HA: if (htab->do_toc_opt && relocation + addend + 0x8000 < 0x10000 - && !ppc64_elf_tdata (input_bfd)->ha_relocs_not_using_r2) + && !ppc64_elf_tdata (input_bfd)->unexpected_toc_insn) { bfd_byte *p = contents + (rel->r_offset & ~3); bfd_put_32 (input_bfd, NOP, p); @@ -13338,33 +13392,22 @@ ppc64_elf_relocate_section (bfd *output_bfd, case R_PPC64_TOC16_LO: case R_PPC64_TOC16_LO_DS: if (htab->do_toc_opt && relocation + addend + 0x8000 < 0x10000 - && !ppc64_elf_tdata (input_bfd)->ha_relocs_not_using_r2) + && !ppc64_elf_tdata (input_bfd)->unexpected_toc_insn) { bfd_byte *p = contents + (rel->r_offset & ~3); insn = bfd_get_32 (input_bfd, p); - if ((insn & (0x3f << 26)) == 14u << 26 /* addi */ - || (insn & (0x3f << 26)) == 32u << 26 /* lwz */ - || (insn & (0x3f << 26)) == 34u << 26 /* lbz */ - || (insn & (0x3f << 26)) == 36u << 26 /* stw */ - || (insn & (0x3f << 26)) == 38u << 26 /* stb */ - || (insn & (0x3f << 26)) == 40u << 26 /* lhz */ - || (insn & (0x3f << 26)) == 42u << 26 /* lha */ - || (insn & (0x3f << 26)) == 44u << 26 /* sth */ - || (insn & (0x3f << 26)) == 46u << 26 /* lmw */ - || (insn & (0x3f << 26)) == 47u << 26 /* stmw */ - || (insn & (0x3f << 26)) == 48u << 26 /* lfs */ - || (insn & (0x3f << 26)) == 50u << 26 /* lfd */ - || (insn & (0x3f << 26)) == 52u << 26 /* stfs */ - || (insn & (0x3f << 26)) == 54u << 26 /* stfd */ - || ((insn & (0x3f << 26)) == 58u << 26 /* lwa,ld,lmd */ - && (insn & 3) != 1) - || ((insn & (0x3f << 26)) == 62u << 26 /* std, stmd */ - && ((insn & 3) == 0 || (insn & 3) == 3))) + if ((insn & (0x3f << 26)) == 12u << 26 /* addic */) + { + /* Transform addic to addi when we change reg. */ + insn &= ~((0x3f << 26) | (0x1f << 16)); + insn |= (14u << 26) | (2 << 16); + } + else { insn &= ~(0x1f << 16); insn |= 2 << 16; - bfd_put_32 (input_bfd, insn, p); } + bfd_put_32 (input_bfd, insn, p); } break; } diff --git a/ld/testsuite/ChangeLog b/ld/testsuite/ChangeLog index 91c593c..4258e95 100644 --- a/ld/testsuite/ChangeLog +++ b/ld/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2011-11-08 Alan Modra <amodra@gmail.com> + + * ld-powerpc/powerpc.exp: Expect ld warnings for tocopt test. + * ld-powerpc/tocopt.out: New file. + 2011-10-25 Alan Modra <amodra@gmail.com> Apply mainline patches diff --git a/ld/testsuite/ld-powerpc/powerpc.exp b/ld/testsuite/ld-powerpc/powerpc.exp index 7f9e7fa..566272d 100644 --- a/ld/testsuite/ld-powerpc/powerpc.exp +++ b/ld/testsuite/ld-powerpc/powerpc.exp @@ -204,7 +204,7 @@ set ppc64elftests { {"sym@tocbase" "-shared -melf64ppc" "-a64" {symtocbase-1.s symtocbase-2.s} {{objdump -dj.data symtocbase.d}} "symtocbase.so"} {"TOC opt" "-melf64ppc" "-a64" {tocopt.s} - {{objdump -s tocopt.d}} "tocopt"} + {{ld tocopt.out} {objdump -s tocopt.d}} "tocopt"} {"TOC opt2" "-melf64ppc --defsym x=2" "-a64" {tocopt2.s} {{ld tocopt2.out} {objdump -s tocopt2.d}} "tocopt2"} {"TOC opt3" "-melf64ppc -no-keep-memory --defsym x=2" "-a64" {tocopt3.s} |