From d4f1ee75e7381b210d5da54c9b6b6ff74aa96c00 Mon Sep 17 00:00:00 2001 From: Alan Modra Date: Mon, 5 Nov 2012 05:17:34 +0000 Subject: [PATCH] * elf64-ppc.c (ppc64_elf_edit_toc): Clear "repeat" inside loop. Really mark toc entry referring to another toc entry only if the first is used. --- bfd/ChangeLog | 6 ++ bfd/elf64-ppc.c | 258 +++++++++++++++++++++++++----------------------- 2 files changed, 138 insertions(+), 126 deletions(-) diff --git a/bfd/ChangeLog b/bfd/ChangeLog index 00f63f2370b..4fa94b1c08f 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,9 @@ +2012-11-05 Alan Modra + + * elf64-ppc.c (ppc64_elf_edit_toc): Clear "repeat" inside + loop. Really mark toc entry referring to another toc entry + only if the first is used. + 2012-10-30 H.J. Lu * configure.in: Also handle --enable-64-bit-bfd when setting diff --git a/bfd/elf64-ppc.c b/bfd/elf64-ppc.c index e67bb8f395f..ff6c4b27210 100644 --- a/bfd/elf64-ppc.c +++ b/bfd/elf64-ppc.c @@ -8372,150 +8372,156 @@ ppc64_elf_edit_toc (struct bfd_link_info *info) goto error_ret; /* Mark toc entries referenced as used. */ - repeat = 0; do - for (rel = relstart; rel < relstart + sec->reloc_count; ++rel) - { - enum elf_ppc64_reloc_type r_type; - unsigned long r_symndx; - asection *sym_sec; - 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; + { + repeat = 0; + for (rel = relstart; rel < relstart + sec->reloc_count; ++rel) + { + enum elf_ppc64_reloc_type r_type; + unsigned long r_symndx; + asection *sym_sec; + struct elf_link_hash_entry *h; + Elf_Internal_Sym *sym; + bfd_vma val; + enum {no_check, check_lo, check_ha} insn_check; - case R_PPC64_GOT_TLSLD16_HA: - case R_PPC64_GOT_TLSGD16_HA: - case R_PPC64_GOT_TPREL16_HA: - case R_PPC64_GOT_DTPREL16_HA: - case R_PPC64_GOT16_HA: - case R_PPC64_TOC16_HA: - insn_check = check_ha; - break; + r_type = ELF64_R_TYPE (rel->r_info); + switch (r_type) + { + default: + insn_check = no_check; + break; - 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; - } + case R_PPC64_GOT_TLSLD16_HA: + case R_PPC64_GOT_TLSGD16_HA: + case R_PPC64_GOT_TPREL16_HA: + case R_PPC64_GOT_DTPREL16_HA: + case R_PPC64_GOT16_HA: + case R_PPC64_TOC16_HA: + insn_check = check_ha; + break; - if (insn_check != no_check) - { - bfd_vma off = rel->r_offset & ~3; - unsigned char buf[4]; - unsigned int insn; + 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 (!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]; + if (insn_check != no_check) + { + bfd_vma off = rel->r_offset & ~3; + unsigned char buf[4]; + unsigned int insn; - 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); - } - } + 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]; - switch (r_type) - { - case R_PPC64_TOC16: - case R_PPC64_TOC16_LO: - case R_PPC64_TOC16_HI: - case R_PPC64_TOC16_HA: - case R_PPC64_TOC16_DS: - case R_PPC64_TOC16_LO_DS: - /* In case we're taking addresses of toc entries. */ - case R_PPC64_ADDR64: - break; + 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); + } + } - default: - continue; - } + switch (r_type) + { + case R_PPC64_TOC16: + case R_PPC64_TOC16_LO: + case R_PPC64_TOC16_HI: + case R_PPC64_TOC16_HA: + case R_PPC64_TOC16_DS: + case R_PPC64_TOC16_LO_DS: + /* In case we're taking addresses of toc entries. */ + case R_PPC64_ADDR64: + break; - r_symndx = ELF64_R_SYM (rel->r_info); - if (!get_sym_h (&h, &sym, &sym_sec, NULL, &local_syms, - r_symndx, ibfd)) - { - free (used); - goto error_ret; - } + default: + continue; + } - if (sym_sec != toc) - continue; + r_symndx = ELF64_R_SYM (rel->r_info); + if (!get_sym_h (&h, &sym, &sym_sec, NULL, &local_syms, + r_symndx, ibfd)) + { + free (used); + goto error_ret; + } - if (h != NULL) - val = h->root.u.def.value; - else - val = sym->st_value; - val += rel->r_addend; + if (sym_sec != toc) + continue; - if (val >= toc->size) - continue; + if (h != NULL) + val = h->root.u.def.value; + else + val = sym->st_value; + val += rel->r_addend; - if ((skip[val >> 3] & can_optimize) != 0) - { - bfd_vma off; - unsigned char opc; + if (val >= toc->size) + continue; - switch (r_type) - { - case R_PPC64_TOC16_HA: - break; + if ((skip[val >> 3] & can_optimize) != 0) + { + bfd_vma off; + unsigned char opc; - case R_PPC64_TOC16_LO_DS: - off = rel->r_offset + (bfd_big_endian (ibfd) ? -2 : 3); - if (!bfd_get_section_contents (ibfd, sec, &opc, off, 1)) - { - free (used); - goto error_ret; - } - if ((opc & (0x3f << 2)) == (58u << 2)) + switch (r_type) + { + case R_PPC64_TOC16_HA: break; - /* Fall thru */ - default: - /* Wrong sort of reloc, or not a ld. We may - as well clear ref_from_discarded too. */ - skip[val >> 3] = 0; - } - } + case R_PPC64_TOC16_LO_DS: + off = rel->r_offset; + off += (bfd_big_endian (ibfd) ? -2 : 3); + if (!bfd_get_section_contents (ibfd, sec, &opc, + off, 1)) + { + free (used); + goto error_ret; + } + if ((opc & (0x3f << 2)) == (58u << 2)) + break; + /* Fall thru */ - /* For the toc section, we only mark as used if - this entry itself isn't unused. */ - if (sec == toc - && !used[val >> 3] - && (used[rel->r_offset >> 3] - || !(skip[rel->r_offset >> 3] & ref_from_discarded))) - /* Do all the relocs again, to catch reference - chains. */ - repeat = 1; - - used[val >> 3] = 1; - } + default: + /* Wrong sort of reloc, or not a ld. We may + as well clear ref_from_discarded too. */ + skip[val >> 3] = 0; + } + } + + if (sec != toc) + used[val >> 3] = 1; + /* For the toc section, we only mark as used if this + entry itself isn't unused. */ + else if ((used[rel->r_offset >> 3] + || !(skip[rel->r_offset >> 3] & ref_from_discarded)) + && !used[val >> 3]) + { + /* Do all the relocs again, to catch reference + chains. */ + repeat = 1; + used[val >> 3] = 1; + } + } + } while (repeat); if (elf_section_data (sec)->relocs != relstart) -- 2.30.2