From 102890f04c44b64cf5cef4588267dd9f24086ac7 Mon Sep 17 00:00:00 2001 From: Alan Modra Date: Tue, 6 Nov 2007 13:49:19 +0000 Subject: [PATCH] bfd/ * elf64-ppc.c (ppc64_elf_check_relocs): Don't refcount tlsld_got here.. (ppc64_elf_gc_sweep_hook): ..or here.. (ppc64_elf_tls_optimize): ..or here. Make two passes through the relocs, ensuring that tls_get_addr calls follow gd and ld relocs. (allocate_dynrelocs): Refcount tlsld_got here. (ppc64_elf_size_dynamic_sections): Allocate local got and call allocate_dynrelocs before allocating tlsld_got. (ppc64_elf_relocate_section): Remove check that a tls_get_addr call follows gd and ld relocs. ld/testsuite/ * ld-powerpc/tlsso.d: Update for changed got alloc order. * ld-powerpc/tlsso.r: Likewise. --- bfd/ChangeLog | 10 + bfd/elf64-ppc.c | 829 +++++++++++++++++--------------- ld/testsuite/ChangeLog | 3 + ld/testsuite/ld-powerpc/tlsso.d | 20 +- ld/testsuite/ld-powerpc/tlsso.r | 2 +- 5 files changed, 459 insertions(+), 405 deletions(-) diff --git a/bfd/ChangeLog b/bfd/ChangeLog index c1022db1268..b42e0c9213b 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,5 +1,15 @@ 2007-11-06 Alan Modra + * elf64-ppc.c (ppc64_elf_check_relocs): Don't refcount tlsld_got here.. + (ppc64_elf_gc_sweep_hook): ..or here.. + (ppc64_elf_tls_optimize): ..or here. Make two passes through the + relocs, ensuring that tls_get_addr calls follow gd and ld relocs. + (allocate_dynrelocs): Refcount tlsld_got here. + (ppc64_elf_size_dynamic_sections): Allocate local got and call + allocate_dynrelocs before allocating tlsld_got. + (ppc64_elf_relocate_section): Remove check that a tls_get_addr + call follows gd and ld relocs. + * elf32-ppc.c (ppc_elf_check_relocs): Don't refcount tlsld_got here.. (ppc_elf_gc_sweep_hook): ..or here.. (ppc_elf_tls_optimize): ..or here. Make two passes through the diff --git a/bfd/elf64-ppc.c b/bfd/elf64-ppc.c index b25ca3a7ac9..6d18fbca761 100644 --- a/bfd/elf64-ppc.c +++ b/bfd/elf64-ppc.c @@ -3161,7 +3161,8 @@ struct got_entry /* Unlike other ELF targets, we use separate GOT entries for the same symbol referenced from different input files. This is to support automatic multiple TOC/GOT sections, where the TOC base can vary - from one input file to another. + from one input file to another. FIXME: After group_sections we + ought to merge entries within the group. Point to the BFD owning this GOT entry. */ bfd *owner; @@ -4480,7 +4481,6 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, case R_PPC64_GOT_TLSLD16_LO: case R_PPC64_GOT_TLSLD16_HI: case R_PPC64_GOT_TLSLD16_HA: - ppc64_tlsld_got (abfd)->refcount += 1; tls_type = TLS_TLS | TLS_LD; goto dogottls; @@ -5306,7 +5306,6 @@ ppc64_elf_gc_sweep_hook (bfd *abfd, struct bfd_link_info *info, case R_PPC64_GOT_TLSLD16_LO: case R_PPC64_GOT_TLSLD16_HI: case R_PPC64_GOT_TLSLD16_HA: - ppc64_tlsld_got (abfd)->refcount -= 1; tls_type = TLS_TLS | TLS_LD; goto dogot; @@ -6795,6 +6794,7 @@ ppc64_elf_tls_optimize (bfd *obfd ATTRIBUTE_UNUSED, struct bfd_link_info *info) bfd *ibfd; asection *sec; struct ppc_link_hash_table *htab; + int pass; if (info->relocatable || info->shared) return TRUE; @@ -6806,320 +6806,382 @@ ppc64_elf_tls_optimize (bfd *obfd ATTRIBUTE_UNUSED, struct bfd_link_info *info) asection *toc = bfd_get_section_by_name (ibfd, ".toc"); unsigned char *toc_ref = NULL; - /* Look at all the sections for this file, with TOC last. */ - for (sec = (ibfd->sections == toc && toc && toc->next ? toc->next - : ibfd->sections); - sec != NULL; - sec = (sec == toc ? NULL - : sec->next == NULL ? toc - : sec->next == toc && toc->next ? toc->next - : sec->next)) - if (sec->has_tls_reloc && !bfd_is_abs_section (sec->output_section)) - { - Elf_Internal_Rela *relstart, *rel, *relend; - int expecting_tls_get_addr; - long toc_ref_index = 0; - - /* Read the relocations. */ - relstart = _bfd_elf_link_read_relocs (ibfd, sec, NULL, NULL, - info->keep_memory); - if (relstart == NULL) - return FALSE; + /* Look at all the sections for this file. Make two passes over + the relocs. On the first pass, mark toc entries involved + with tls relocs, and check that tls relocs involved in + setting up a tls_get_addr call are indeed followed by such a + call. If they are not, exclude them from the optimizations + done on the second pass. */ + for (pass = 0; pass < 2; ++pass) + for (sec = ibfd->sections; sec != NULL; sec = sec->next) + if (sec->has_tls_reloc && !bfd_is_abs_section (sec->output_section)) + { + Elf_Internal_Rela *relstart, *rel, *relend; - expecting_tls_get_addr = 0; - relend = relstart + sec->reloc_count; - for (rel = relstart; rel < relend; rel++) - { - enum elf_ppc64_reloc_type r_type; - unsigned long r_symndx; - struct elf_link_hash_entry *h; - Elf_Internal_Sym *sym; - asection *sym_sec; - char *tls_mask; - char tls_set, tls_clear, tls_type = 0; - bfd_vma value; - bfd_boolean ok_tprel, is_local; + /* Read the relocations. */ + relstart = _bfd_elf_link_read_relocs (ibfd, sec, NULL, NULL, + info->keep_memory); + if (relstart == NULL) + return FALSE; - r_symndx = ELF64_R_SYM (rel->r_info); - if (!get_sym_h (&h, &sym, &sym_sec, &tls_mask, &locsyms, - r_symndx, ibfd)) - { - err_free_rel: - if (elf_section_data (sec)->relocs != relstart) - free (relstart); - if (toc_ref != NULL) - free (toc_ref); - if (locsyms != NULL - && (elf_tdata (ibfd)->symtab_hdr.contents - != (unsigned char *) locsyms)) - free (locsyms); - return FALSE; - } + relend = relstart + sec->reloc_count; + for (rel = relstart; rel < relend; rel++) + { + enum elf_ppc64_reloc_type r_type; + unsigned long r_symndx; + struct elf_link_hash_entry *h; + Elf_Internal_Sym *sym; + asection *sym_sec; + char *tls_mask; + char tls_set, tls_clear, tls_type = 0; + bfd_vma value; + bfd_boolean ok_tprel, is_local; + long toc_ref_index = 0; + int expecting_tls_get_addr = 0; - if (h != NULL) - { - if (h->root.type != bfd_link_hash_defined - && h->root.type != bfd_link_hash_defweak) - continue; - value = h->root.u.def.value; - } - else - /* Symbols referenced by TLS relocs must be of type - STT_TLS. So no need for .opd local sym adjust. */ - value = sym->st_value; - - ok_tprel = FALSE; - is_local = FALSE; - if (h == NULL - || !h->def_dynamic) - { - is_local = TRUE; - value += sym_sec->output_offset; - value += sym_sec->output_section->vma; - value -= htab->elf.tls_sec->vma; - ok_tprel = (value + TP_OFFSET + ((bfd_vma) 1 << 31) - < (bfd_vma) 1 << 32); - } + r_symndx = ELF64_R_SYM (rel->r_info); + if (!get_sym_h (&h, &sym, &sym_sec, &tls_mask, &locsyms, + r_symndx, ibfd)) + { + err_free_rel: + if (elf_section_data (sec)->relocs != relstart) + free (relstart); + if (toc_ref != NULL) + free (toc_ref); + if (locsyms != NULL + && (elf_tdata (ibfd)->symtab_hdr.contents + != (unsigned char *) locsyms)) + free (locsyms); + return FALSE; + } - r_type = ELF64_R_TYPE (rel->r_info); - switch (r_type) - { - case R_PPC64_GOT_TLSLD16: - case R_PPC64_GOT_TLSLD16_LO: - case R_PPC64_GOT_TLSLD16_HI: - case R_PPC64_GOT_TLSLD16_HA: - /* These relocs should never be against a symbol - defined in a shared lib. Leave them alone if - that turns out to be the case. */ - ppc64_tlsld_got (ibfd)->refcount -= 1; - if (!is_local) - continue; + if (h != NULL) + { + if (h->root.type != bfd_link_hash_defined + && h->root.type != bfd_link_hash_defweak) + continue; + value = h->root.u.def.value; + } + else + /* Symbols referenced by TLS relocs must be of type + STT_TLS. So no need for .opd local sym adjust. */ + value = sym->st_value; + + ok_tprel = FALSE; + is_local = FALSE; + if (h == NULL + || !h->def_dynamic) + { + is_local = TRUE; + value += sym_sec->output_offset; + value += sym_sec->output_section->vma; + value -= htab->elf.tls_sec->vma; + ok_tprel = (value + TP_OFFSET + ((bfd_vma) 1 << 31) + < (bfd_vma) 1 << 32); + } - /* LD -> LE */ - tls_set = 0; - tls_clear = TLS_LD; - tls_type = TLS_TLS | TLS_LD; - expecting_tls_get_addr = 1; - break; + r_type = ELF64_R_TYPE (rel->r_info); + switch (r_type) + { + case R_PPC64_GOT_TLSLD16: + case R_PPC64_GOT_TLSLD16_LO: + expecting_tls_get_addr = 1; + /* Fall thru */ + + case R_PPC64_GOT_TLSLD16_HI: + case R_PPC64_GOT_TLSLD16_HA: + /* These relocs should never be against a symbol + defined in a shared lib. Leave them alone if + that turns out to be the case. */ + if (!is_local) + continue; - case R_PPC64_GOT_TLSGD16: - case R_PPC64_GOT_TLSGD16_LO: - case R_PPC64_GOT_TLSGD16_HI: - case R_PPC64_GOT_TLSGD16_HA: - if (ok_tprel) - /* GD -> LE */ + /* LD -> LE */ tls_set = 0; - else - /* GD -> IE */ - tls_set = TLS_TLS | TLS_TPRELGD; - tls_clear = TLS_GD; - tls_type = TLS_TLS | TLS_GD; - expecting_tls_get_addr = 1; - break; + tls_clear = TLS_LD; + tls_type = TLS_TLS | TLS_LD; + break; - case R_PPC64_GOT_TPREL16_DS: - case R_PPC64_GOT_TPREL16_LO_DS: - case R_PPC64_GOT_TPREL16_HI: - case R_PPC64_GOT_TPREL16_HA: - expecting_tls_get_addr = 0; - if (ok_tprel) - { - /* IE -> LE */ + case R_PPC64_GOT_TLSGD16: + case R_PPC64_GOT_TLSGD16_LO: + expecting_tls_get_addr = 1; + /* Fall thru */ + + case R_PPC64_GOT_TLSGD16_HI: + case R_PPC64_GOT_TLSGD16_HA: + if (ok_tprel) + /* GD -> LE */ tls_set = 0; - tls_clear = TLS_TPREL; - tls_type = TLS_TLS | TLS_TPREL; - break; - } - else + else + /* GD -> IE */ + tls_set = TLS_TLS | TLS_TPRELGD; + tls_clear = TLS_GD; + tls_type = TLS_TLS | TLS_GD; + break; + + case R_PPC64_GOT_TPREL16_DS: + case R_PPC64_GOT_TPREL16_LO_DS: + case R_PPC64_GOT_TPREL16_HI: + case R_PPC64_GOT_TPREL16_HA: + if (ok_tprel) + { + /* IE -> LE */ + tls_set = 0; + tls_clear = TLS_TPREL; + tls_type = TLS_TLS | TLS_TPREL; + break; + } continue; - case R_PPC64_REL14: - case R_PPC64_REL14_BRTAKEN: - case R_PPC64_REL14_BRNTAKEN: - case R_PPC64_REL24: - if (h != NULL - && (h == &htab->tls_get_addr->elf - || h == &htab->tls_get_addr_fd->elf)) - { - if (!expecting_tls_get_addr - && rel != relstart - && ((ELF64_R_TYPE (rel[-1].r_info) - == R_PPC64_TOC16) - || (ELF64_R_TYPE (rel[-1].r_info) - == R_PPC64_TOC16_LO))) + case R_PPC64_TOC16: + case R_PPC64_TOC16_LO: + case R_PPC64_TLS: + if (sym_sec == NULL || sym_sec != toc) + continue; + + /* Mark this toc entry as referenced by a TLS + code sequence. We can do that now in the + case of R_PPC64_TLS, and after checking for + tls_get_addr for the TOC16 relocs. */ + if (toc_ref == NULL) + { + toc_ref = bfd_zmalloc (toc->size / 8); + if (toc_ref == NULL) + goto err_free_rel; + } + if (h != NULL) + value = h->root.u.def.value; + else + value = sym->st_value; + value += rel->r_addend; + BFD_ASSERT (value < toc->size && value % 8 == 0); + toc_ref_index = value / 8; + if (r_type == R_PPC64_TLS) + { + toc_ref[toc_ref_index] = 1; + continue; + } + + if (pass != 0 && toc_ref[toc_ref_index] == 0) + continue; + + tls_set = 0; + tls_clear = 0; + expecting_tls_get_addr = 2; + break; + + case R_PPC64_TPREL64: + if (pass == 0 + || sec != toc + || toc_ref == NULL + || !toc_ref[rel->r_offset / 8]) + continue; + if (ok_tprel) + { + /* IE -> LE */ + tls_set = TLS_EXPLICIT; + tls_clear = TLS_TPREL; + break; + } + continue; + + case R_PPC64_DTPMOD64: + if (pass == 0 + || sec != toc + || toc_ref == NULL + || !toc_ref[rel->r_offset / 8]) + continue; + if (rel + 1 < relend + && (rel[1].r_info + == ELF64_R_INFO (r_symndx, R_PPC64_DTPREL64)) + && rel[1].r_offset == rel->r_offset + 8) + { + if (ok_tprel) + /* GD -> LE */ + tls_set = TLS_EXPLICIT | TLS_GD; + else + /* GD -> IE */ + tls_set = TLS_EXPLICIT | TLS_GD | TLS_TPRELGD; + tls_clear = TLS_GD; + } + else + { + if (!is_local) + continue; + + /* LD -> LE */ + tls_set = TLS_EXPLICIT; + tls_clear = TLS_LD; + } + break; + + default: + continue; + } + + if (pass == 0) + { + if (!expecting_tls_get_addr) + continue; + + if (rel + 1 < relend) + { + Elf_Internal_Shdr *symtab_hdr; + enum elf_ppc64_reloc_type r_type2; + unsigned long r_symndx2; + struct elf_link_hash_entry *h2; + + symtab_hdr = &elf_tdata (ibfd)->symtab_hdr; + + /* The next instruction should be a call to + __tls_get_addr. Peek at the reloc to be sure. */ + r_type2 = ELF64_R_TYPE (rel[1].r_info); + r_symndx2 = ELF64_R_SYM (rel[1].r_info); + if (r_symndx2 >= symtab_hdr->sh_info + && (r_type2 == R_PPC64_REL14 + || r_type2 == R_PPC64_REL14_BRTAKEN + || r_type2 == R_PPC64_REL14_BRNTAKEN + || r_type2 == R_PPC64_REL24)) + { + struct elf_link_hash_entry **sym_hashes; + + sym_hashes = elf_sym_hashes (ibfd); + + h2 = sym_hashes[r_symndx2 - symtab_hdr->sh_info]; + while (h2->root.type == bfd_link_hash_indirect + || h2->root.type == bfd_link_hash_warning) + h2 = ((struct elf_link_hash_entry *) + h2->root.u.i.link); + if (h2 != NULL + && (h2 == &htab->tls_get_addr->elf + || h2 == &htab->tls_get_addr_fd->elf)) + { + if (expecting_tls_get_addr == 2) + { + /* Check for toc tls entries. */ + char *toc_tls; + int retval; + + retval = get_tls_mask (&toc_tls, NULL, + &locsyms, + rel, ibfd); + if (retval == 0) + goto err_free_rel; + if (retval > 1 && toc_tls != NULL) + toc_ref[toc_ref_index] = 1; + } + continue; + } + } + } + + if (expecting_tls_get_addr != 1) + continue; + + /* Uh oh, we didn't find the expected call. We + could just mark this symbol to exclude it + from tls optimization but it's safer to skip + the entire section. */ + sec->has_tls_reloc = 0; + break; + } + + if (expecting_tls_get_addr) + { + struct plt_entry *ent; + for (ent = htab->tls_get_addr->elf.plt.plist; + ent != NULL; + ent = ent->next) + if (ent->addend == 0) { - /* Check for toc tls entries. */ - char *toc_tls; - int retval; - - retval = get_tls_mask (&toc_tls, NULL, &locsyms, - rel - 1, ibfd); - if (retval == 0) - goto err_free_rel; - if (retval > 1 && toc_tls != NULL) + if (ent->plt.refcount > 0) { - expecting_tls_get_addr = 1; - if (toc_ref != NULL) - toc_ref[toc_ref_index] = 1; + ent->plt.refcount -= 1; + expecting_tls_get_addr = 0; } + break; } + } - if (expecting_tls_get_addr) + if (expecting_tls_get_addr) + { + struct plt_entry *ent; + for (ent = htab->tls_get_addr_fd->elf.plt.plist; + ent != NULL; + ent = ent->next) + if (ent->addend == 0) { - struct plt_entry *ent; - for (ent = h->plt.plist; ent; ent = ent->next) - if (ent->addend == 0) - { - if (ent->plt.refcount > 0) - ent->plt.refcount -= 1; - break; - } + if (ent->plt.refcount > 0) + ent->plt.refcount -= 1; + break; } - } - expecting_tls_get_addr = 0; - continue; + } - case R_PPC64_TOC16: - case R_PPC64_TOC16_LO: - case R_PPC64_TLS: - expecting_tls_get_addr = 0; - if (sym_sec == toc && toc != NULL) - { - /* Mark this toc entry as referenced by a TLS - code sequence. We can do that now in the - case of R_PPC64_TLS, and after checking for - tls_get_addr for the TOC16 relocs. */ - if (toc_ref == NULL) - { - toc_ref = bfd_zmalloc (toc->size / 8); - if (toc_ref == NULL) - goto err_free_rel; - } - if (h != NULL) - value = h->root.u.def.value; - else - value = sym->st_value; - value += rel->r_addend; - BFD_ASSERT (value < toc->size && value % 8 == 0); - toc_ref_index = value / 8; - if (r_type == R_PPC64_TLS) - toc_ref[toc_ref_index] = 1; - } + if (tls_clear == 0) continue; - case R_PPC64_TPREL64: - expecting_tls_get_addr = 0; - if (sec != toc - || toc_ref == NULL - || !toc_ref[rel->r_offset / 8]) - continue; - if (ok_tprel) - { - /* IE -> LE */ - tls_set = TLS_EXPLICIT; - tls_clear = TLS_TPREL; - break; - } - else - continue; - - case R_PPC64_DTPMOD64: - expecting_tls_get_addr = 0; - if (sec != toc - || toc_ref == NULL - || !toc_ref[rel->r_offset / 8]) - continue; - if (rel + 1 < relend - && (rel[1].r_info - == ELF64_R_INFO (r_symndx, R_PPC64_DTPREL64)) - && rel[1].r_offset == rel->r_offset + 8) - { - if (ok_tprel) - /* GD -> LE */ - tls_set = TLS_EXPLICIT | TLS_GD; - else - /* GD -> IE */ - tls_set = TLS_EXPLICIT | TLS_GD | TLS_TPRELGD; - tls_clear = TLS_GD; - } - else - { - if (!is_local) - continue; - - /* LD -> LE */ - tls_set = TLS_EXPLICIT; - tls_clear = TLS_LD; - } - break; + if ((tls_set & TLS_EXPLICIT) == 0) + { + struct got_entry *ent; - default: - expecting_tls_get_addr = 0; - continue; - } + /* Adjust got entry for this reloc. */ + if (h != NULL) + ent = h->got.glist; + else + ent = elf_local_got_ents (ibfd)[r_symndx]; - if ((tls_set & TLS_EXPLICIT) == 0) - { - struct got_entry *ent; + for (; ent != NULL; ent = ent->next) + if (ent->addend == rel->r_addend + && ent->owner == ibfd + && ent->tls_type == tls_type) + break; + if (ent == NULL) + abort (); - /* Adjust got entry for this reloc. */ - if (h != NULL) - ent = h->got.glist; - else - ent = elf_local_got_ents (ibfd)[r_symndx]; + if (tls_set == 0) + { + /* We managed to get rid of a got entry. */ + if (ent->got.refcount > 0) + ent->got.refcount -= 1; + } + } + else + { + /* If we got rid of a DTPMOD/DTPREL reloc pair then + we'll lose one or two dyn relocs. */ + if (!dec_dynrel_count (rel->r_info, sec, info, + NULL, h, sym_sec)) + return FALSE; - for (; ent != NULL; ent = ent->next) - if (ent->addend == rel->r_addend - && ent->owner == ibfd - && ent->tls_type == tls_type) - break; - if (ent == NULL) - abort (); + if (tls_set == (TLS_EXPLICIT | TLS_GD)) + { + if (!dec_dynrel_count ((rel + 1)->r_info, sec, info, + NULL, h, sym_sec)) + return FALSE; + } + } - if (tls_set == 0) - { - /* We managed to get rid of a got entry. */ - if (ent->got.refcount > 0) - ent->got.refcount -= 1; - } - } - else - { - /* If we got rid of a DTPMOD/DTPREL reloc pair then - we'll lose one or two dyn relocs. */ - if (!dec_dynrel_count (rel->r_info, sec, info, - NULL, h, sym_sec)) - return FALSE; + *tls_mask |= tls_set; + *tls_mask &= ~tls_clear; + } - if (tls_set == (TLS_EXPLICIT | TLS_GD)) - { - if (!dec_dynrel_count ((rel + 1)->r_info, sec, info, - NULL, h, sym_sec)) - return FALSE; - } - } + if (elf_section_data (sec)->relocs != relstart) + free (relstart); + } - *tls_mask |= tls_set; - *tls_mask &= ~tls_clear; - } + if (toc_ref != NULL) + free (toc_ref); - if (elf_section_data (sec)->relocs != relstart) - free (relstart); + if (locsyms != NULL + && (elf_tdata (ibfd)->symtab_hdr.contents + != (unsigned char *) locsyms)) + { + if (!info->keep_memory) + free (locsyms); + else + elf_tdata (ibfd)->symtab_hdr.contents = (unsigned char *) locsyms; } - - if (toc_ref != NULL) - free (toc_ref); - - if (locsyms != NULL - && (elf_tdata (ibfd)->symtab_hdr.contents - != (unsigned char *) locsyms)) - { - if (!info->keep_memory) - free (locsyms); - else - elf_tdata (ibfd)->symtab_hdr.contents = (unsigned char *) locsyms; - } - } + } return TRUE; } @@ -7693,7 +7755,8 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf) if ((gent->tls_type & TLS_LD) != 0 && !h->def_dynamic) { - gent->got.offset = ppc64_tlsld_got (gent->owner)->offset; + ppc64_tlsld_got (gent->owner)->refcount += 1; + gent->got.offset = (bfd_vma) -1; continue; } @@ -7877,20 +7940,6 @@ ppc64_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED, if (!is_ppc64_elf_target (ibfd->xvec)) continue; - if (ppc64_tlsld_got (ibfd)->refcount > 0) - { - s = ppc64_elf_tdata (ibfd)->got; - ppc64_tlsld_got (ibfd)->offset = s->size; - s->size += 16; - if (info->shared) - { - srel = ppc64_elf_tdata (ibfd)->relgot; - srel->size += sizeof (Elf64_External_Rela); - } - } - else - ppc64_tlsld_got (ibfd)->offset = (bfd_vma) -1; - for (s = ibfd->sections; s != NULL; s = s->next) { struct ppc_dyn_relocs *p; @@ -7934,14 +7983,8 @@ ppc64_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED, { if ((ent->tls_type & *lgot_masks & TLS_LD) != 0) { - if (ppc64_tlsld_got (ibfd)->offset == (bfd_vma) -1) - { - ppc64_tlsld_got (ibfd)->offset = s->size; - s->size += 16; - if (info->shared) - srel->size += sizeof (Elf64_External_Rela); - } - ent->got.offset = ppc64_tlsld_got (ibfd)->offset; + ppc64_tlsld_got (ibfd)->refcount += 1; + ent->got.offset = (bfd_vma) -1; } else { @@ -7969,6 +8012,26 @@ ppc64_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED, sym dynamic relocs. */ elf_link_hash_traverse (&htab->elf, allocate_dynrelocs, info); + for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next) + { + if (!is_ppc64_elf_target (ibfd->xvec)) + continue; + + if (ppc64_tlsld_got (ibfd)->refcount > 0) + { + s = ppc64_elf_tdata (ibfd)->got; + ppc64_tlsld_got (ibfd)->offset = s->size; + s->size += 16; + if (info->shared) + { + asection *srel = ppc64_elf_tdata (ibfd)->relgot; + srel->size += sizeof (Elf64_External_Rela); + } + } + else + ppc64_tlsld_got (ibfd)->offset = (bfd_vma) -1; + } + /* We now have determined the sizes of the various dynamic sections. Allocate memory for them. */ relocs = FALSE; @@ -10118,12 +10181,12 @@ ppc64_elf_relocate_section (bfd *output_bfd, { tls_gd = TLS_TPRELGD; if (tls_mask != 0 && (tls_mask & TLS_GD) == 0) - goto tls_get_addr_check; + goto tls_ldgd_opt; } else if (retval == 3) { if (tls_mask != 0 && (tls_mask & TLS_LD) == 0) - goto tls_get_addr_check; + goto tls_ldgd_opt; } } } @@ -10236,98 +10299,76 @@ ppc64_elf_relocate_section (bfd *output_bfd, case R_PPC64_GOT_TLSGD16_LO: tls_gd = TLS_TPRELGD; if (tls_mask != 0 && (tls_mask & TLS_GD) == 0) - goto tls_get_addr_check; + goto tls_ldgd_opt; break; case R_PPC64_GOT_TLSLD16: case R_PPC64_GOT_TLSLD16_LO: if (tls_mask != 0 && (tls_mask & TLS_LD) == 0) { - tls_get_addr_check: - if (rel + 1 < relend) + bfd_vma insn1, insn2, insn3; + bfd_vma offset; + + tls_ldgd_opt: + /* We know that the next reloc is on a tls_get_addr + call, since ppc64_elf_tls_optimize checks this. */ + offset = rel[1].r_offset; + insn1 = bfd_get_32 (output_bfd, + contents + rel->r_offset - d_offset); + insn3 = bfd_get_32 (output_bfd, + contents + offset + 4); + if ((tls_mask & tls_gd) != 0) { - enum elf_ppc64_reloc_type r_type2; - unsigned long r_symndx2; - struct elf_link_hash_entry *h2; - bfd_vma insn1, insn2, insn3; - bfd_vma offset; - - /* The next instruction should be a call to - __tls_get_addr. Peek at the reloc to be sure. */ - r_type2 = ELF64_R_TYPE (rel[1].r_info); - r_symndx2 = ELF64_R_SYM (rel[1].r_info); - if (r_symndx2 < symtab_hdr->sh_info - || (r_type2 != R_PPC64_REL14 - && r_type2 != R_PPC64_REL14_BRTAKEN - && r_type2 != R_PPC64_REL14_BRNTAKEN - && r_type2 != R_PPC64_REL24)) - break; - - h2 = sym_hashes[r_symndx2 - symtab_hdr->sh_info]; - while (h2->root.type == bfd_link_hash_indirect - || h2->root.type == bfd_link_hash_warning) - h2 = (struct elf_link_hash_entry *) h2->root.u.i.link; - if (h2 == NULL || (h2 != &htab->tls_get_addr->elf - && h2 != &htab->tls_get_addr_fd->elf)) - break; - - /* OK, it checks out. Replace the call. */ - offset = rel[1].r_offset; - insn1 = bfd_get_32 (output_bfd, - contents + rel->r_offset - d_offset); - insn3 = bfd_get_32 (output_bfd, - contents + offset + 4); - if ((tls_mask & tls_gd) != 0) - { - /* IE */ - insn1 &= (1 << 26) - (1 << 2); - insn1 |= 58 << 26; /* ld */ - insn2 = 0x7c636a14; /* add 3,3,13 */ - rel[1].r_info = ELF64_R_INFO (r_symndx2, R_PPC64_NONE); - if ((tls_mask & TLS_EXPLICIT) == 0) - r_type = (((r_type - (R_PPC64_GOT_TLSGD16 & 3)) & 3) - + R_PPC64_GOT_TPREL16_DS); - else - r_type += R_PPC64_TOC16_DS - R_PPC64_TOC16; - rel->r_info = ELF64_R_INFO (r_symndx, r_type); - } + /* IE */ + insn1 &= (1 << 26) - (1 << 2); + insn1 |= 58 << 26; /* ld */ + insn2 = 0x7c636a14; /* add 3,3,13 */ + rel[1].r_info = ELF64_R_INFO (ELF64_R_SYM (rel[1].r_info), + R_PPC64_NONE); + if ((tls_mask & TLS_EXPLICIT) == 0) + r_type = (((r_type - (R_PPC64_GOT_TLSGD16 & 3)) & 3) + + R_PPC64_GOT_TPREL16_DS); else + r_type += R_PPC64_TOC16_DS - R_PPC64_TOC16; + rel->r_info = ELF64_R_INFO (r_symndx, r_type); + } + else + { + /* LE */ + insn1 = 0x3c6d0000; /* addis 3,13,0 */ + insn2 = 0x38630000; /* addi 3,3,0 */ + if (tls_gd == 0) { - /* LE */ - insn1 = 0x3c6d0000; /* addis 3,13,0 */ - insn2 = 0x38630000; /* addi 3,3,0 */ - if (tls_gd == 0) - { - /* Was an LD reloc. */ - r_symndx = 0; - rel->r_addend = htab->elf.tls_sec->vma + DTP_OFFSET; - rel[1].r_addend = htab->elf.tls_sec->vma + DTP_OFFSET; - } - else if (toc_symndx != 0) - r_symndx = toc_symndx; - r_type = R_PPC64_TPREL16_HA; - rel->r_info = ELF64_R_INFO (r_symndx, r_type); - rel[1].r_info = ELF64_R_INFO (r_symndx, - R_PPC64_TPREL16_LO); - rel[1].r_offset += d_offset; - } - if (insn3 == NOP - || insn3 == CROR_151515 || insn3 == CROR_313131) - { - insn3 = insn2; - insn2 = NOP; - rel[1].r_offset += 4; - } - bfd_put_32 (output_bfd, insn1, contents + rel->r_offset - d_offset); - bfd_put_32 (output_bfd, insn2, contents + offset); - bfd_put_32 (output_bfd, insn3, contents + offset + 4); - if (tls_gd == 0 || toc_symndx != 0) - { - /* We changed the symbol. Start over in order - to get h, sym, sec etc. right. */ - rel--; - continue; + /* Was an LD reloc. */ + r_symndx = 0; + rel->r_addend = htab->elf.tls_sec->vma + DTP_OFFSET; + rel[1].r_addend = htab->elf.tls_sec->vma + DTP_OFFSET; } + else if (toc_symndx != 0) + r_symndx = toc_symndx; + r_type = R_PPC64_TPREL16_HA; + rel->r_info = ELF64_R_INFO (r_symndx, r_type); + rel[1].r_info = ELF64_R_INFO (r_symndx, + R_PPC64_TPREL16_LO); + rel[1].r_offset += d_offset; + } + if (insn3 == NOP + || insn3 == CROR_151515 || insn3 == CROR_313131) + { + insn3 = insn2; + insn2 = NOP; + rel[1].r_offset += 4; + } + bfd_put_32 (output_bfd, insn1, + contents + rel->r_offset - d_offset); + bfd_put_32 (output_bfd, insn2, contents + offset); + bfd_put_32 (output_bfd, insn3, contents + offset + 4); + if (tls_gd == 0 || toc_symndx != 0) + { + /* We changed the symbol. Start over in order + to get h, sym, sec etc. right. */ + rel--; + continue; } } break; diff --git a/ld/testsuite/ChangeLog b/ld/testsuite/ChangeLog index fd417c0e6d0..e748cf6f806 100644 --- a/ld/testsuite/ChangeLog +++ b/ld/testsuite/ChangeLog @@ -1,5 +1,8 @@ 2007-11-06 Alan Modra + * ld-powerpc/tlsso.d: Update for changed got alloc order. + * ld-powerpc/tlsso.r: Likewise. + * ld-powerpc/tlsso32.d: Update for changed got alloc order. 2007-11-05 Alan Modra diff --git a/ld/testsuite/ld-powerpc/tlsso.d b/ld/testsuite/ld-powerpc/tlsso.d index 3fa4029d5a9..b1149aeaa3f 100644 --- a/ld/testsuite/ld-powerpc/tlsso.d +++ b/ld/testsuite/ld-powerpc/tlsso.d @@ -17,40 +17,40 @@ Disassembly of section \.text: .* 4e 80 04 20 bctr .* <_start>: -.* 38 62 80 30 addi r3,r2,-32720 +.* 38 62 80 20 addi r3,r2,-32736 .* 4b ff ff e5 bl .* <\.__tls_get_addr> .* e8 41 00 28 ld r2,40\(r1\) -.* 38 62 80 08 addi r3,r2,-32760 +.* 38 62 80 50 addi r3,r2,-32688 .* 4b ff ff d9 bl .* <\.__tls_get_addr> .* e8 41 00 28 ld r2,40\(r1\) -.* 38 62 80 48 addi r3,r2,-32696 +.* 38 62 80 38 addi r3,r2,-32712 .* 4b ff ff cd bl .* <\.__tls_get_addr> .* e8 41 00 28 ld r2,40\(r1\) -.* 38 62 80 08 addi r3,r2,-32760 +.* 38 62 80 50 addi r3,r2,-32688 .* 4b ff ff c1 bl .* <\.__tls_get_addr> .* e8 41 00 28 ld r2,40\(r1\) .* 39 23 80 40 addi r9,r3,-32704 .* 3d 23 00 00 addis r9,r3,0 .* 81 49 80 48 lwz r10,-32696\(r9\) -.* e9 22 80 40 ld r9,-32704\(r2\) +.* e9 22 80 30 ld r9,-32720\(r2\) .* 7d 49 18 2a ldx r10,r9,r3 -.* e9 22 80 58 ld r9,-32680\(r2\) +.* e9 22 80 48 ld r9,-32696\(r2\) .* 7d 49 6a 2e lhzx r10,r9,r13 .* 89 4d 00 00 lbz r10,0\(r13\) .* 3d 2d 00 00 addis r9,r13,0 .* 99 49 00 00 stb r10,0\(r9\) -.* 38 62 80 18 addi r3,r2,-32744 +.* 38 62 80 08 addi r3,r2,-32760 .* 4b ff ff 8d bl .* <\.__tls_get_addr> .* e8 41 00 28 ld r2,40\(r1\) -.* 38 62 80 08 addi r3,r2,-32760 +.* 38 62 80 50 addi r3,r2,-32688 .* 4b ff ff 81 bl .* <\.__tls_get_addr> .* e8 41 00 28 ld r2,40\(r1\) .* f9 43 80 08 std r10,-32760\(r3\) .* 3d 23 00 00 addis r9,r3,0 .* 91 49 80 10 stw r10,-32752\(r9\) -.* e9 22 80 28 ld r9,-32728\(r2\) +.* e9 22 80 18 ld r9,-32744\(r2\) .* 7d 49 19 2a stdx r10,r9,r3 -.* e9 22 80 58 ld r9,-32680\(r2\) +.* e9 22 80 48 ld r9,-32696\(r2\) .* 7d 49 6b 2e sthx r10,r9,r13 .* e9 4d 00 02 lwa r10,0\(r13\) .* 3d 2d 00 00 addis r9,r13,0 diff --git a/ld/testsuite/ld-powerpc/tlsso.r b/ld/testsuite/ld-powerpc/tlsso.r index 7dcf17390c0..7b2ee14f436 100644 --- a/ld/testsuite/ld-powerpc/tlsso.r +++ b/ld/testsuite/ld-powerpc/tlsso.r @@ -53,9 +53,9 @@ Relocation section '\.rela\.dyn' at offset .* contains 16 entries: [0-9a-f ]+R_PPC64_TPREL16_HA +0+105f0 \.tdata \+ 30 [0-9a-f ]+R_PPC64_TPREL16_LO +0+105f0 \.tdata \+ 30 [0-9a-f ]+R_PPC64_DTPMOD64 +0+ -[0-9a-f ]+R_PPC64_DTPMOD64 +0+ [0-9a-f ]+R_PPC64_DTPREL64 +0+ [0-9a-f ]+R_PPC64_DTPREL64 +0+18 +[0-9a-f ]+R_PPC64_DTPMOD64 +0+ [0-9a-f ]+R_PPC64_DTPMOD64 +0+ gd \+ 0 [0-9a-f ]+R_PPC64_DTPREL64 +0+ gd \+ 0 [0-9a-f ]+R_PPC64_DTPREL64 +0+50 ld2 \+ 0 -- 2.30.2