From: Alan Modra Date: Wed, 3 Feb 2010 12:03:35 +0000 (+0000) Subject: bfd/ X-Git-Tag: gdb_7_1-2010-02-18-branchpoint~215 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=927be08ec81c122ef4872ec6d588965cbe05d7f9;p=platform%2Fupstream%2Fbinutils.git bfd/ * elf64-ppc.c (struct plt_entry): Move earlier in file. (struct got_entry): Likewise. Add is_indirect and got.ent fields. (struct ppc64_elf_obj_tdata): Change tlsld_got to be a struct got_entry. Update all uses. (struct ppc_link_hash_table): Add got_reli_size and second_toc_pass. Remove no_multi_toc. (update_local_sym_info, ppc64_elf_check_relocs): Clear is_indirect when allocating a new struct got_entry. (allocate_got): New function, extracted from.. (allocate_dynrelocs): ..here. Abort on got entry in non-ppc64 bfd. (ppc64_elf_size_dynamic_sections): Track got relocs allocated in .reliplt by got_reli_size. Set owner on ppc64_tlsld_got entries. (ppc64_elf_setup_section_lists): Remove output_bfd param and no_multi_toc, add add_stub_section and layout_sections_again. Stash new params in htab. Extract some code to.. (ppc64_elf_start_multitoc_partition): ..here. New function. (ppc64_elf_next_toc_section): Check for linker script errors. Handle second pass toc scan. (merge_got_entries, merge_global_got, reallocate_got): New functions. (ppc64_elf_reinit_toc): Rename to.. (ppc64_elf_finish_multitoc_partition): ..this. (ppc64_elf_layout_multitoc): New function. (ppc64_elf_size_stubs): Delete output_bfd, add_stub_section and layout_sections_again params. (ppc64_elf_relocate_section): Handle indirect got entries. * elf64-ppc.h: Update prototypes. Declare new functions. ld/ * emultempl/ppc64elf.em (build_toc_list): Report errors from ppc64_elf_next_toc_section. (after_allocation): Update for changed function names and params. Run second pass of multitoc partitioning. --- diff --git a/bfd/ChangeLog b/bfd/ChangeLog index 791ec74..3007e91 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,32 @@ +2010-02-03 Alan Modra + + * elf64-ppc.c (struct plt_entry): Move earlier in file. + (struct got_entry): Likewise. Add is_indirect and got.ent fields. + (struct ppc64_elf_obj_tdata): Change tlsld_got to be a struct got_entry. + Update all uses. + (struct ppc_link_hash_table): Add got_reli_size and second_toc_pass. + Remove no_multi_toc. + (update_local_sym_info, ppc64_elf_check_relocs): Clear is_indirect + when allocating a new struct got_entry. + (allocate_got): New function, extracted from.. + (allocate_dynrelocs): ..here. Abort on got entry in non-ppc64 bfd. + (ppc64_elf_size_dynamic_sections): Track got relocs allocated in + .reliplt by got_reli_size. Set owner on ppc64_tlsld_got entries. + (ppc64_elf_setup_section_lists): Remove output_bfd param and + no_multi_toc, add add_stub_section and layout_sections_again. Stash + new params in htab. Extract some code to.. + (ppc64_elf_start_multitoc_partition): ..here. New function. + (ppc64_elf_next_toc_section): Check for linker script errors. Handle + second pass toc scan. + (merge_got_entries, merge_global_got, reallocate_got): New functions. + (ppc64_elf_reinit_toc): Rename to.. + (ppc64_elf_finish_multitoc_partition): ..this. + (ppc64_elf_layout_multitoc): New function. + (ppc64_elf_size_stubs): Delete output_bfd, add_stub_section and + layout_sections_again params. + (ppc64_elf_relocate_section): Handle indirect got entries. + * elf64-ppc.h: Update prototypes. Declare new functions. + 2010-02-02 H.J. Lu * elf-bfd.h (elfcore_write_xstatereg): New. diff --git a/bfd/elf64-ppc.c b/bfd/elf64-ppc.c index 010f384..b44eeab 100644 --- a/bfd/elf64-ppc.c +++ b/bfd/elf64-ppc.c @@ -2526,6 +2526,54 @@ ppc64_elf_unhandled_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol, return bfd_reloc_dangerous; } +/* Track GOT entries needed for a given symbol. We might need more + than one got entry per symbol. */ +struct got_entry +{ + struct got_entry *next; + + /* The symbol addend that we'll be placing in the GOT. */ + bfd_vma addend; + + /* 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. After partitioning into TOC groups + we merge entries within the group. + + Point to the BFD owning this GOT entry. */ + bfd *owner; + + /* Zero for non-tls entries, or TLS_TLS and one of TLS_GD, TLS_LD, + TLS_TPREL or TLS_DTPREL for tls entries. */ + char tls_type; + + /* Non-zero if got.ent points to real entry. */ + char is_indirect; + + /* Reference count until size_dynamic_sections, GOT offset thereafter. */ + union + { + bfd_signed_vma refcount; + bfd_vma offset; + struct got_entry *ent; + } got; +}; + +/* The same for PLT. */ +struct plt_entry +{ + struct plt_entry *next; + + bfd_vma addend; + + union + { + bfd_signed_vma refcount; + bfd_vma offset; + } plt; +}; + struct ppc64_elf_obj_tdata { struct elf_obj_tdata elf; @@ -2538,12 +2586,9 @@ struct ppc64_elf_obj_tdata on removed .opd entries to this section so that the sym is removed. */ asection *deleted_section; - /* TLS local dynamic got entry handling. Suppose for multiple GOT + /* TLS local dynamic got entry handling. Support for multiple GOT sections means we potentially need one of these for each input bfd. */ - union { - bfd_signed_vma refcount; - bfd_vma offset; - } tlsld_got; + struct got_entry tlsld_got; /* A copy of relocs before they are modified for --emit-relocs. */ Elf_Internal_Rela *opd_relocs; @@ -3453,50 +3498,6 @@ struct ppc_dyn_relocs bfd_size_type pc_count; }; -/* Track GOT entries needed for a given symbol. We might need more - than one got entry per symbol. */ -struct got_entry -{ - struct got_entry *next; - - /* The symbol addend that we'll be placing in the GOT. */ - bfd_vma addend; - - /* 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. FIXME: After group_sections we - ought to merge entries within the group. - - Point to the BFD owning this GOT entry. */ - bfd *owner; - - /* Zero for non-tls entries, or TLS_TLS and one of TLS_GD, TLS_LD, - TLS_TPREL or TLS_DTPREL for tls entries. */ - char tls_type; - - /* Reference count until size_dynamic_sections, GOT offset thereafter. */ - union - { - bfd_signed_vma refcount; - bfd_vma offset; - } got; -}; - -/* The same for PLT. */ -struct plt_entry -{ - struct plt_entry *next; - - bfd_vma addend; - - union - { - bfd_signed_vma refcount; - bfd_vma offset; - } plt; -}; - /* Of those relocs that might be copied as dynamic relocs, this function selects those that must be copied when linking a shared library, even when the symbol is local. */ @@ -3764,6 +3765,9 @@ struct ppc_link_hash_table struct ppc_link_hash_entry *tls_get_addr; struct ppc_link_hash_entry *tls_get_addr_fd; + /* The size of reliplt used by got entry relocs. */ + bfd_size_type got_reli_size; + /* Statistics. */ unsigned long stub_count[ppc_stub_plt_call]; @@ -3777,8 +3781,8 @@ struct ppc_link_hash_table unsigned int no_tls_get_addr_opt:1; /* Support for multiple toc sections. */ - unsigned int no_multi_toc:1; unsigned int multi_toc_needed:1; + unsigned int second_toc_pass:1; /* Set on error. */ unsigned int stub_error:1; @@ -4736,6 +4740,7 @@ update_local_sym_info (bfd *abfd, Elf_Internal_Shdr *symtab_hdr, ent->addend = r_addend; ent->owner = abfd; ent->tls_type = tls_type; + ent->is_indirect = FALSE; ent->got.refcount = 0; local_got_ents[r_symndx] = ent; } @@ -4993,6 +4998,7 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, ent->addend = rel->r_addend; ent->owner = abfd; ent->tls_type = tls_type; + ent->is_indirect = FALSE; ent->got.refcount = 0; eh->elf.got.glist = ent; } @@ -8176,6 +8182,42 @@ ppc64_elf_edit_toc (bfd *obfd ATTRIBUTE_UNUSED, struct bfd_link_info *info) return TRUE; } +/* Allocate space for one GOT entry. */ + +static void +allocate_got (struct elf_link_hash_entry *h, + struct bfd_link_info *info, + struct got_entry *gent) +{ + struct ppc_link_hash_table *htab = ppc_hash_table (info); + bfd_boolean dyn; + struct ppc_link_hash_entry *eh = (struct ppc_link_hash_entry *) h; + int entsize = (gent->tls_type & eh->tls_mask & (TLS_GD | TLS_LD) + ? 16 : 8); + int rentsize = (gent->tls_type & eh->tls_mask & TLS_GD + ? 2 : 1) * sizeof (Elf64_External_Rela); + asection *got = ppc64_elf_tdata (gent->owner)->got; + + gent->got.offset = got->size; + got->size += entsize; + + dyn = htab->elf.dynamic_sections_created; + if ((info->shared + || WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, 0, h)) + && (ELF_ST_VISIBILITY (h->other) == STV_DEFAULT + || h->root.type != bfd_link_hash_undefweak)) + { + asection *relgot = ppc64_elf_tdata (gent->owner)->relgot; + relgot->size += rentsize; + } + else if (h->type == STT_GNU_IFUNC) + { + asection *relgot = htab->reliplt; + relgot->size += rentsize; + htab->got_reli_size += rentsize; + } +} + /* Allocate space in .plt, .got and associated reloc sections for dynamic relocs. */ @@ -8287,9 +8329,6 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf) for (gent = h->got.glist; gent != NULL; gent = gent->next) if (gent->got.refcount > 0) { - bfd_boolean dyn; - asection *rsec; - /* Make sure this symbol is output as a dynamic symbol. Undefined weak syms won't yet be marked as dynamic, nor will all TLS symbols. */ @@ -8305,31 +8344,15 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf) if ((gent->tls_type & TLS_LD) != 0 && !h->def_dynamic) { - ppc64_tlsld_got (gent->owner)->refcount += 1; + ppc64_tlsld_got (gent->owner)->got.refcount += 1; gent->got.offset = (bfd_vma) -1; continue; } if (!is_ppc64_elf (gent->owner)) - continue; + abort (); - s = ppc64_elf_tdata (gent->owner)->got; - gent->got.offset = s->size; - s->size - += (gent->tls_type & eh->tls_mask & (TLS_GD | TLS_LD)) ? 16 : 8; - dyn = htab->elf.dynamic_sections_created; - rsec = NULL; - if ((info->shared - || WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, 0, h)) - && (ELF_ST_VISIBILITY (h->other) == STV_DEFAULT - || h->root.type != bfd_link_hash_undefweak)) - rsec = ppc64_elf_tdata (gent->owner)->relgot; - else if (h->type == STT_GNU_IFUNC) - rsec = htab->reliplt; - if (rsec != NULL) - rsec->size += (gent->tls_type & eh->tls_mask & TLS_GD - ? 2 * sizeof (Elf64_External_Rela) - : sizeof (Elf64_External_Rela)); + allocate_got (h, info, gent); } else gent->got.offset = (bfd_vma) -1; @@ -8554,7 +8577,7 @@ ppc64_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED, { if ((ent->tls_type & *lgot_masks & TLS_LD) != 0) { - ppc64_tlsld_got (ibfd)->refcount += 1; + ppc64_tlsld_got (ibfd)->got.refcount += 1; ent->got.offset = (bfd_vma) -1; } else @@ -8567,7 +8590,12 @@ ppc64_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED, if (info->shared) srel->size += num * sizeof (Elf64_External_Rela); else if ((*lgot_masks & PLT_IFUNC) != 0) - htab->reliplt->size += num * sizeof (Elf64_External_Rela); + { + htab->reliplt->size + += num * sizeof (Elf64_External_Rela); + htab->got_reli_size + += num * sizeof (Elf64_External_Rela); + } } } else @@ -8602,10 +8630,11 @@ ppc64_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED, if (!is_ppc64_elf (ibfd)) continue; - if (ppc64_tlsld_got (ibfd)->refcount > 0) + if (ppc64_tlsld_got (ibfd)->got.refcount > 0) { s = ppc64_elf_tdata (ibfd)->got; - ppc64_tlsld_got (ibfd)->offset = s->size; + ppc64_tlsld_got (ibfd)->got.offset = s->size; + ppc64_tlsld_got (ibfd)->owner = ibfd; s->size += 16; if (info->shared) { @@ -8614,7 +8643,7 @@ ppc64_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED, } } else - ppc64_tlsld_got (ibfd)->offset = (bfd_vma) -1; + ppc64_tlsld_got (ibfd)->got.offset = (bfd_vma) -1; } /* We now have determined the sizes of the various dynamic sections. @@ -9573,9 +9602,10 @@ ppc_size_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg) 0 when no stubs will be needed, and 1 on success. */ int -ppc64_elf_setup_section_lists (bfd *output_bfd, - struct bfd_link_info *info, - int no_multi_toc) +ppc64_elf_setup_section_lists + (struct bfd_link_info *info, + asection *(*add_stub_section) (const char *, asection *), + void (*layout_sections_again) (void)) { bfd *input_bfd; int top_id, top_index, id; @@ -9584,7 +9614,9 @@ ppc64_elf_setup_section_lists (bfd *output_bfd, bfd_size_type amt; struct ppc_link_hash_table *htab = ppc_hash_table (info); - htab->no_multi_toc = no_multi_toc; + /* Stash our params away. */ + htab->add_stub_section = add_stub_section; + htab->layout_sections_again = layout_sections_again; if (htab->brlt == NULL) return 0; @@ -9613,14 +9645,10 @@ ppc64_elf_setup_section_lists (bfd *output_bfd, for (id = 0; id < 3; id++) htab->stub_group[id].toc_off = TOC_BASE_OFF; - elf_gp (output_bfd) = htab->toc_curr = ppc64_elf_toc (output_bfd); - htab->toc_bfd = NULL; - htab->toc_first_sec = NULL; - /* We can't use output_bfd->section_count here to find the top output section index as some sections may have been removed, and strip_excluded_output_sections doesn't renumber the indices. */ - for (section = output_bfd->sections, top_index = 0; + for (section = info->output_bfd->sections, top_index = 0; section != NULL; section = section->next) { @@ -9638,25 +9666,38 @@ ppc64_elf_setup_section_lists (bfd *output_bfd, return 1; } +/* Set up for first pass at multitoc partitioning. */ + +void +ppc64_elf_start_multitoc_partition (struct bfd_link_info *info) +{ + struct ppc_link_hash_table *htab = ppc_hash_table (info); + + elf_gp (info->output_bfd) = ppc64_elf_toc (info->output_bfd); + htab->toc_curr = elf_gp (info->output_bfd); + htab->toc_bfd = NULL; + htab->toc_first_sec = NULL; +} + /* The linker repeatedly calls this function for each TOC input section and linker generated GOT section. Group input bfds such that the toc - within a group is less than 64k in size. Will break with cute linker - scripts that play games with dot in the output toc section. */ + within a group is less than 64k in size. */ -void +bfd_boolean ppc64_elf_next_toc_section (struct bfd_link_info *info, asection *isec) { struct ppc_link_hash_table *htab = ppc_hash_table (info); + bfd_vma addr, off; - if (!htab->no_multi_toc) + if (!htab->second_toc_pass) { - bfd_vma addr, off; - + /* Keep track of the first .toc or .got section for this input bfd. */ if (htab->toc_bfd != isec->owner) { htab->toc_bfd = isec->owner; htab->toc_first_sec = isec; } + addr = isec->output_offset + isec->output_section->vma; off = addr - htab->toc_curr; if (off + isec->size > 0x10000) @@ -9666,23 +9707,320 @@ ppc64_elf_next_toc_section (struct bfd_link_info *info, asection *isec) htab->toc_curr = addr; } - elf_gp (isec->owner) = (htab->toc_curr - - elf_gp (isec->output_section->owner) - + TOC_BASE_OFF); + /* toc_curr is the base address of this toc group. Set elf_gp + for the input section to be the offset relative to the + output toc base plus 0x8000. Making the input elf_gp an + offset allows us to move the toc as a whole without + recalculating input elf_gp. */ + off = htab->toc_curr - elf_gp (isec->output_section->owner); + off += TOC_BASE_OFF; + + /* Die if someone uses a linker script that doesn't keep input + file .toc and .got together. */ + if (elf_gp (isec->owner) != 0 + && elf_gp (isec->owner) != off) + return FALSE; + + elf_gp (isec->owner) = off; + return TRUE; } + + /* During the second pass toc_first_sec points to the start of + a toc group, and toc_curr is used to track the old elf_gp. + We use toc_bfd to ensure we only look at each bfd once. */ + if (htab->toc_bfd == isec->owner) + return TRUE; + htab->toc_bfd = isec->owner; + + if (htab->toc_first_sec == NULL + || htab->toc_curr != elf_gp (isec->owner)) + { + htab->toc_curr = elf_gp (isec->owner); + htab->toc_first_sec = isec; + } + addr = (htab->toc_first_sec->output_offset + + htab->toc_first_sec->output_section->vma); + off = addr - elf_gp (isec->output_section->owner) + TOC_BASE_OFF; + elf_gp (isec->owner) = off; + + return TRUE; } -/* Called after the last call to the above function. */ +/* This function removes unneeded got entries (those with got.offset == -1) + and merges entries in the same toc group. */ -void -ppc64_elf_reinit_toc (bfd *output_bfd, struct bfd_link_info *info) +static void +merge_got_entries (struct got_entry **pent) +{ + struct got_entry *ent, *ent2; + + while ((ent = *pent) != NULL) + { + if (!ent->is_indirect) + { + if (ent->got.offset == (bfd_vma) -1) + { + *pent = ent->next; + continue; + } + for (ent2 = ent->next; ent2 != NULL; ent2 = ent2->next) + if (!ent2->is_indirect + && ent2->got.offset != (bfd_vma) -1 + && ent2->addend == ent->addend + && ent2->tls_type == ent->tls_type + && elf_gp (ent2->owner) == elf_gp (ent->owner)) + { + ent2->is_indirect = TRUE; + ent2->got.ent = ent; + } + } + pent = &ent->next; + } +} + +/* Called via elf_link_hash_traverse to merge GOT entries for global + symbol H. */ + +static bfd_boolean +merge_global_got (struct elf_link_hash_entry *h, void *inf ATTRIBUTE_UNUSED) +{ + if (h->root.type == bfd_link_hash_indirect) + return TRUE; + + if (h->root.type == bfd_link_hash_warning) + h = (struct elf_link_hash_entry *) h->root.u.i.link; + + merge_got_entries (&h->got.glist); + + return TRUE; +} + +/* Called via elf_link_hash_traverse to allocate GOT entries for global + symbol H. */ + +static bfd_boolean +reallocate_got (struct elf_link_hash_entry *h, void *inf) +{ + struct got_entry *gent; + + if (h->root.type == bfd_link_hash_indirect) + return TRUE; + + if (h->root.type == bfd_link_hash_warning) + h = (struct elf_link_hash_entry *) h->root.u.i.link; + + for (gent = h->got.glist; gent != NULL; gent = gent->next) + if (!gent->is_indirect) + allocate_got (h, (struct bfd_link_info *) inf, gent); + return TRUE; +} + +/* Called on the first multitoc pass after the last call to + ppc64_elf_next_toc_section. This function removes duplicate GOT + entries. */ + +bfd_boolean +ppc64_elf_layout_multitoc (struct bfd_link_info *info) { struct ppc_link_hash_table *htab = ppc_hash_table (info); + struct bfd *ibfd, *ibfd2; + bfd_boolean done_something; + + htab->multi_toc_needed = htab->toc_curr != elf_gp (info->output_bfd); - htab->multi_toc_needed = htab->toc_curr != elf_gp (output_bfd); + /* Merge local got entries within a toc group. */ + for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next) + { + struct got_entry **lgot_ents; + struct got_entry **end_lgot_ents; + Elf_Internal_Shdr *symtab_hdr; + bfd_size_type locsymcount; - /* toc_curr tracks the TOC offset used for code sections below in - ppc64_elf_next_input_section. Start off at 0x8000. */ + if (!is_ppc64_elf (ibfd)) + continue; + + lgot_ents = elf_local_got_ents (ibfd); + if (!lgot_ents) + continue; + + symtab_hdr = &elf_symtab_hdr (ibfd); + locsymcount = symtab_hdr->sh_info; + end_lgot_ents = lgot_ents + locsymcount; + + for (; lgot_ents < end_lgot_ents; ++lgot_ents) + merge_got_entries (lgot_ents); + } + + /* And the same for global sym got entries. */ + elf_link_hash_traverse (&htab->elf, merge_global_got, info); + + /* And tlsld_got. */ + for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next) + { + struct got_entry *ent, *ent2; + + if (!is_ppc64_elf (ibfd)) + continue; + + ent = ppc64_tlsld_got (ibfd); + if (!ent->is_indirect + && ent->got.offset != (bfd_vma) -1) + { + for (ibfd2 = ibfd->link_next; ibfd2 != NULL; ibfd2 = ibfd2->link_next) + { + if (!is_ppc64_elf (ibfd2)) + continue; + + ent2 = ppc64_tlsld_got (ibfd2); + if (!ent2->is_indirect + && ent2->got.offset != (bfd_vma) -1 + && elf_gp (ibfd2) == elf_gp (ibfd)) + { + ent2->is_indirect = TRUE; + ent2->got.ent = ent; + } + } + } + } + + /* Zap sizes of got sections. */ + htab->reliplt->rawsize = htab->reliplt->size; + htab->reliplt->size -= htab->got_reli_size; + htab->got_reli_size = 0; + + for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next) + { + asection *got, *relgot; + + if (!is_ppc64_elf (ibfd)) + continue; + + got = ppc64_elf_tdata (ibfd)->got; + if (got != NULL) + { + got->rawsize = got->size; + got->size = 0; + relgot = ppc64_elf_tdata (ibfd)->relgot; + relgot->rawsize = relgot->size; + relgot->size = 0; + } + } + + /* Now reallocate the got, local syms first. We don't need to + allocate section contents again since we never increase size. */ + for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next) + { + struct got_entry **lgot_ents; + struct got_entry **end_lgot_ents; + struct plt_entry **local_plt; + struct plt_entry **end_local_plt; + char *lgot_masks; + bfd_size_type locsymcount; + Elf_Internal_Shdr *symtab_hdr; + asection *s, *srel; + + if (!is_ppc64_elf (ibfd)) + continue; + + lgot_ents = elf_local_got_ents (ibfd); + if (!lgot_ents) + continue; + + symtab_hdr = &elf_symtab_hdr (ibfd); + locsymcount = symtab_hdr->sh_info; + end_lgot_ents = lgot_ents + locsymcount; + local_plt = (struct plt_entry **) end_lgot_ents; + end_local_plt = local_plt + locsymcount; + lgot_masks = (char *) end_local_plt; + s = ppc64_elf_tdata (ibfd)->got; + srel = ppc64_elf_tdata (ibfd)->relgot; + for (; lgot_ents < end_lgot_ents; ++lgot_ents, ++lgot_masks) + { + struct got_entry *ent; + + for (ent = *lgot_ents; ent != NULL; ent = ent->next) + if (!ent->is_indirect) + { + unsigned int num = 1; + ent->got.offset = s->size; + if ((ent->tls_type & *lgot_masks & TLS_GD) != 0) + num = 2; + s->size += num * 8; + if (info->shared) + srel->size += num * sizeof (Elf64_External_Rela); + else if ((*lgot_masks & PLT_IFUNC) != 0) + { + htab->reliplt->size + += num * sizeof (Elf64_External_Rela); + htab->got_reli_size + += num * sizeof (Elf64_External_Rela); + } + } + } + } + + elf_link_hash_traverse (&htab->elf, reallocate_got, info); + + for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next) + { + struct got_entry *ent; + + if (!is_ppc64_elf (ibfd)) + continue; + + ent = ppc64_tlsld_got (ibfd); + if (!ent->is_indirect + && ent->got.offset != (bfd_vma) -1) + { + asection *s = ppc64_elf_tdata (ibfd)->got; + ent->got.offset = s->size; + s->size += 16; + if (info->shared) + { + asection *srel = ppc64_elf_tdata (ibfd)->relgot; + srel->size += sizeof (Elf64_External_Rela); + } + } + } + + done_something = htab->reliplt->rawsize != htab->reliplt->size; + if (!done_something) + for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next) + { + asection *got; + + if (!is_ppc64_elf (ibfd)) + continue; + + got = ppc64_elf_tdata (ibfd)->got; + if (got != NULL) + { + done_something = got->rawsize != got->size; + if (done_something) + break; + } + } + + if (done_something) + (*htab->layout_sections_again) (); + + /* Set up for second pass over toc sections to recalculate elf_gp + on input sections. */ + htab->toc_bfd = NULL; + htab->toc_first_sec = NULL; + htab->second_toc_pass = TRUE; + return done_something; +} + +/* Called after second pass of multitoc partitioning. */ + +void +ppc64_elf_finish_multitoc_partition (struct bfd_link_info *info) +{ + struct ppc_link_hash_table *htab = ppc_hash_table (info); + + /* After the second pass, toc_curr tracks the TOC offset used + for code sections below in ppc64_elf_next_input_section. */ htab->toc_curr = TOC_BASE_OFF; } @@ -10055,19 +10393,12 @@ group_sections (struct ppc_link_hash_table *htab, instruction. */ bfd_boolean -ppc64_elf_size_stubs (bfd *output_bfd, - struct bfd_link_info *info, - bfd_signed_vma group_size, - asection *(*add_stub_section) (const char *, asection *), - void (*layout_sections_again) (void)) +ppc64_elf_size_stubs (struct bfd_link_info *info, bfd_signed_vma group_size) { bfd_size_type stub_group_size; bfd_boolean stubs_always_before_branch; struct ppc_link_hash_table *htab = ppc_hash_table (info); - /* Stash our params away. */ - htab->add_stub_section = add_stub_section; - htab->layout_sections_again = layout_sections_again; stubs_always_before_branch = group_size < 0; if (group_size < 0) stub_group_size = -group_size; @@ -10119,7 +10450,7 @@ ppc64_elf_size_stubs (bfd *output_bfd, /* If this section is a link-once section that will be discarded, then don't create any stubs. */ if (section->output_section == NULL - || section->output_section->owner != output_bfd) + || section->output_section->owner != info->output_bfd) continue; /* Get the relocs. */ @@ -11599,14 +11930,14 @@ ppc64_elf_relocate_section (bfd *output_bfd, bfd_vma *offp; bfd_vma off; unsigned long indx = 0; + struct got_entry *ent; if (tls_type == (TLS_TLS | TLS_LD) && (h == NULL || !h->elf.def_dynamic)) - offp = &ppc64_tlsld_got (input_bfd)->offset; + ent = ppc64_tlsld_got (input_bfd); else { - struct got_entry *ent; if (h != NULL) { @@ -11639,12 +11970,14 @@ ppc64_elf_relocate_section (bfd *output_bfd, && ent->owner == input_bfd && ent->tls_type == tls_type) break; - if (ent == NULL) - abort (); - offp = &ent->got.offset; } - got = ppc64_elf_tdata (input_bfd)->got; + if (ent == NULL) + abort (); + if (ent->is_indirect) + ent = ent->got.ent; + offp = &ent->got.offset; + got = ppc64_elf_tdata (ent->owner)->got; if (got == NULL) abort (); @@ -11668,11 +12001,12 @@ ppc64_elf_relocate_section (bfd *output_bfd, ? h->elf.type == STT_GNU_IFUNC : ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC); if ((info->shared || indx != 0) - && (offp == &ppc64_tlsld_got (input_bfd)->offset - || h == NULL + && (h == NULL + || (tls_type == (TLS_TLS | TLS_LD) + && !h->elf.def_dynamic) || ELF_ST_VISIBILITY (h->elf.other) == STV_DEFAULT || h->elf.root.type != bfd_link_hash_undefweak)) - relgot = ppc64_elf_tdata (input_bfd)->relgot; + relgot = ppc64_elf_tdata (ent->owner)->relgot; else if (ifunc) relgot = htab->reliplt; if (relgot != NULL) diff --git a/bfd/elf64-ppc.h b/bfd/elf64-ppc.h index e5f7140..79bb1b3 100644 --- a/bfd/elf64-ppc.h +++ b/bfd/elf64-ppc.h @@ -1,5 +1,5 @@ /* PowerPC64-specific support for 64-bit ELF. - Copyright 2002, 2003, 2004, 2005, 2007, 2008 + Copyright 2002, 2003, 2004, 2005, 2007, 2008, 2010 Free Software Foundation, Inc. This file is part of BFD, the Binary File Descriptor library. @@ -24,7 +24,7 @@ void ppc64_elf_init_stub_bfd bfd_boolean ppc64_elf_edit_opd (bfd *, struct bfd_link_info *, bfd_boolean); asection *ppc64_elf_tls_setup -(bfd *, struct bfd_link_info *, int); + (bfd *, struct bfd_link_info *, int); bfd_boolean ppc64_elf_tls_optimize (bfd *, struct bfd_link_info *); bfd_boolean ppc64_elf_edit_toc @@ -32,16 +32,20 @@ bfd_boolean ppc64_elf_edit_toc bfd_vma ppc64_elf_toc (bfd *); int ppc64_elf_setup_section_lists - (bfd *, struct bfd_link_info *, int); -void ppc64_elf_next_toc_section + (struct bfd_link_info *, asection *(*) (const char *, asection *), + void (*) (void)); +void ppc64_elf_start_multitoc_partition + (struct bfd_link_info *); +bfd_boolean ppc64_elf_next_toc_section (struct bfd_link_info *, asection *); -void ppc64_elf_reinit_toc - (bfd *, struct bfd_link_info *); +bfd_boolean ppc64_elf_layout_multitoc + (struct bfd_link_info *); +void ppc64_elf_finish_multitoc_partition + (struct bfd_link_info *); bfd_boolean ppc64_elf_next_input_section (struct bfd_link_info *, asection *); bfd_boolean ppc64_elf_size_stubs - (bfd *, struct bfd_link_info *, bfd_signed_vma, - asection *(*) (const char *, asection *), void (*) (void)); + (struct bfd_link_info *, bfd_signed_vma); bfd_boolean ppc64_elf_build_stubs (bfd_boolean, struct bfd_link_info *, char **); void ppc64_elf_restore_symbols diff --git a/ld/ChangeLog b/ld/ChangeLog index baaf4df..c40683b 100644 --- a/ld/ChangeLog +++ b/ld/ChangeLog @@ -1,3 +1,10 @@ +2010-02-03 Alan Modra + + * emultempl/ppc64elf.em (build_toc_list): Report errors from + ppc64_elf_next_toc_section. + (after_allocation): Update for changed function names and params. + Run second pass of multitoc partitioning. + 2010-01-21 Jon Grant Nick Clifton diff --git a/ld/emultempl/ppc64elf.em b/ld/emultempl/ppc64elf.em index 88971d7..a11f300 100644 --- a/ld/emultempl/ppc64elf.em +++ b/ld/emultempl/ppc64elf.em @@ -1,5 +1,5 @@ # This shell script emits a C file. -*- C -*- -# Copyright 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 +# Copyright 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 # Free Software Foundation, Inc. # # This file is part of the GNU Binutils. @@ -279,7 +279,10 @@ build_toc_list (lang_statement_union_type *statement) if (!((lang_input_statement_type *) i->owner->usrdata)->just_syms_flag && (i->flags & SEC_EXCLUDE) == 0 && i->output_section == toc_section) - ppc64_elf_next_toc_section (&link_info, i); + { + if (!ppc64_elf_next_toc_section (&link_info, i)) + einfo ("%X%P: linker script separates .got and .toc\n"); + } } } @@ -319,27 +322,34 @@ gld${EMULATION_NAME}_after_allocation (void) stubs. */ if (stub_file != NULL && !link_info.relocatable) { - int ret = ppc64_elf_setup_section_lists (link_info.output_bfd, - &link_info, - no_multi_toc); + int ret = ppc64_elf_setup_section_lists (&link_info, + &ppc_add_stub_section, + &ppc_layout_sections_again); if (ret < 0) einfo ("%X%P: can not size stub section: %E\n"); else if (ret > 0) { - toc_section = bfd_get_section_by_name (link_info.output_bfd, ".got"); - if (toc_section != NULL) + ppc64_elf_start_multitoc_partition (&link_info); + + if (!no_multi_toc) + { + toc_section = bfd_get_section_by_name (link_info.output_bfd, + ".got"); + if (toc_section != NULL) + lang_for_each_statement (build_toc_list); + } + + if (ppc64_elf_layout_multitoc (&link_info) + && !no_multi_toc + && toc_section != NULL) lang_for_each_statement (build_toc_list); - ppc64_elf_reinit_toc (link_info.output_bfd, &link_info); + ppc64_elf_finish_multitoc_partition (&link_info); lang_for_each_statement (build_section_lists); /* Call into the BFD backend to do the real work. */ - if (!ppc64_elf_size_stubs (link_info.output_bfd, - &link_info, - group_size, - &ppc_add_stub_section, - &ppc_layout_sections_again)) + if (!ppc64_elf_size_stubs (&link_info, group_size)) einfo ("%X%P: can not size stub section: %E\n"); } }