X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=bfd%2Felf64-ppc.c;h=47acd93554ffcc8bc31cf8305cb51cf6216c1472;hb=ceab86af75e9870ecf2da772a0d867ca12521a24;hp=17b7a134a0cc3eecdd9bc6ea5830090871c2c4fd;hpb=006589cfa144fc1efeea1d114943c0bd1624e930;p=deliverable%2Fbinutils-gdb.git diff --git a/bfd/elf64-ppc.c b/bfd/elf64-ppc.c index 17b7a134a0..47acd93554 100644 --- a/bfd/elf64-ppc.c +++ b/bfd/elf64-ppc.c @@ -1,5 +1,5 @@ /* PowerPC64-specific support for 64-bit ELF. - Copyright (C) 1999-2015 Free Software Foundation, Inc. + Copyright (C) 1999-2016 Free Software Foundation, Inc. Written by Linus Nordberg, Swox AB , based on elf32-ppc.c by Ian Lance Taylor. Largely rewritten by Alan Modra. @@ -2570,6 +2570,7 @@ ppc64_elf_branch_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol, elf_symbol_type *elfsym = (elf_symbol_type *) symbol; if (symbol->section->owner != abfd + && symbol->section->owner != NULL && abiversion (symbol->section->owner) >= 2) { unsigned int i; @@ -4344,14 +4345,20 @@ create_linkage_sections (bfd *dynobj, struct bfd_link_info *info) htab = ppc_hash_table (info); - /* Create .sfpr for code to save and restore fp regs. */ flags = (SEC_ALLOC | SEC_LOAD | SEC_CODE | SEC_READONLY | SEC_HAS_CONTENTS | SEC_IN_MEMORY | SEC_LINKER_CREATED); - htab->sfpr = bfd_make_section_anyway_with_flags (dynobj, ".sfpr", - flags); - if (htab->sfpr == NULL - || ! bfd_set_section_alignment (dynobj, htab->sfpr, 2)) - return FALSE; + if (htab->params->save_restore_funcs) + { + /* Create .sfpr for code to save and restore fp regs. */ + htab->sfpr = bfd_make_section_anyway_with_flags (dynobj, ".sfpr", + flags); + if (htab->sfpr == NULL + || ! bfd_set_section_alignment (dynobj, htab->sfpr, 2)) + return FALSE; + } + + if (bfd_link_relocatable (info)) + return TRUE; /* Create .glink for lazy dynamic linking support. */ htab->glink = bfd_make_section_anyway_with_flags (dynobj, ".glink", @@ -4424,14 +4431,9 @@ ppc64_elf_init_stub_bfd (struct bfd_link_info *info, linker created stub bfd. This ensures that the GOT header is at the start of the output TOC section. */ htab = ppc_hash_table (info); - if (htab == NULL) - return FALSE; htab->elf.dynobj = params->stub_bfd; htab->params = params; - if (bfd_link_relocatable (info)) - return TRUE; - return create_linkage_sections (htab->elf.dynobj, info); } @@ -4893,11 +4895,10 @@ ppc64_elf_add_symbol_hook (bfd *ibfd, asection **sec, bfd_vma *value) { - if ((ELF_ST_TYPE (isym->st_info) == STT_GNU_IFUNC - || ELF_ST_BIND (isym->st_info) == STB_GNU_UNIQUE) + if (ELF_ST_TYPE (isym->st_info) == STT_GNU_IFUNC && (ibfd->flags & DYNAMIC) == 0 && bfd_get_flavour (info->output_bfd) == bfd_target_elf_flavour) - elf_tdata (info->output_bfd)->has_gnu_symbols = elf_gnu_symbol_any; + elf_tdata (info->output_bfd)->has_gnu_symbols |= elf_gnu_symbol_ifunc; if (*sec != NULL && strcmp ((*sec)->name, ".opd") == 0) @@ -5149,7 +5150,7 @@ ppc64_elf_before_check_relocs (bfd *ibfd, struct bfd_link_info *info) } /* We need to fix the undefs list for any syms we have twiddled to - undef_weak. */ + undefweak. */ if (htab->twiddled_syms) { bfd_link_repair_undef_list (&htab->elf.root); @@ -5340,7 +5341,7 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, enum elf_ppc64_reloc_type r_type; int tls_type; struct _ppc64_elf_section_data *ppc64_sec; - struct plt_entry **ifunc; + struct plt_entry **ifunc, **plt_list; r_symndx = ELF64_R_SYM (rel->r_info); if (r_symndx < symtab_hdr->sh_info) @@ -5383,28 +5384,8 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, return FALSE; } } - r_type = ELF64_R_TYPE (rel->r_info); - if (is_branch_reloc (r_type)) - { - if (h != NULL && (h == tga || h == dottga)) - { - if (rel != relocs - && (ELF64_R_TYPE (rel[-1].r_info) == R_PPC64_TLSGD - || ELF64_R_TYPE (rel[-1].r_info) == R_PPC64_TLSLD)) - /* We have a new-style __tls_get_addr call with a marker - reloc. */ - ; - else - /* Mark this section as having an old-style call. */ - sec->has_tls_get_addr_call = 1; - } - - /* STT_GNU_IFUNC symbols must have a PLT entry. */ - if (ifunc != NULL - && !update_plt_info (abfd, ifunc, rel->r_addend)) - return FALSE; - } + r_type = ELF64_R_TYPE (rel->r_info); switch (r_type) { case R_PPC64_TLSGD: @@ -5516,27 +5497,29 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, case R_PPC64_PLT16_LO: case R_PPC64_PLT32: case R_PPC64_PLT64: - /* This symbol requires a procedure linkage table entry. We - actually build the entry in adjust_dynamic_symbol, - because this might be a case of linking PIC code without - linking in any dynamic objects, in which case we don't - need to generate a procedure linkage table after all. */ - if (h == NULL) - { - /* It does not make sense to have a procedure linkage - table entry for a local symbol. */ - bfd_set_error (bfd_error_bad_value); - return FALSE; - } - else + /* This symbol requires a procedure linkage table entry. */ + plt_list = ifunc; + if (h != NULL) { - if (!update_plt_info (abfd, &h->plt.plist, rel->r_addend)) - return FALSE; h->needs_plt = 1; if (h->root.root.string[0] == '.' && h->root.root.string[1] != '\0') ((struct ppc_link_hash_entry *) h)->is_func = 1; + plt_list = &h->plt.plist; + } + if (plt_list == NULL) + { + /* It does not make sense to have a procedure linkage + table entry for a non-ifunc local symbol. */ + info->callbacks->einfo + (_("%P: %H: %s reloc against local symbol\n"), + abfd, sec, rel->r_offset, + ppc64_elf_howto_table[r_type]->name); + bfd_set_error (bfd_error_bad_value); + return FALSE; } + if (!update_plt_info (abfd, plt_list, rel->r_addend)) + return FALSE; break; /* The following relocations don't need to propagate the @@ -5649,21 +5632,43 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, /* Fall through. */ case R_PPC64_REL24: - if (h != NULL && ifunc == NULL) + plt_list = ifunc; + if (h != NULL) { - /* We may need a .plt entry if the function this reloc - refers to is in a shared lib. */ - if (!update_plt_info (abfd, &h->plt.plist, rel->r_addend)) - return FALSE; h->needs_plt = 1; if (h->root.root.string[0] == '.' && h->root.root.string[1] != '\0') ((struct ppc_link_hash_entry *) h)->is_func = 1; + if (h == tga || h == dottga) - sec->has_tls_reloc = 1; + { + sec->has_tls_reloc = 1; + if (rel != relocs + && (ELF64_R_TYPE (rel[-1].r_info) == R_PPC64_TLSGD + || ELF64_R_TYPE (rel[-1].r_info) == R_PPC64_TLSLD)) + /* We have a new-style __tls_get_addr call with + a marker reloc. */ + ; + else + /* Mark this section as having an old-style call. */ + sec->has_tls_get_addr_call = 1; + } + plt_list = &h->plt.plist; } + + /* We may need a .plt entry if the function this reloc + refers to is in a shared lib. */ + if (plt_list + && !update_plt_info (abfd, plt_list, rel->r_addend)) + return FALSE; break; + case R_PPC64_ADDR14: + case R_PPC64_ADDR14_BRNTAKEN: + case R_PPC64_ADDR14_BRTAKEN: + case R_PPC64_ADDR24: + goto dodyn; + case R_PPC64_TPREL64: tls_type = TLS_EXPLICIT | TLS_TLS | TLS_TPREL; if (bfd_link_pic (info)) @@ -5806,10 +5811,6 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, case R_PPC64_REL30: case R_PPC64_REL32: case R_PPC64_REL64: - case R_PPC64_ADDR14: - case R_PPC64_ADDR14_BRNTAKEN: - case R_PPC64_ADDR14_BRTAKEN: - case R_PPC64_ADDR24: case R_PPC64_ADDR32: case R_PPC64_UADDR16: case R_PPC64_UADDR32: @@ -6505,6 +6506,7 @@ ppc64_elf_gc_sweep_hook (bfd *abfd, struct bfd_link_info *info, unsigned long r_symndx; enum elf_ppc64_reloc_type r_type; struct elf_link_hash_entry *h = NULL; + struct plt_entry **plt_list; unsigned char tls_type = 0; r_symndx = ELF64_R_SYM (rel->r_info); @@ -6528,38 +6530,6 @@ ppc64_elf_gc_sweep_hook (bfd *abfd, struct bfd_link_info *info, } } - if (is_branch_reloc (r_type)) - { - struct plt_entry **ifunc = NULL; - if (h != NULL) - { - if (h->type == STT_GNU_IFUNC) - ifunc = &h->plt.plist; - } - else if (local_got_ents != NULL) - { - struct plt_entry **local_plt = (struct plt_entry **) - (local_got_ents + symtab_hdr->sh_info); - unsigned char *local_got_tls_masks = (unsigned char *) - (local_plt + symtab_hdr->sh_info); - if ((local_got_tls_masks[r_symndx] & PLT_IFUNC) != 0) - ifunc = local_plt + r_symndx; - } - if (ifunc != NULL) - { - struct plt_entry *ent; - - for (ent = *ifunc; ent != NULL; ent = ent->next) - if (ent->addend == rel->r_addend) - break; - if (ent == NULL) - abort (); - if (ent->plt.refcount > 0) - ent->plt.refcount -= 1; - continue; - } - } - switch (r_type) { case R_PPC64_GOT_TLSLD16: @@ -6626,11 +6596,23 @@ ppc64_elf_gc_sweep_hook (bfd *abfd, struct bfd_link_info *info, case R_PPC64_REL14_BRNTAKEN: case R_PPC64_REL14_BRTAKEN: case R_PPC64_REL24: + plt_list = NULL; if (h != NULL) + plt_list = &h->plt.plist; + else if (local_got_ents != NULL) + { + struct plt_entry **local_plt = (struct plt_entry **) + (local_got_ents + symtab_hdr->sh_info); + unsigned char *local_got_tls_masks = (unsigned char *) + (local_plt + symtab_hdr->sh_info); + if ((local_got_tls_masks[r_symndx] & PLT_IFUNC) != 0) + plt_list = local_plt + r_symndx; + } + if (plt_list) { struct plt_entry *ent; - for (ent = h->plt.plist; ent != NULL; ent = ent->next) + for (ent = *plt_list; ent != NULL; ent = ent->next) if (ent->addend == rel->r_addend) break; if (ent != NULL && ent->plt.refcount > 0) @@ -6684,7 +6666,7 @@ sfpr_define (struct bfd_link_info *info, sym[len + 0] = i / 10 + '0'; sym[len + 1] = i % 10 + '0'; h = (struct ppc_link_hash_entry *) - elf_link_hash_lookup (&htab->elf, sym, FALSE, FALSE, TRUE); + elf_link_hash_lookup (&htab->elf, sym, writing, TRUE, TRUE); if (stub_sec != NULL) { if (h != NULL @@ -6725,6 +6707,7 @@ sfpr_define (struct bfd_link_info *info, h->elf.root.u.def.value = htab->sfpr->size; h->elf.type = STT_FUNC; h->elf.def_regular = 1; + h->elf.non_elf = 0; _bfd_elf_link_hash_hide_symbol (info, &h->elf, TRUE); writing = TRUE; if (htab->sfpr->contents == NULL) @@ -7069,14 +7052,28 @@ ppc64_elf_func_desc_adjust (bfd *obfd ATTRIBUTE_UNUSED, struct bfd_link_info *info) { struct ppc_link_hash_table *htab; - unsigned int i; htab = ppc_hash_table (info); if (htab == NULL) return FALSE; - if (!bfd_link_relocatable (info) - && htab->elf.hgot != NULL) + /* Provide any missing _save* and _rest* functions. */ + if (htab->sfpr != NULL) + { + unsigned int i; + + htab->sfpr->size = 0; + for (i = 0; i < ARRAY_SIZE (save_res_funcs); i++) + if (!sfpr_define (info, &save_res_funcs[i], NULL)) + return FALSE; + if (htab->sfpr->size == 0) + htab->sfpr->flags |= SEC_EXCLUDE; + } + + if (bfd_link_relocatable (info)) + return TRUE; + + if (htab->elf.hgot != NULL) { _bfd_elf_link_hash_hide_symbol (info, htab->elf.hgot, TRUE); /* Make .TOC. defined so as to prevent it being made dynamic. @@ -7095,22 +7092,8 @@ ppc64_elf_func_desc_adjust (bfd *obfd ATTRIBUTE_UNUSED, | STV_HIDDEN); } - if (htab->sfpr == NULL) - /* We don't have any relocs. */ - return TRUE; - - /* Provide any missing _save* and _rest* functions. */ - htab->sfpr->size = 0; - if (htab->params->save_restore_funcs) - for (i = 0; i < ARRAY_SIZE (save_res_funcs); i++) - if (!sfpr_define (info, &save_res_funcs[i], NULL)) - return FALSE; - elf_link_hash_traverse (&htab->elf, func_desc_adjust, info); - if (htab->sfpr->size == 0) - htab->sfpr->flags |= SEC_EXCLUDE; - return TRUE; } @@ -8243,6 +8226,7 @@ ppc64_elf_tls_setup (struct bfd_link_info *info) tga_fd->root.type = bfd_link_hash_indirect; tga_fd->root.u.i.link = &opt_fd->root; ppc64_elf_copy_indirect_symbol (info, opt_fd, tga_fd); + opt_fd->forced_local = 0; if (opt_fd->dynindx != -1) { /* Use __tls_get_addr_opt in dynamic relocations. */ @@ -8259,6 +8243,7 @@ ppc64_elf_tls_setup (struct bfd_link_info *info) tga->root.type = bfd_link_hash_indirect; tga->root.u.i.link = &opt->root; ppc64_elf_copy_indirect_symbol (info, opt, tga); + opt->forced_local = 0; _bfd_elf_link_hash_hide_symbol (info, opt, tga->forced_local); htab->tls_get_addr = (struct ppc_link_hash_entry *) opt; @@ -9568,71 +9553,6 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf) if (htab == NULL) return FALSE; - if ((htab->elf.dynamic_sections_created - && h->dynindx != -1 - && WILL_CALL_FINISH_DYNAMIC_SYMBOL (1, bfd_link_pic (info), h)) - || h->type == STT_GNU_IFUNC) - { - struct plt_entry *pent; - bfd_boolean doneone = FALSE; - for (pent = h->plt.plist; pent != NULL; pent = pent->next) - if (pent->plt.refcount > 0) - { - if (!htab->elf.dynamic_sections_created - || h->dynindx == -1) - { - s = htab->elf.iplt; - pent->plt.offset = s->size; - s->size += PLT_ENTRY_SIZE (htab); - s = htab->elf.irelplt; - } - else - { - /* If this is the first .plt entry, make room for the special - first entry. */ - s = htab->elf.splt; - if (s->size == 0) - s->size += PLT_INITIAL_ENTRY_SIZE (htab); - - pent->plt.offset = s->size; - - /* Make room for this entry. */ - s->size += PLT_ENTRY_SIZE (htab); - - /* Make room for the .glink code. */ - s = htab->glink; - if (s->size == 0) - s->size += GLINK_CALL_STUB_SIZE; - if (htab->opd_abi) - { - /* We need bigger stubs past index 32767. */ - if (s->size >= GLINK_CALL_STUB_SIZE + 32768*2*4) - s->size += 4; - s->size += 2*4; - } - else - s->size += 4; - - /* We also need to make an entry in the .rela.plt section. */ - s = htab->elf.srelplt; - } - s->size += sizeof (Elf64_External_Rela); - doneone = TRUE; - } - else - pent->plt.offset = (bfd_vma) -1; - if (!doneone) - { - h->plt.plist = NULL; - h->needs_plt = 0; - } - } - else - { - h->plt.plist = NULL; - h->needs_plt = 0; - } - eh = (struct ppc_link_hash_entry *) h; /* Run through the TLS GD got entries first if we're changing them to TPREL. */ @@ -9702,99 +9622,165 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf) allocate_got (h, info, gent); } - if (eh->dyn_relocs == NULL - || (!htab->elf.dynamic_sections_created - && h->type != STT_GNU_IFUNC)) - return TRUE; - - /* In the shared -Bsymbolic case, discard space allocated for - dynamic pc-relative relocs against symbols which turn out to be - defined in regular objects. For the normal shared case, discard - space for relocs that have become local due to symbol visibility - changes. */ - - if (bfd_link_pic (info)) + if (eh->dyn_relocs != NULL + && (htab->elf.dynamic_sections_created + || h->type == STT_GNU_IFUNC)) { - /* Relocs that use pc_count are those that appear on a call insn, - or certain REL relocs (see must_be_dyn_reloc) that can be - generated via assembly. We want calls to protected symbols to - resolve directly to the function rather than going via the plt. - If people want function pointer comparisons to work as expected - then they should avoid writing weird assembly. */ - if (SYMBOL_CALLS_LOCAL (info, h)) + /* In the shared -Bsymbolic case, discard space allocated for + dynamic pc-relative relocs against symbols which turn out to + be defined in regular objects. For the normal shared case, + discard space for relocs that have become local due to symbol + visibility changes. */ + + if (bfd_link_pic (info)) { - struct elf_dyn_relocs **pp; + /* Relocs that use pc_count are those that appear on a call + insn, or certain REL relocs (see must_be_dyn_reloc) that + can be generated via assembly. We want calls to + protected symbols to resolve directly to the function + rather than going via the plt. If people want function + pointer comparisons to work as expected then they should + avoid writing weird assembly. */ + if (SYMBOL_CALLS_LOCAL (info, h)) + { + struct elf_dyn_relocs **pp; - for (pp = &eh->dyn_relocs; (p = *pp) != NULL; ) + for (pp = &eh->dyn_relocs; (p = *pp) != NULL; ) + { + p->count -= p->pc_count; + p->pc_count = 0; + if (p->count == 0) + *pp = p->next; + else + pp = &p->next; + } + } + + /* Also discard relocs on undefined weak syms with + non-default visibility. */ + if (eh->dyn_relocs != NULL + && h->root.type == bfd_link_hash_undefweak) { - p->count -= p->pc_count; - p->pc_count = 0; - if (p->count == 0) - *pp = p->next; - else - pp = &p->next; + if (ELF_ST_VISIBILITY (h->other) != STV_DEFAULT) + eh->dyn_relocs = NULL; + + /* Make sure this symbol is output as a dynamic symbol. + Undefined weak syms won't yet be marked as dynamic. */ + else if (h->dynindx == -1 + && !h->forced_local) + { + if (! bfd_elf_link_record_dynamic_symbol (info, h)) + return FALSE; + } } } - - /* Also discard relocs on undefined weak syms with non-default - visibility. */ - if (eh->dyn_relocs != NULL - && h->root.type == bfd_link_hash_undefweak) + else if (h->type == STT_GNU_IFUNC) { - if (ELF_ST_VISIBILITY (h->other) != STV_DEFAULT) + if (!h->non_got_ref) eh->dyn_relocs = NULL; + } + else if (ELIMINATE_COPY_RELOCS) + { + /* For the non-shared case, discard space for relocs against + symbols which turn out to need copy relocs or are not + dynamic. */ - /* Make sure this symbol is output as a dynamic symbol. - Undefined weak syms won't yet be marked as dynamic. */ - else if (h->dynindx == -1 - && !h->forced_local) + if (!h->non_got_ref + && !h->def_regular) { - if (! bfd_elf_link_record_dynamic_symbol (info, h)) - return FALSE; + /* Make sure this symbol is output as a dynamic symbol. + Undefined weak syms won't yet be marked as dynamic. */ + if (h->dynindx == -1 + && !h->forced_local) + { + if (! bfd_elf_link_record_dynamic_symbol (info, h)) + return FALSE; + } + + /* If that succeeded, we know we'll be keeping all the + relocs. */ + if (h->dynindx != -1) + goto keep; } + + eh->dyn_relocs = NULL; + + keep: ; + } + + /* Finally, allocate space. */ + for (p = eh->dyn_relocs; p != NULL; p = p->next) + { + asection *sreloc = elf_section_data (p->sec)->sreloc; + if (eh->elf.type == STT_GNU_IFUNC) + sreloc = htab->elf.irelplt; + sreloc->size += p->count * sizeof (Elf64_External_Rela); } } - else if (h->type == STT_GNU_IFUNC) - { - if (!h->non_got_ref) - eh->dyn_relocs = NULL; - } - else if (ELIMINATE_COPY_RELOCS) + + if ((htab->elf.dynamic_sections_created + && h->dynindx != -1 + && WILL_CALL_FINISH_DYNAMIC_SYMBOL (1, bfd_link_pic (info), h)) + || h->type == STT_GNU_IFUNC) { - /* For the non-shared case, discard space for relocs against - symbols which turn out to need copy relocs or are not - dynamic. */ + struct plt_entry *pent; + bfd_boolean doneone = FALSE; + for (pent = h->plt.plist; pent != NULL; pent = pent->next) + if (pent->plt.refcount > 0) + { + if (!htab->elf.dynamic_sections_created + || h->dynindx == -1) + { + s = htab->elf.iplt; + pent->plt.offset = s->size; + s->size += PLT_ENTRY_SIZE (htab); + s = htab->elf.irelplt; + } + else + { + /* If this is the first .plt entry, make room for the special + first entry. */ + s = htab->elf.splt; + if (s->size == 0) + s->size += PLT_INITIAL_ENTRY_SIZE (htab); - if (!h->non_got_ref - && !h->def_regular) - { - /* Make sure this symbol is output as a dynamic symbol. - Undefined weak syms won't yet be marked as dynamic. */ - if (h->dynindx == -1 - && !h->forced_local) - { - if (! bfd_elf_link_record_dynamic_symbol (info, h)) - return FALSE; - } + pent->plt.offset = s->size; - /* If that succeeded, we know we'll be keeping all the - relocs. */ - if (h->dynindx != -1) - goto keep; - } + /* Make room for this entry. */ + s->size += PLT_ENTRY_SIZE (htab); - eh->dyn_relocs = NULL; + /* Make room for the .glink code. */ + s = htab->glink; + if (s->size == 0) + s->size += GLINK_CALL_STUB_SIZE; + if (htab->opd_abi) + { + /* We need bigger stubs past index 32767. */ + if (s->size >= GLINK_CALL_STUB_SIZE + 32768*2*4) + s->size += 4; + s->size += 2*4; + } + else + s->size += 4; - keep: ; + /* We also need to make an entry in the .rela.plt section. */ + s = htab->elf.srelplt; + } + s->size += sizeof (Elf64_External_Rela); + doneone = TRUE; + } + else + pent->plt.offset = (bfd_vma) -1; + if (!doneone) + { + h->plt.plist = NULL; + h->needs_plt = 0; + } } - - /* Finally, allocate space. */ - for (p = eh->dyn_relocs; p != NULL; p = p->next) + else { - asection *sreloc = elf_section_data (p->sec)->sreloc; - if (eh->elf.type == STT_GNU_IFUNC) - sreloc = htab->elf.irelplt; - sreloc->size += p->count * sizeof (Elf64_External_Rela); + h->plt.plist = NULL; + h->needs_plt = 0; } return TRUE; @@ -13934,6 +13920,7 @@ ppc64_elf_relocate_section (bfd *output_bfd, if (!bfd_link_pic (info) && !info->traditional_format && !htab->opd_abi + && rel->r_addend == d_offset && h != NULL && &h->elf == htab->elf.hgot && rel + 1 < relend && rel[1].r_info == ELF64_R_INFO (r_symndx, R_PPC64_REL16_LO) @@ -14485,30 +14472,43 @@ ppc64_elf_relocate_section (bfd *output_bfd, case R_PPC64_PLT64: /* Relocation is to the entry for this symbol in the procedure linkage table. */ + { + struct plt_entry **plt_list = NULL; + if (h != NULL) + plt_list = &h->elf.plt.plist; + else if (local_got_ents != NULL) + { + struct plt_entry **local_plt = (struct plt_entry **) + (local_got_ents + symtab_hdr->sh_info); + unsigned char *local_got_tls_masks = (unsigned char *) + (local_plt + symtab_hdr->sh_info); + if ((local_got_tls_masks[r_symndx] & PLT_IFUNC) != 0) + plt_list = local_plt + r_symndx; + } + if (plt_list) + { + struct plt_entry *ent; - /* Resolve a PLT reloc against a local symbol directly, - without using the procedure linkage table. */ - if (h == NULL) - break; - - /* It's possible that we didn't make a PLT entry for this - symbol. This happens when statically linking PIC code, - or when using -Bsymbolic. Go find a match if there is a - PLT entry. */ - if (htab->elf.splt != NULL) - { - struct plt_entry *ent; - for (ent = h->elf.plt.plist; ent != NULL; ent = ent->next) - if (ent->plt.offset != (bfd_vma) -1 - && ent->addend == orig_rel.r_addend) - { - relocation = (htab->elf.splt->output_section->vma - + htab->elf.splt->output_offset - + ent->plt.offset); - unresolved_reloc = FALSE; - break; - } - } + for (ent = *plt_list; ent != NULL; ent = ent->next) + if (ent->plt.offset != (bfd_vma) -1 + && ent->addend == orig_rel.r_addend) + { + asection *plt; + + plt = htab->elf.splt; + if (!htab->elf.dynamic_sections_created + || h == NULL + || h->elf.dynindx == -1) + plt = htab->elf.iplt; + relocation = (plt->output_section->vma + + plt->output_offset + + ent->plt.offset); + addend = 0; + unresolved_reloc = FALSE; + break; + } + } + } break; case R_PPC64_TOC: