X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=bfd%2Felf64-ppc.c;h=d6acc1f38026309e62bac872365fc89a0e522f5f;hb=83ae81cd0b2ec355aeb7666c0c059f00492635e8;hp=5ad5f48c0e2c90df678335b6f176db9c8cadd0de;hpb=7c9cf4158452094f4c463676e5122c5c4ce64de8;p=deliverable%2Fbinutils-gdb.git diff --git a/bfd/elf64-ppc.c b/bfd/elf64-ppc.c index 5ad5f48c0e..d6acc1f380 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. @@ -173,8 +173,12 @@ static bfd_vma opd_entry_value #define LD_R2_0R2 0xe8420000 /* ld %r2,xxx+0(%r2) */ #define LD_R2_0R1 0xe8410000 /* ld %r2,0(%r1) */ +#define LD_R2_0R12 0xe84c0000 /* ld %r2,0(%r12) */ +#define ADD_R2_R2_R12 0x7c426214 /* add %r2,%r2,%r12 */ -#define ADDIS_R12_R2 0x3d820000 /* addis %r12,%r2,xxx@ha */ +#define LIS_R2 0x3c400000 /* lis %r2,xxx@ha */ +#define ADDIS_R2_R12 0x3c4c0000 /* addis %r2,%r12,xxx@ha */ +#define ADDIS_R12_R2 0x3d820000 /* addis %r12,%r2,xxx@ha */ #define ADDIS_R12_R12 0x3d8c0000 /* addis %r12,%r12,xxx@ha */ #define LD_R12_0R12 0xe98c0000 /* ld %r12,xxx@l(%r12) */ @@ -683,7 +687,7 @@ static reloc_howto_type ppc64_elf_howto_raw[] = { TRUE, /* pc_relative */ 0, /* bitpos */ complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ + ppc64_elf_unhandled_reloc, /* special_function */ "R_PPC64_PLTREL32", /* name */ FALSE, /* partial_inplace */ 0, /* src_mask */ @@ -2022,6 +2026,21 @@ static reloc_howto_type ppc64_elf_howto_raw[] = { 0xffff, /* dst_mask */ TRUE), /* pcrel_offset */ + /* Like R_PPC64_REL16_HA but for split field in addpcis. */ + HOWTO (R_PPC64_REL16DX_HA, /* type */ + 16, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + TRUE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + ppc64_elf_ha_reloc, /* special_function */ + "R_PPC64_REL16DX_HA", /* name */ + FALSE, /* partial_inplace */ + 0, /* src_mask */ + 0x1fffc1, /* dst_mask */ + TRUE), /* pcrel_offset */ + /* Like R_PPC64_ADDR16_HI, but no overflow. */ HOWTO (R_PPC64_ADDR16_HIGH, /* type */ 16, /* rightshift */ @@ -2112,6 +2131,21 @@ static reloc_howto_type ppc64_elf_howto_raw[] = { 0xffff, /* dst_mask */ FALSE), /* pcrel_offset */ + /* Marker reloc on ELFv2 large-model function entry. */ + HOWTO (R_PPC64_ENTRY, + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 32, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_PPC64_ENTRY", /* name */ + FALSE, /* partial_inplace */ + 0, /* src_mask */ + 0, /* dst_mask */ + FALSE), /* pcrel_offset */ + /* Like ADDR64, but use local entry point of function. */ HOWTO (R_PPC64_ADDR64_LOCAL, /* type */ 0, /* rightshift */ @@ -2412,6 +2446,10 @@ ppc64_elf_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED, break; case BFD_RELOC_HI16_S_PCREL: r = R_PPC64_REL16_HA; break; + case BFD_RELOC_PPC_REL16DX_HA: r = R_PPC64_REL16DX_HA; + break; + case BFD_RELOC_PPC64_ENTRY: r = R_PPC64_ENTRY; + break; case BFD_RELOC_PPC64_ADDR64_LOCAL: r = R_PPC64_ADDR64_LOCAL; break; case BFD_RELOC_VTABLE_INHERIT: r = R_PPC64_GNU_VTINHERIT; @@ -2466,6 +2504,11 @@ ppc64_elf_ha_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol, void *data, asection *input_section, bfd *output_bfd, char **error_message) { + enum elf_ppc64_reloc_type r_type; + long insn; + bfd_size_type octets; + bfd_vma value; + /* If this is a relocatable link (output_bfd test tells us), just call the generic function. Any adjustment will be done at final link time. */ @@ -2477,7 +2520,29 @@ ppc64_elf_ha_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol, We won't actually be using the low 16 bits, so trashing them doesn't matter. */ reloc_entry->addend += 0x8000; - return bfd_reloc_continue; + r_type = reloc_entry->howto->type; + if (r_type != R_PPC64_REL16DX_HA) + return bfd_reloc_continue; + + value = 0; + if (!bfd_is_com_section (symbol->section)) + value = symbol->value; + value += (reloc_entry->addend + + symbol->section->output_offset + + symbol->section->output_section->vma); + value -= (reloc_entry->address + + input_section->output_offset + + input_section->output_section->vma); + value = (bfd_signed_vma) value >> 16; + + octets = reloc_entry->address * bfd_octets_per_byte (abfd); + insn = bfd_get_32 (abfd, (bfd_byte *) data + octets); + insn &= ~0x1fffc1; + insn |= (value & 0xffc1) | ((value & 0x3e) << 15); + bfd_put_32 (abfd, insn, (bfd_byte *) data + octets); + if (value + 0x8000 > 0xffff) + return bfd_reloc_overflow; + return bfd_reloc_ok; } static bfd_reloc_status_type @@ -2505,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; @@ -2822,12 +2888,15 @@ ppc64_elf_mkobject (bfd *abfd) } /* Fix bad default arch selected for a 64 bit input bfd when the - default is 32 bit. */ + default is 32 bit. Also select arch based on apuinfo. */ static bfd_boolean ppc64_elf_object_p (bfd *abfd) { - if (abfd->arch_info->the_default && abfd->arch_info->bits_per_word == 32) + if (!abfd->arch_info->the_default) + return TRUE; + + if (abfd->arch_info->bits_per_word == 32) { Elf_Internal_Ehdr *i_ehdr = elf_elfheader (abfd); @@ -2838,7 +2907,7 @@ ppc64_elf_object_p (bfd *abfd) BFD_ASSERT (abfd->arch_info->bits_per_word == 64); } } - return TRUE; + return _bfd_elf_ppc_set_arch (abfd); } /* Support for core dump NOTE sections. */ @@ -3016,6 +3085,7 @@ get_opd_info (asection * sec) /* Parameters for the qsort hook. */ static bfd_boolean synthetic_relocatable; +static asection *synthetic_opd; /* qsort comparison function for ppc64_elf_get_synthetic_symtab. */ @@ -3032,12 +3102,15 @@ compare_symbols (const void *ap, const void *bp) return 1; /* then .opd symbols. */ - if (strcmp (a->section->name, ".opd") == 0 - && strcmp (b->section->name, ".opd") != 0) - return -1; - if (strcmp (a->section->name, ".opd") != 0 - && strcmp (b->section->name, ".opd") == 0) - return 1; + if (synthetic_opd != NULL) + { + if (strcmp (a->section->name, ".opd") == 0 + && strcmp (b->section->name, ".opd") != 0) + return -1; + if (strcmp (a->section->name, ".opd") != 0 + && strcmp (b->section->name, ".opd") == 0) + return 1; + } /* then other code symbols. */ if ((a->section->flags & (SEC_CODE | SEC_ALLOC | SEC_THREAD_LOCAL)) @@ -3196,6 +3269,7 @@ ppc64_elf_get_synthetic_symtab (bfd *abfd, memcpy (syms, static_syms, (symcount + 1) * sizeof (*syms)); synthetic_relocatable = relocatable; + synthetic_opd = opd; qsort (syms, symcount, sizeof (*syms), compare_symbols); if (!relocatable && symcount > 1) @@ -3212,7 +3286,11 @@ ppc64_elf_get_synthetic_symtab (bfd *abfd, } i = 0; - if (strcmp (syms[i]->section->name, ".opd") == 0) + /* Note that here and in compare_symbols we can't compare opd and + sym->section directly. With separate debug info files, the + symbols will be extracted from the debug file while abfd passed + to this function is the real binary. */ + if (opd != NULL && strcmp (syms[i]->section->name, ".opd") == 0) ++i; codesecsym = i; @@ -3228,9 +3306,10 @@ ppc64_elf_get_synthetic_symtab (bfd *abfd, break; secsymend = i; - for (; i < symcount; ++i) - if (strcmp (syms[i]->section->name, ".opd") != 0) - break; + if (opd != NULL) + for (; i < symcount; ++i) + if (strcmp (syms[i]->section->name, ".opd") != 0) + break; opdsymend = i; for (; i < symcount; ++i) @@ -3881,6 +3960,9 @@ struct ppc_link_hash_entry /* Track dynamic relocs copied for this symbol. */ struct elf_dyn_relocs *dyn_relocs; + /* Chain of aliases referring to a weakdef. */ + struct ppc_link_hash_entry *weakref; + /* Link between function code and descriptor symbols. */ struct ppc_link_hash_entry *oh; @@ -4279,14 +4361,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", @@ -4359,14 +4447,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); } @@ -4435,6 +4518,8 @@ ppc_get_stub_entry (const asection *input_section, more than one stub used to reach say, printf, and we need to distinguish between them. */ group = htab->sec_info[input_section->id].u.group; + if (group == NULL) + return NULL; if (h != NULL && h->u.stub_cache != NULL && h->u.stub_cache->h == h @@ -4666,6 +4751,45 @@ ppc64_elf_copy_indirect_symbol (struct bfd_link_info *info, edir->elf.needs_plt |= eind->elf.needs_plt; edir->elf.pointer_equality_needed |= eind->elf.pointer_equality_needed; + /* If we were called to copy over info for a weak sym, don't copy + dyn_relocs, plt/got info, or dynindx. We used to copy dyn_relocs + in order to simplify readonly_dynrelocs and save a field in the + symbol hash entry, but that means dyn_relocs can't be used in any + tests about a specific symbol, or affect other symbol flags which + are then tested. + Chain weakdefs so we can get from the weakdef back to an alias. + The list is circular so that we don't need to use u.weakdef as + well as this list to look at all aliases. */ + if (eind->elf.root.type != bfd_link_hash_indirect) + { + struct ppc_link_hash_entry *cur, *add, *next; + + add = eind; + do + { + cur = edir->weakref; + if (cur != NULL) + { + do + { + /* We can be called twice for the same symbols. + Don't make multiple loops. */ + if (cur == add) + return; + cur = cur->weakref; + } while (cur != edir); + } + next = add->weakref; + if (cur != add) + { + add->weakref = edir->weakref != NULL ? edir->weakref : edir; + edir->weakref = add; + } + add = next; + } while (add != NULL && add != eind); + return; + } + /* Copy over any dynamic relocs we may have on the indirect sym. */ if (eind->dyn_relocs != NULL) { @@ -4698,16 +4822,6 @@ ppc64_elf_copy_indirect_symbol (struct bfd_link_info *info, eind->dyn_relocs = NULL; } - /* If we were called to copy over info for a weak sym, that's all. - You might think dyn_relocs need not be copied over; After all, - both syms will be dynamic or both non-dynamic so we're just - moving reloc accounting around. However, ELIMINATE_COPY_RELOCS - code in ppc64_elf_adjust_dynamic_symbol needs to check for - dyn_relocs in read-only sections, and it does so on what is the - DIR sym here. */ - if (eind->elf.root.type != bfd_link_hash_indirect) - return; - /* Copy over got entries that we may have already seen to the symbol which just became indirect. */ if (eind->elf.got.glist != NULL) @@ -4828,11 +4942,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) @@ -5010,7 +5123,7 @@ ppc64_elf_before_check_relocs (bfd *ibfd, struct bfd_link_info *info) { if (abiversion (ibfd) == 0) set_abiversion (ibfd, 1); - else if (abiversion (ibfd) == 2) + else if (abiversion (ibfd) >= 2) { info->callbacks->einfo (_("%P: %B .opd not allowed in ABI" " version %d\n"), @@ -5084,7 +5197,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); @@ -5275,7 +5388,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) @@ -5318,28 +5431,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: @@ -5451,27 +5544,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 @@ -5502,6 +5597,7 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, case R_PPC64_REL16_LO: case R_PPC64_REL16_HI: case R_PPC64_REL16_HA: + case R_PPC64_REL16DX_HA: break; /* Not supported as a dynamic relocation. */ @@ -5530,6 +5626,10 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, sec->has_toc_reloc = 1; break; + /* Marker reloc. */ + case R_PPC64_ENTRY: + break; + /* This relocation describes the C++ object vtable hierarchy. Reconstruct it for later use during GC. */ case R_PPC64_GNU_VTINHERIT: @@ -5579,21 +5679,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)) @@ -5736,10 +5858,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: @@ -5912,6 +6030,8 @@ ppc64_elf_merge_private_bfd_data (bfd *ibfd, bfd *obfd) return FALSE; } + _bfd_elf_ppc_merge_fp_attributes (ibfd, obfd); + /* Merge Tag_compatibility attributes and any common GNU ones. */ _bfd_elf_merge_object_attributes (ibfd, obfd); @@ -6435,6 +6555,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); @@ -6458,38 +6579,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: @@ -6556,11 +6645,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) @@ -6614,7 +6715,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 @@ -6655,6 +6756,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) @@ -6999,14 +7101,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. @@ -7025,26 +7141,13 @@ 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; } -/* Return true if we have dynamic relocs that apply to read-only sections. */ +/* Return true if we have dynamic relocs against H that apply to + read-only sections. */ static bfd_boolean readonly_dynrelocs (struct elf_link_hash_entry *h) @@ -7063,6 +7166,58 @@ readonly_dynrelocs (struct elf_link_hash_entry *h) return FALSE; } +/* Return true if we have dynamic relocs against H or any of its weak + aliases, that apply to read-only sections. */ + +static bfd_boolean +alias_readonly_dynrelocs (struct elf_link_hash_entry *h) +{ + struct ppc_link_hash_entry *eh; + + eh = (struct ppc_link_hash_entry *) h; + do + { + if (readonly_dynrelocs (&eh->elf)) + return TRUE; + eh = eh->weakref; + } while (eh != NULL && &eh->elf != h); + + return FALSE; +} + +/* Return whether EH has pc-relative dynamic relocs. */ + +static bfd_boolean +pc_dynrelocs (struct ppc_link_hash_entry *eh) +{ + struct elf_dyn_relocs *p; + + for (p = eh->dyn_relocs; p != NULL; p = p->next) + if (p->pc_count != 0) + return TRUE; + return FALSE; +} + +/* Return true if a global entry stub will be created for H. Valid + for ELFv2 before plt entries have been allocated. */ + +static bfd_boolean +global_entry_stub (struct elf_link_hash_entry *h) +{ + struct plt_entry *pent; + + if (!h->pointer_equality_needed + || h->def_regular) + return FALSE; + + for (pent = h->plt.plist; pent != NULL; pent = pent->next) + if (pent->plt.refcount > 0 + && pent->addend == 0) + return TRUE; + + return FALSE; +} + /* Adjust a symbol defined by a dynamic object and referenced by a regular object. The current definition is in some section of the dynamic object, but we're not including those sections. We have to @@ -7102,35 +7257,25 @@ ppc64_elf_adjust_dynamic_symbol (struct bfd_link_info *info, h->needs_plt = 0; h->pointer_equality_needed = 0; } - else if (abiversion (info->output_bfd) == 2) + else if (abiversion (info->output_bfd) >= 2) { /* Taking a function's address in a read/write section doesn't require us to define the function symbol in the executable on a global entry stub. A dynamic reloc can - be used instead. */ - if (h->pointer_equality_needed - && h->type != STT_GNU_IFUNC - && !readonly_dynrelocs (h)) + be used instead. The reason we prefer a few more dynamic + relocs is that calling via a global entry stub costs a + few more instructions, and pointer_equality_needed causes + extra work in ld.so when resolving these symbols. */ + if (global_entry_stub (h) + && !alias_readonly_dynrelocs (h)) { h->pointer_equality_needed = 0; + /* After adjust_dynamic_symbol, non_got_ref set in + the non-pic case means that dyn_relocs for this + symbol should be discarded. */ h->non_got_ref = 0; } - /* After adjust_dynamic_symbol, non_got_ref set in the - non-shared case means that we have allocated space in - .dynbss for the symbol and thus dyn_relocs for this - symbol should be discarded. - If we get here we know we are making a PLT entry for this - symbol, and in an executable we'd normally resolve - relocations against this symbol to the PLT entry. Allow - dynamic relocs if the reference is weak, and the dynamic - relocs will not cause text relocation. */ - else if (!h->ref_regular_nonweak - && h->non_got_ref - && h->type != STT_GNU_IFUNC - && !readonly_dynrelocs (h)) - h->non_got_ref = 0; - /* If making a plt entry, then we don't need copy relocs. */ return TRUE; } @@ -7165,29 +7310,20 @@ ppc64_elf_adjust_dynamic_symbol (struct bfd_link_info *info, return TRUE; /* Don't generate a copy reloc for symbols defined in the executable. */ - if (!h->def_dynamic || !h->ref_regular || h->def_regular) - return TRUE; + if (!h->def_dynamic || !h->ref_regular || h->def_regular - /* If -z nocopyreloc was given, don't generate them either. */ - if (info->nocopyreloc) - { - h->non_got_ref = 0; - return TRUE; - } + /* If -z nocopyreloc was given, don't generate them either. */ + || info->nocopyreloc - /* If we didn't find any dynamic relocs in read-only sections, then - we'll be keeping the dynamic relocs and avoiding the copy reloc. */ - if (ELIMINATE_COPY_RELOCS && !readonly_dynrelocs (h)) - { - h->non_got_ref = 0; - return TRUE; - } + /* If we didn't find any dynamic relocs in read-only sections, then + we'll be keeping the dynamic relocs and avoiding the copy reloc. */ + || (ELIMINATE_COPY_RELOCS && !alias_readonly_dynrelocs (h)) - /* Protected variables do not work with .dynbss. The copy in - .dynbss won't be used by the shared library with the protected - definition for the variable. Text relocations are preferable - to an incorrect program. */ - if (h->protected_def) + /* Protected variables do not work with .dynbss. The copy in + .dynbss won't be used by the shared library with the protected + definition for the variable. Text relocations are preferable + to an incorrect program. */ + || h->protected_def) { h->non_got_ref = 0; return TRUE; @@ -8173,6 +8309,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. */ @@ -8189,6 +8326,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; @@ -8346,7 +8484,8 @@ ppc64_elf_tls_optimize (struct bfd_link_info *info) if (h != NULL && h->root.type == bfd_link_hash_undefweak) ok_tprel = TRUE; - else + else if (sym_sec != NULL + && sym_sec->output_section != NULL) { value += sym_sec->output_offset; value += sym_sec->output_section->vma; @@ -8907,6 +9046,7 @@ ppc64_elf_edit_toc (struct bfd_link_info *info) goto error_ret; if (sym_sec == NULL + || sym_sec->output_section == NULL || discarded_section (sym_sec)) continue; @@ -9485,7 +9625,6 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf) struct ppc_link_hash_table *htab; asection *s; struct ppc_link_hash_entry *eh; - struct elf_dyn_relocs *p; struct got_entry **pgent, *gent; if (h->root.type == bfd_link_hash_indirect) @@ -9496,71 +9635,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. */ @@ -9630,99 +9704,178 @@ 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 (!htab->elf.dynamic_sections_created + && h->type != STT_GNU_IFUNC) + eh->dyn_relocs = NULL; - if (bfd_link_pic (info)) + if (eh->dyn_relocs != NULL) { - /* 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 *p, **pp; + + /* 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)) + { + 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; + } + } - for (pp = &eh->dyn_relocs; (p = *pp) != NULL; ) + /* 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) - eh->dyn_relocs = NULL; + /* A plt entry is always created when making direct calls to + an ifunc, even when building a static executable, but + that doesn't cover all cases. We may have only an ifunc + initialised function pointer for a given ifunc symbol. - /* 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) + For ELFv2, dynamic relocations are not required when + generating a global entry PLT stub. */ + if (abiversion (info->output_bfd) >= 2) { - if (! bfd_elf_link_record_dynamic_symbol (info, h)) - return FALSE; + if (global_entry_stub (h)) + eh->dyn_relocs = NULL; } - } - } - else if (h->type == STT_GNU_IFUNC) - { - 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. */ - if (!h->non_got_ref - && !h->def_regular) + /* For ELFv1 we have function descriptors. Descriptors need + to be treated like PLT entries and thus have dynamic + relocations. One exception is when the function + descriptor is copied into .dynbss (which should only + happen with ancient versions of gcc). */ + else if (h->needs_copy) + eh->dyn_relocs = NULL; + } + else if (ELIMINATE_COPY_RELOCS) { - /* Make sure this symbol is output as a dynamic symbol. + /* For the non-pic case, discard space for relocs against + symbols which turn out to need copy relocs or are not + dynamic. */ + + /* First 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 (h->root.type == bfd_link_hash_undefweak + && !h->non_got_ref + && !h->def_regular + && h->dynindx == -1 + && !h->forced_local + && !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; + if (h->non_got_ref + || h->def_regular + || h->dynindx == -1) + eh->dyn_relocs = NULL; } - 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); + } } - /* Finally, allocate space. */ - for (p = eh->dyn_relocs; p != NULL; p = p->next) + 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 { - 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; @@ -9764,6 +9917,7 @@ size_global_entry_stubs (struct elf_link_hash_entry *h, void *inf) need to define the symbol in the executable on a call stub. This is to avoid text relocations. */ s->size = (s->size + 15) & -16; + h->root.type = bfd_link_hash_defined; h->root.u.def.section = s; h->root.u.def.value = s->size; s->size += 16; @@ -9815,7 +9969,7 @@ ppc64_elf_size_dynamic_sections (bfd *output_bfd, if (htab->elf.dynamic_sections_created) { /* Set the contents of the .interp section to the interpreter. */ - if (bfd_link_executable (info)) + if (bfd_link_executable (info) && !info->nointerp) { s = bfd_get_linker_section (dynobj, ".interp"); if (s == NULL) @@ -11907,7 +12061,6 @@ group_sections (struct bfd_link_info *info, { struct ppc_link_hash_table *htab; asection *osec; - bfd_size_type stub14_group_size; bfd_boolean suppress_size_errors; htab = ppc_hash_table (info); @@ -11915,20 +12068,13 @@ group_sections (struct bfd_link_info *info, return FALSE; suppress_size_errors = FALSE; - stub14_group_size = stub_group_size >> 10; if (stub_group_size == 1) { /* Default values. */ if (stubs_always_before_branch) - { - stub_group_size = 0x1e00000; - stub14_group_size = 0x7800; - } + stub_group_size = 0x1e00000; else - { - stub_group_size = 0x1c00000; - stub14_group_size = 0x7000; - } + stub_group_size = 0x1c00000; suppress_size_errors = TRUE; } @@ -11948,12 +12094,15 @@ group_sections (struct bfd_link_info *info, bfd_boolean big_sec; bfd_vma curr_toc; struct map_stub *group; + bfd_size_type group_size; curr = tail; total = tail->size; - big_sec = total > (ppc64_elf_section_data (tail) != NULL - && ppc64_elf_section_data (tail)->has_14bit_branch - ? stub14_group_size : stub_group_size); + group_size = (ppc64_elf_section_data (tail) != NULL + && ppc64_elf_section_data (tail)->has_14bit_branch + ? stub_group_size >> 10 : stub_group_size); + + big_sec = total > group_size; if (big_sec && !suppress_size_errors) (*_bfd_error_handler) (_("%B section %A exceeds stub group size"), tail->owner, tail); @@ -11963,20 +12112,20 @@ group_sections (struct bfd_link_info *info, && ((total += curr->output_offset - prev->output_offset) < (ppc64_elf_section_data (prev) != NULL && ppc64_elf_section_data (prev)->has_14bit_branch - ? stub14_group_size : stub_group_size)) + ? (group_size = stub_group_size >> 10) : group_size)) && htab->sec_info[prev->id].toc_off == curr_toc) curr = prev; /* OK, the size from the start of CURR to the end is less - than stub_group_size and thus can be handled by one stub + than group_size and thus can be handled by one stub section. (or the tail section is itself larger than - stub_group_size, in which case we may be toast.) We - should really be keeping track of the total size of stubs - added here, as stubs contribute to the final output - section size. That's a little tricky, and this way will - only break if stubs added make the total size more than - 2^25, ie. for the default stub_group_size, if stubs total - more than 2097152 bytes, or nearly 75000 plt call stubs. */ + group_size, in which case we may be toast.) We should + really be keeping track of the total size of stubs added + here, as stubs contribute to the final output section + size. That's a little tricky, and this way will only + break if stubs added make the total size more than 2^25, + ie. for the default stub_group_size, if stubs total more + than 2097152 bytes, or nearly 75000 plt call stubs. */ group = bfd_alloc (curr->owner, sizeof (*group)); if (group == NULL) return FALSE; @@ -11993,7 +12142,7 @@ group_sections (struct bfd_link_info *info, } while (tail != curr && (tail = prev) != NULL); - /* But wait, there's more! Input sections up to stub_group_size + /* But wait, there's more! Input sections up to group_size bytes before the stub section can be handled by it too. Don't do this if we have a really large section after the stubs, as adding more stubs increases the chance that @@ -12005,7 +12154,7 @@ group_sections (struct bfd_link_info *info, && ((total += tail->output_offset - prev->output_offset) < (ppc64_elf_section_data (prev) != NULL && ppc64_elf_section_data (prev)->has_14bit_branch - ? stub14_group_size : stub_group_size)) + ? (group_size = stub_group_size >> 10) : group_size)) && htab->sec_info[prev->id].toc_off == curr_toc) { tail = prev; @@ -12124,6 +12273,13 @@ ppc64_elf_size_stubs (struct bfd_link_info *info) if (!group_sections (info, stub_group_size, stubs_always_before_branch)) return FALSE; +#define STUB_SHRINK_ITER 20 + /* Loop until no stubs added. After iteration 20 of this loop we may + exit on a stub section shrinking. This is to break out of a + pathological case where adding stubs on one iteration decreases + section gaps (perhaps due to alignment), which then requires + fewer or smaller stubs on the next iteration. */ + while (1) { bfd *input_bfd; @@ -12230,7 +12386,9 @@ ppc64_elf_size_stubs (struct bfd_link_info *info) if (hash == NULL) { sym_value = sym->st_value; - ok_dest = TRUE; + if (sym_sec != NULL + && sym_sec->output_section != NULL) + ok_dest = TRUE; } else if (hash->elf.root.type == bfd_link_hash_defined || hash->elf.root.type == bfd_link_hash_defweak) @@ -12497,17 +12655,17 @@ ppc64_elf_size_stubs (struct bfd_link_info *info) if ((stub_sec->flags & SEC_LINKER_CREATED) == 0) stub_sec->size = ((stub_sec->size + (1 << htab->params->plt_stub_align) - 1) - & (-1 << htab->params->plt_stub_align)); + & -(1 << htab->params->plt_stub_align)); for (stub_sec = htab->params->stub_bfd->sections; stub_sec != NULL; stub_sec = stub_sec->next) if ((stub_sec->flags & SEC_LINKER_CREATED) == 0 - && stub_sec->rawsize != stub_sec->size) + && stub_sec->rawsize != stub_sec->size + && (htab->stub_iteration <= STUB_SHRINK_ITER + || stub_sec->rawsize < stub_sec->size)) break; - /* Exit from this loop when no stubs have been added, and no stubs - have changed size. */ if (stub_sec == NULL && (htab->glink_eh_frame == NULL || htab->glink_eh_frame->rawsize == htab->glink_eh_frame->size)) @@ -12583,7 +12741,7 @@ ppc64_elf_size_stubs (struct bfd_link_info *info) *p++ = DW_CFA_advance_loc + 1; *p++ = DW_CFA_register; *p++ = 65; - *p++ = 12; + *p++ = htab->opd_abi ? 12 : 0; *p++ = DW_CFA_advance_loc + 4; *p++ = DW_CFA_restore_extended; *p++ = 65; @@ -12838,9 +12996,6 @@ ppc64_elf_build_stubs (struct bfd_link_info *info, stub_sec->contents = bfd_zalloc (htab->params->stub_bfd, stub_sec->size); if (stub_sec->contents == NULL) return FALSE; - /* We want to check that built size is the same as calculated - size. rawsize is a convenient location to use. */ - stub_sec->rawsize = stub_sec->size; stub_sec->size = 0; } @@ -13021,7 +13176,7 @@ ppc64_elf_build_stubs (struct bfd_link_info *info, if ((stub_sec->flags & SEC_LINKER_CREATED) == 0) stub_sec->size = ((stub_sec->size + (1 << htab->params->plt_stub_align) - 1) - & (-1 << htab->params->plt_stub_align)); + & -(1 << htab->params->plt_stub_align)); for (stub_sec = htab->params->stub_bfd->sections; stub_sec != NULL; @@ -13029,7 +13184,9 @@ ppc64_elf_build_stubs (struct bfd_link_info *info, if ((stub_sec->flags & SEC_LINKER_CREATED) == 0) { stub_sec_count += 1; - if (stub_sec->rawsize != stub_sec->size) + if (stub_sec->rawsize != stub_sec->size + && (htab->stub_iteration <= STUB_SHRINK_ITER + || stub_sec->rawsize < stub_sec->size)) break; } @@ -13162,6 +13319,7 @@ ppc64_elf_relocate_section (bfd *output_bfd, Elf_Internal_Shdr *symtab_hdr; struct elf_link_hash_entry **sym_hashes; Elf_Internal_Rela *rel; + Elf_Internal_Rela *wrel; Elf_Internal_Rela *relend; Elf_Internal_Rela outrel; bfd_byte *loc; @@ -13193,9 +13351,9 @@ ppc64_elf_relocate_section (bfd *output_bfd, sym_hashes = elf_sym_hashes (input_bfd); is_opd = ppc64_elf_section_data (input_section)->sec_type == sec_opd; - rel = relocs; + rel = wrel = relocs; relend = relocs + input_section->reloc_count; - for (; rel < relend; rel++) + for (; rel < relend; wrel++, rel++) { enum elf_ppc64_reloc_type r_type; bfd_vma addend; @@ -13219,10 +13377,13 @@ ppc64_elf_relocate_section (bfd *output_bfd, struct ppc_stub_hash_entry *stub_entry; bfd_vma max_br_offset; bfd_vma from; - const Elf_Internal_Rela orig_rel = *rel; + Elf_Internal_Rela orig_rel; reloc_howto_type *howto; struct reloc_howto_struct alt_howto; + again: + orig_rel = *rel; + r_type = ELF64_R_TYPE (rel->r_info); r_symndx = ELF64_R_SYM (rel->r_info); @@ -13230,10 +13391,10 @@ ppc64_elf_relocate_section (bfd *output_bfd, symbol of the previous ADDR64 reloc. The symbol gives us the proper TOC base to use. */ if (rel->r_info == ELF64_R_INFO (0, R_PPC64_TOC) - && rel != relocs - && ELF64_R_TYPE (rel[-1].r_info) == R_PPC64_ADDR64 + && wrel != relocs + && ELF64_R_TYPE (wrel[-1].r_info) == R_PPC64_ADDR64 && is_opd) - r_symndx = ELF64_R_SYM (rel[-1].r_info); + r_symndx = ELF64_R_SYM (wrel[-1].r_info); sym = NULL; sec = NULL; @@ -13314,13 +13475,27 @@ ppc64_elf_relocate_section (bfd *output_bfd, h = (struct ppc_link_hash_entry *) h_elf; if (sec != NULL && discarded_section (sec)) - RELOC_AGAINST_DISCARDED_SECTION (info, input_bfd, input_section, - rel, 1, relend, - ppc64_elf_howto_table[r_type], 0, - contents); + { + _bfd_clear_contents (ppc64_elf_howto_table[r_type], + input_bfd, input_section, + contents + rel->r_offset); + wrel->r_offset = rel->r_offset; + wrel->r_info = 0; + wrel->r_addend = 0; + + /* For ld -r, remove relocations in debug sections against + sections defined in discarded sections. Not done for + non-debug to preserve relocs in .eh_frame which the + eh_frame editing code expects to be present. */ + if (bfd_link_relocatable (info) + && (input_section->flags & SEC_DEBUGGING)) + wrel--; + + continue; + } if (bfd_link_relocatable (info)) - continue; + goto copy_reloc; if (h != NULL && &h->elf == htab->elf.hgot) { @@ -13480,10 +13655,12 @@ ppc64_elf_relocate_section (bfd *output_bfd, && (tls_mask & TLS_TPREL) == 0) { toctprel: - insn = bfd_get_32 (output_bfd, contents + rel->r_offset - d_offset); + insn = bfd_get_32 (output_bfd, + contents + rel->r_offset - d_offset); insn &= 31 << 21; insn |= 0x3c0d0000; /* addis 0,13,0 */ - bfd_put_32 (output_bfd, insn, contents + rel->r_offset - d_offset); + bfd_put_32 (output_bfd, insn, + contents + rel->r_offset - d_offset); r_type = R_PPC64_TPREL16_HA; if (toc_symndx != 0) { @@ -13491,8 +13668,7 @@ ppc64_elf_relocate_section (bfd *output_bfd, rel->r_addend = toc_addend; /* We changed the symbol. Start over in order to get h, sym, sec etc. right. */ - rel--; - continue; + goto again; } else rel->r_info = ELF64_R_INFO (r_symndx, r_type); @@ -13518,8 +13694,7 @@ ppc64_elf_relocate_section (bfd *output_bfd, rel->r_addend = toc_addend; /* We changed the symbol. Start over in order to get h, sym, sec etc. right. */ - rel--; - continue; + goto again; } else rel->r_info = ELF64_R_INFO (r_symndx, r_type); @@ -13658,8 +13833,7 @@ ppc64_elf_relocate_section (bfd *output_bfd, { /* We changed the symbol. Start over in order to get h, sym, sec etc. right. */ - rel--; - continue; + goto again; } } break; @@ -13703,10 +13877,7 @@ ppc64_elf_relocate_section (bfd *output_bfd, } bfd_put_32 (output_bfd, insn2, contents + offset); if ((tls_mask & TLS_TPRELGD) == 0 && toc_symndx != 0) - { - rel--; - continue; - } + goto again; } break; @@ -13748,8 +13919,7 @@ ppc64_elf_relocate_section (bfd *output_bfd, insn2 = NOP; } bfd_put_32 (output_bfd, insn2, contents + offset); - rel--; - continue; + goto again; } break; @@ -13790,6 +13960,52 @@ ppc64_elf_relocate_section (bfd *output_bfd, } break; + case R_PPC64_ENTRY: + relocation = TOCstart + htab->sec_info[input_section->id].toc_off; + if (!bfd_link_pic (info) + && !info->traditional_format + && relocation + 0x80008000 <= 0xffffffff) + { + unsigned int insn1, insn2; + + insn1 = bfd_get_32 (input_bfd, contents + rel->r_offset); + insn2 = bfd_get_32 (input_bfd, contents + rel->r_offset + 4); + if ((insn1 & ~0xfffc) == LD_R2_0R12 + && insn2 == ADD_R2_R2_R12) + { + bfd_put_32 (output_bfd, + LIS_R2 + PPC_HA (relocation), + contents + rel->r_offset); + bfd_put_32 (output_bfd, + ADDI_R2_R2 + PPC_LO (relocation), + contents + rel->r_offset + 4); + } + } + else + { + relocation -= (rel->r_offset + + input_section->output_offset + + input_section->output_section->vma); + if (relocation + 0x80008000 <= 0xffffffff) + { + unsigned int insn1, insn2; + + insn1 = bfd_get_32 (input_bfd, contents + rel->r_offset); + insn2 = bfd_get_32 (input_bfd, contents + rel->r_offset + 4); + if ((insn1 & ~0xfffc) == LD_R2_0R12 + && insn2 == ADD_R2_R2_R12) + { + bfd_put_32 (output_bfd, + ADDIS_R2_R12 + PPC_HA (relocation), + contents + rel->r_offset); + bfd_put_32 (output_bfd, + ADDI_R2_R2 + PPC_LO (relocation), + contents + rel->r_offset + 4); + } + } + } + break; + case R_PPC64_REL16_HA: /* If we are generating a non-PIC executable, edit . 0: addis 2,12,.TOC.-0b@ha @@ -13800,6 +14016,8 @@ ppc64_elf_relocate_section (bfd *output_bfd, if .TOC. is in range. */ 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) @@ -13811,15 +14029,15 @@ ppc64_elf_relocate_section (bfd *output_bfd, bfd_vma offset = rel->r_offset - d_offset; insn1 = bfd_get_32 (output_bfd, contents + offset); insn2 = bfd_get_32 (output_bfd, contents + offset + 4); - if ((insn1 & 0xffff0000) == 0x3c4c0000 /* addis 2,12 */ - && (insn2 & 0xffff0000) == 0x38420000 /* addi 2,2 */) + if ((insn1 & 0xffff0000) == ADDIS_R2_R12 + && (insn2 & 0xffff0000) == ADDI_R2_R2) { r_type = R_PPC64_ADDR16_HA; rel->r_info = ELF64_R_INFO (r_symndx, r_type); rel->r_addend -= d_offset; rel[1].r_info = ELF64_R_INFO (r_symndx, R_PPC64_ADDR16_LO); rel[1].r_addend -= d_offset + 4; - bfd_put_32 (output_bfd, 0x3c400000, contents + offset); + bfd_put_32 (output_bfd, LIS_R2, contents + offset); } } break; @@ -14091,7 +14309,7 @@ ppc64_elf_relocate_section (bfd *output_bfd, && addend == 0) { bfd_put_32 (output_bfd, NOP, contents + rel->r_offset); - continue; + goto copy_reloc; } break; } @@ -14107,7 +14325,7 @@ ppc64_elf_relocate_section (bfd *output_bfd, bfd_set_error (bfd_error_bad_value); ret = FALSE; - continue; + goto copy_reloc; case R_PPC64_NONE: case R_PPC64_TLS: @@ -14116,7 +14334,8 @@ ppc64_elf_relocate_section (bfd *output_bfd, case R_PPC64_TOCSAVE: case R_PPC64_GNU_VTINHERIT: case R_PPC64_GNU_VTENTRY: - continue; + case R_PPC64_ENTRY: + goto copy_reloc; /* GOT16 relocations. Like an ADDR16 using the symbol's address in the GOT as relocation value instead of the @@ -14350,30 +14569,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: @@ -14417,6 +14649,7 @@ ppc64_elf_relocate_section (bfd *output_bfd, case R_PPC64_REL16_LO: case R_PPC64_REL16_HI: case R_PPC64_REL16_HA: + case R_PPC64_REL16DX_HA: break; case R_PPC64_REL14: @@ -14532,22 +14765,12 @@ ppc64_elf_relocate_section (bfd *output_bfd, if (NO_OPD_RELOCS && is_opd) break; - if ((bfd_link_pic (info) - && (h == NULL - || ELF_ST_VISIBILITY (h->elf.other) == STV_DEFAULT - || h->elf.root.type != bfd_link_hash_undefweak) - && (must_be_dyn_reloc (info, r_type) - || !SYMBOL_CALLS_LOCAL (info, &h->elf))) - || (ELIMINATE_COPY_RELOCS - && !bfd_link_pic (info) - && h != NULL - && h->elf.dynindx != -1 - && !h->elf.non_got_ref - && !h->elf.def_regular) - || (!bfd_link_pic (info) - && (h != NULL - ? h->elf.type == STT_GNU_IFUNC - : ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC))) + if (bfd_link_pic (info) + ? ((h != NULL && pc_dynrelocs (h)) + || must_be_dyn_reloc (info, r_type)) + : (h != NULL + ? h->dyn_relocs != NULL + : ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC)) { bfd_boolean skip, relocate; asection *sreloc; @@ -14752,7 +14975,7 @@ ppc64_elf_relocate_section (bfd *output_bfd, bfd_set_error (bfd_error_invalid_operation); ret = FALSE; - continue; + goto copy_reloc; } /* Multi-instruction sequences that access the TOC can be @@ -14829,6 +15052,7 @@ ppc64_elf_relocate_section (bfd *output_bfd, break; case R_PPC64_REL16_HA: + case R_PPC64_REL16DX_HA: case R_PPC64_ADDR16_HA: case R_PPC64_ADDR16_HIGHA: case R_PPC64_ADDR16_HIGHERA: @@ -14884,16 +15108,20 @@ ppc64_elf_relocate_section (bfd *output_bfd, case R_PPC64_DTPREL16_LO_DS: insn = bfd_get_32 (input_bfd, contents + (rel->r_offset & ~3)); mask = 3; - /* If this reloc is against an lq insn, then the value must be - a multiple of 16. This is somewhat of a hack, but the - "correct" way to do this by defining _DQ forms of all the - _DS relocs bloats all reloc switches in this file. It - doesn't seem to make much sense to use any of these relocs - in data, so testing the insn should be safe. */ - if ((insn & (0x3f << 26)) == (56u << 26)) + /* If this reloc is against an lq, lxv, or stxv insn, then + the value must be a multiple of 16. This is somewhat of + a hack, but the "correct" way to do this by defining _DQ + forms of all the _DS relocs bloats all reloc switches in + this file. It doesn't make much sense to use these + relocs in data, so testing the insn should be safe. */ + if ((insn & (0x3f << 26)) == (56u << 26) + || ((insn & (0x3f << 26)) == (61u << 26) && (insn & 3) == 1)) mask = 15; - if (((relocation + addend) & mask) != 0) + relocation += addend; + addend = insn & (mask ^ 3); + if ((relocation & mask) != 0) { + relocation ^= relocation & mask; info->callbacks->einfo (_("%P: %H: error: %s not a multiple of %u\n"), input_bfd, input_section, rel->r_offset, @@ -14901,7 +15129,7 @@ ppc64_elf_relocate_section (bfd *output_bfd, mask + 1); bfd_set_error (bfd_error_bad_value); ret = FALSE; - continue; + goto copy_reloc; } break; } @@ -14951,8 +15179,30 @@ ppc64_elf_relocate_section (bfd *output_bfd, } } - r = _bfd_final_link_relocate (howto, input_bfd, input_section, contents, - rel->r_offset, relocation, addend); + if (r_type == R_PPC64_REL16DX_HA) + { + /* Split field reloc isn't handled by _bfd_final_link_relocate. */ + if (rel->r_offset + 4 > input_section->size) + r = bfd_reloc_outofrange; + else + { + relocation += addend; + relocation -= (rel->r_offset + + input_section->output_offset + + input_section->output_section->vma); + relocation = (bfd_signed_vma) relocation >> 16; + insn = bfd_get_32 (input_bfd, contents + rel->r_offset); + insn &= ~0x1fffc1; + insn |= (relocation & 0xffc1) | ((relocation & 0x3e) << 15); + bfd_put_32 (input_bfd, insn, contents + rel->r_offset); + r = bfd_reloc_ok; + if (relocation + 0x8000 > 0xffff) + r = bfd_reloc_overflow; + } + } + else + r = _bfd_final_link_relocate (howto, input_bfd, input_section, contents, + rel->r_offset, relocation, addend); if (r != bfd_reloc_ok) { @@ -14981,13 +15231,11 @@ ppc64_elf_relocate_section (bfd *output_bfd, && (h->elf.root.type == bfd_link_hash_undefweak || h->elf.root.type == bfd_link_hash_undefined) && is_branch_reloc (r_type)))) - { - if (!((*info->callbacks->reloc_overflow) - (info, &h->elf.root, sym_name, - reloc_name, orig_rel.r_addend, - input_bfd, input_section, rel->r_offset))) - return FALSE; - } + info->callbacks->reloc_overflow (info, &h->elf.root, + sym_name, reloc_name, + orig_rel.r_addend, + input_bfd, input_section, + rel->r_offset); } else { @@ -15000,6 +15248,29 @@ ppc64_elf_relocate_section (bfd *output_bfd, if (more_info != NULL) free (more_info); } + copy_reloc: + if (wrel != rel) + *wrel = *rel; + } + + if (wrel != rel) + { + Elf_Internal_Shdr *rel_hdr; + size_t deleted = rel - wrel; + + rel_hdr = _bfd_elf_single_rel_hdr (input_section->output_section); + rel_hdr->sh_size -= rel_hdr->sh_entsize * deleted; + if (rel_hdr->sh_size == 0) + { + /* It is too late to remove an empty reloc section. Leave + one NONE reloc. + ??? What is wrong with an empty section??? */ + rel_hdr->sh_size = rel_hdr->sh_entsize; + deleted -= 1; + } + rel_hdr = _bfd_elf_single_rel_hdr (input_section); + rel_hdr->sh_size -= rel_hdr->sh_entsize * deleted; + input_section->reloc_count -= deleted; } /* If we're emitting relocations, then shortly after this function