X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=bfd%2Felf64-ppc.c;h=8d710848ba60bd89ab5c5ef039d01cd7c4208a66;hb=cf6f3e86ded2cd950f59a0f2c164f2c953ef534b;hp=5c7f32315fa57cb7fee28f82bfbe8e60fe04d2e9;hpb=618265039f697eab9e72bb58b95fc2d32925df58;p=deliverable%2Fbinutils-gdb.git diff --git a/bfd/elf64-ppc.c b/bfd/elf64-ppc.c index 5c7f32315f..8d710848ba 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-2019 Free Software Foundation, Inc. + Copyright (C) 1999-2020 Free Software Foundation, Inc. Written by Linus Nordberg, Swox AB , based on elf32-ppc.c by Ian Lance Taylor. Largely rewritten by Alan Modra. @@ -35,6 +35,9 @@ #include "elf64-ppc.h" #include "dwarf2.h" +/* All users of this file have bfd_octets_per_byte (abfd, sec) == 1. */ +#define OCTETS_PER_BYTE(ABFD, SEC) 1 + static bfd_reloc_status_type ppc64_elf_ha_reloc (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **); static bfd_reloc_status_type ppc64_elf_branch_reloc @@ -122,6 +125,7 @@ static bfd_vma opd_entry_value #define elf_backend_finish_dynamic_sections ppc64_elf_finish_dynamic_sections #define elf_backend_link_output_symbol_hook ppc64_elf_output_symbol_hook #define elf_backend_special_sections ppc64_elf_special_sections +#define elf_backend_section_flags ppc64_elf_section_flags #define elf_backend_merge_symbol_attribute ppc64_elf_merge_symbol_attribute #define elf_backend_merge_symbol ppc64_elf_merge_symbol #define elf_backend_get_reloc_section bfd_get_section_by_name @@ -926,16 +930,16 @@ static reloc_howto_type ppc64_elf_howto_raw[] = HOW (R_PPC64_DTPREL34, 4, 34, 0x3ffff0000ffffULL, 0, FALSE, signed, ppc64_elf_unhandled_reloc), - HOW (R_PPC64_GOT_TLSGD34, 4, 34, 0x3ffff0000ffffULL, 0, TRUE, signed, + HOW (R_PPC64_GOT_TLSGD_PCREL34, 4, 34, 0x3ffff0000ffffULL, 0, TRUE, signed, ppc64_elf_unhandled_reloc), - HOW (R_PPC64_GOT_TLSLD34, 4, 34, 0x3ffff0000ffffULL, 0, TRUE, signed, + HOW (R_PPC64_GOT_TLSLD_PCREL34, 4, 34, 0x3ffff0000ffffULL, 0, TRUE, signed, ppc64_elf_unhandled_reloc), - HOW (R_PPC64_GOT_TPREL34, 4, 34, 0x3ffff0000ffffULL, 0, TRUE, signed, + HOW (R_PPC64_GOT_TPREL_PCREL34, 4, 34, 0x3ffff0000ffffULL, 0, TRUE, signed, ppc64_elf_unhandled_reloc), - HOW (R_PPC64_GOT_DTPREL34, 4, 34, 0x3ffff0000ffffULL, 0, TRUE, signed, + HOW (R_PPC64_GOT_DTPREL_PCREL34, 4, 34, 0x3ffff0000ffffULL, 0, TRUE, signed, ppc64_elf_unhandled_reloc), HOW (R_PPC64_ADDR16_HIGHER34, 1, 16, 0xffff, 34, FALSE, dont, @@ -995,8 +999,7 @@ ppc_howto_init (void) } static reloc_howto_type * -ppc64_elf_reloc_type_lookup (bfd *abfd, - bfd_reloc_code_real_type code) +ppc64_elf_reloc_type_lookup (bfd *abfd, bfd_reloc_code_real_type code) { enum elf_ppc64_reloc_type r = R_PPC64_NONE; @@ -1276,13 +1279,13 @@ ppc64_elf_reloc_type_lookup (bfd *abfd, break; case BFD_RELOC_PPC64_DTPREL34: r = R_PPC64_DTPREL34; break; - case BFD_RELOC_PPC64_GOT_TLSGD34: r = R_PPC64_GOT_TLSGD34; + case BFD_RELOC_PPC64_GOT_TLSGD_PCREL34: r = R_PPC64_GOT_TLSGD_PCREL34; break; - case BFD_RELOC_PPC64_GOT_TLSLD34: r = R_PPC64_GOT_TLSLD34; + case BFD_RELOC_PPC64_GOT_TLSLD_PCREL34: r = R_PPC64_GOT_TLSLD_PCREL34; break; - case BFD_RELOC_PPC64_GOT_TPREL34: r = R_PPC64_GOT_TPREL34; + case BFD_RELOC_PPC64_GOT_TPREL_PCREL34: r = R_PPC64_GOT_TPREL_PCREL34; break; - case BFD_RELOC_PPC64_GOT_DTPREL34: r = R_PPC64_GOT_DTPREL34; + case BFD_RELOC_PPC64_GOT_DTPREL_PCREL34: r = R_PPC64_GOT_DTPREL_PCREL34; break; case BFD_RELOC_PPC64_ADDR16_HIGHER34: r = R_PPC64_ADDR16_HIGHER34; break; @@ -1314,16 +1317,33 @@ ppc64_elf_reloc_type_lookup (bfd *abfd, }; static reloc_howto_type * -ppc64_elf_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, - const char *r_name) +ppc64_elf_reloc_name_lookup (bfd *abfd, const char *r_name) { unsigned int i; + static char *compat_map[][2] = { + { "R_PPC64_GOT_TLSGD34", "R_PPC64_GOT_TLSGD_PCREL34" }, + { "R_PPC64_GOT_TLSLD34", "R_PPC64_GOT_TLSLD_PCREL34" }, + { "R_PPC64_GOT_TPREL34", "R_PPC64_GOT_TPREL_PCREL34" }, + { "R_PPC64_GOT_DTPREL34", "R_PPC64_GOT_DTPREL_PCREL34" } + }; for (i = 0; i < ARRAY_SIZE (ppc64_elf_howto_raw); i++) if (ppc64_elf_howto_raw[i].name != NULL && strcasecmp (ppc64_elf_howto_raw[i].name, r_name) == 0) return &ppc64_elf_howto_raw[i]; + /* Handle old names of relocations in case they were used by + .reloc directives. + FIXME: Remove this soon. Mapping the reloc names is very likely + completely unnecessary. */ + for (i = 0; i < ARRAY_SIZE (compat_map); i++) + if (strcasecmp (compat_map[i][0], r_name) == 0) + { + _bfd_error_handler (_("warning: %s should be used rather than %s"), + compat_map[i][1], compat_map[i][0]); + return ppc64_elf_reloc_name_lookup (abfd, compat_map[i][1]); + } + return NULL; } @@ -1405,7 +1425,7 @@ ppc64_elf_ha_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol, + input_section->output_section->vma); value = (bfd_signed_vma) value >> 16; - octets = reloc_entry->address * bfd_octets_per_byte (abfd, NULL); + octets = reloc_entry->address * OCTETS_PER_BYTE (abfd, input_section); insn = bfd_get_32 (abfd, (bfd_byte *) data + octets); insn &= ~0x1fffc1; insn |= (value & 0xffc1) | ((value & 0x3e) << 15); @@ -1480,7 +1500,7 @@ ppc64_elf_brtaken_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol, return bfd_elf_generic_reloc (abfd, reloc_entry, symbol, data, input_section, output_bfd, error_message); - octets = reloc_entry->address * bfd_octets_per_byte (abfd, NULL); + octets = reloc_entry->address * OCTETS_PER_BYTE (abfd, input_section); insn = bfd_get_32 (abfd, (bfd_byte *) data + octets); insn &= ~(0x01 << 21); r_type = reloc_entry->howto->type; @@ -1630,7 +1650,7 @@ ppc64_elf_toc64_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol, if (TOCstart == 0) TOCstart = ppc64_elf_set_toc (NULL, input_section->output_section->owner); - octets = reloc_entry->address * bfd_octets_per_byte (abfd, NULL); + octets = reloc_entry->address * OCTETS_PER_BYTE (abfd, input_section); bfd_put_64 (abfd, TOCstart + TOC_BASE_OFF, (bfd_byte *) data + octets); return bfd_reloc_ok; } @@ -1997,7 +2017,7 @@ ppc64_elf_new_section_hook (bfd *abfd, asection *sec) if (!sec->used_by_bfd) { struct _ppc64_elf_section_data *sdata; - bfd_size_type amt = sizeof (*sdata); + size_t amt = sizeof (*sdata); sdata = bfd_zalloc (abfd, amt); if (sdata == NULL) @@ -2008,6 +2028,18 @@ ppc64_elf_new_section_hook (bfd *abfd, asection *sec) return _bfd_elf_new_section_hook (abfd, sec); } +static bfd_boolean +ppc64_elf_section_flags (const Elf_Internal_Shdr *hdr) +{ + const char *name = hdr->bfd_section->name; + + if (strncmp (name, ".sbss", 5) == 0 + || strncmp (name, ".sdata", 6) == 0) + hdr->bfd_section->flags |= SEC_SMALL_DATA; + + return TRUE; +} + static struct _opd_sec_data * get_opd_info (asection * sec) { @@ -2117,9 +2149,10 @@ compare_symbols (const void *ap, const void *bp) /* Search SYMS for a symbol of the given VALUE. */ static asymbol * -sym_exists_at (asymbol **syms, long lo, long hi, unsigned int id, bfd_vma value) +sym_exists_at (asymbol **syms, size_t lo, size_t hi, unsigned int id, + bfd_vma value) { - long mid; + size_t mid; if (id == (unsigned) -1) { @@ -2405,8 +2438,7 @@ ppc64_elf_get_synthetic_symtab (bfd *abfd, free_contents_and_exit_err: count = -1; free_contents_and_exit: - if (contents) - free (contents); + free (contents); goto done; } @@ -2784,20 +2816,20 @@ must_be_dyn_reloc (struct bfd_link_info *info, } /* If ELIMINATE_COPY_RELOCS is non-zero, the linker will try to avoid - copying dynamic variables from a shared lib into an app's dynbss + copying dynamic variables from a shared lib into an app's .dynbss section, and instead use a dynamic relocation to point into the - shared lib. With code that gcc generates, it's vital that this be - enabled; In the PowerPC64 ABI, the address of a function is actually - the address of a function descriptor, which resides in the .opd - section. gcc uses the descriptor directly rather than going via the - GOT as some other ABI's do, which means that initialized function - pointers must reference the descriptor. Thus, a function pointer - initialized to the address of a function in a shared library will - either require a copy reloc, or a dynamic reloc. Using a copy reloc - redefines the function descriptor symbol to point to the copy. This - presents a problem as a plt entry for that function is also - initialized from the function descriptor symbol and the copy reloc - may not be initialized first. */ + shared lib. With code that gcc generates it is vital that this be + enabled; In the PowerPC64 ELFv1 ABI the address of a function is + actually the address of a function descriptor which resides in the + .opd section. gcc uses the descriptor directly rather than going + via the GOT as some other ABIs do, which means that initialized + function pointers reference the descriptor. Thus, a function + pointer initialized to the address of a function in a shared + library will either require a .dynbss copy and a copy reloc, or a + dynamic reloc. Using a .dynbss copy redefines the function + descriptor symbol to point to the copy. This presents a problem as + a PLT entry for that function is also initialized from the function + descriptor symbol and the copy may not be initialized first. */ #define ELIMINATE_COPY_RELOCS 1 /* Section name for stubs is the associated section name plus this @@ -2813,8 +2845,8 @@ must_be_dyn_reloc (struct bfd_link_info *info, ppc_stub_plt_branch: Similar to the above, but a 24 bit branch in the stub section won't reach its destination. - . addis %r11,%r2,xxx@toc@ha - . ld %r12,xxx@toc@l(%r11) + . addis %r12,%r2,xxx@toc@ha + . ld %r12,xxx@toc@l(%r12) . mtctr %r12 . bctr @@ -2840,8 +2872,8 @@ must_be_dyn_reloc (struct bfd_link_info *info, A ppc_stub_plt_branch with an r2 offset looks like: . std %r2,40(%r1) - . addis %r11,%r2,xxx@toc@ha - . ld %r12,xxx@toc@l(%r11) + . addis %r12,%r2,xxx@toc@ha + . ld %r12,xxx@toc@l(%r12) . addis %r2,%r2,off@ha . addi %r2,%r2,off@l . mtctr %r12 @@ -2897,7 +2929,7 @@ must_be_dyn_reloc (struct bfd_link_info *info, . mtctr %r12 . bctr - There are also ELFv1 powerxx variants of these stubs. + There are also ELFv1 power10 variants of these stubs. ppc_stub_long_branch_notoc: . pla %r12,dest@pcrel . b dest @@ -2920,7 +2952,7 @@ must_be_dyn_reloc (struct bfd_link_info *info, In cases where the high instructions would add zero, they are omitted and following instructions modified in some cases. - For example, a powerxx ppc_stub_plt_call_notoc might simplify down + For example, a power10 ppc_stub_plt_call_notoc might simplify down to . pld %r12,xxx@pcrel . mtctr %r12 @@ -3059,9 +3091,6 @@ struct ppc_link_hash_entry struct ppc_link_hash_entry *next_dot_sym; } u; - /* Track dynamic relocs copied for this symbol. */ - struct elf_dyn_relocs *dyn_relocs; - /* Link between function code and descriptor symbols. */ struct ppc_link_hash_entry *oh; @@ -3108,6 +3137,12 @@ struct ppc_link_hash_entry #define NON_GOT 256 /* local symbol plt, not stored. */ }; +static inline struct ppc_link_hash_entry * +ppc_elf_hash_entry (struct elf_link_hash_entry *ent) +{ + return (struct ppc_link_hash_entry *) ent; +} + /* ppc64 ELF linker hash table. */ struct ppc_link_hash_table @@ -3170,6 +3205,9 @@ struct ppc_link_hash_table /* Shortcut to .__tls_get_addr and __tls_get_addr. */ struct ppc_link_hash_entry *tls_get_addr; struct ppc_link_hash_entry *tls_get_addr_fd; + struct ppc_link_hash_entry *tga_desc; + struct ppc_link_hash_entry *tga_desc_fd; + struct map_stub *tga_group; /* The size of reliplt used by got entry relocs. */ bfd_size_type got_reli_size; @@ -3201,19 +3239,14 @@ struct ppc_link_hash_table /* Whether func_desc_adjust needs to be run over symbols. */ unsigned int need_func_desc_adj:1; - /* Whether there exist local gnu indirect function resolvers, - referenced by dynamic relocations. */ - unsigned int local_ifunc_resolver:1; - unsigned int maybe_local_ifunc_resolver:1; - /* Whether plt calls for ELFv2 localentry:0 funcs have been optimized. */ unsigned int has_plt_localentry0:1; /* Whether calls are made via the PLT from NOTOC functions. */ unsigned int notoc_plt:1; - /* Whether to use powerxx instructions in linkage stubs. */ - unsigned int powerxx_stubs:1; + /* Whether to use power10 instructions in linkage stubs. */ + unsigned int power10_stubs:1; /* Incremented every time we size stubs. */ unsigned int stub_iteration; @@ -3422,7 +3455,7 @@ static struct bfd_link_hash_table * ppc64_elf_link_hash_table_create (bfd *abfd) { struct ppc_link_hash_table *htab; - bfd_size_type amt = sizeof (struct ppc_link_hash_table); + size_t amt = sizeof (struct ppc_link_hash_table); htab = bfd_zmalloc (amt); if (htab == NULL) @@ -3807,7 +3840,7 @@ elf_follow_link (struct elf_link_hash_entry *h) static inline struct ppc_link_hash_entry * ppc_follow_link (struct ppc_link_hash_entry *h) { - return (struct ppc_link_hash_entry *) follow_link (&h->elf.root); + return ppc_elf_hash_entry (elf_follow_link (&h->elf)); } /* Merge PLT info on FROM with that on TO. */ @@ -3854,8 +3887,8 @@ ppc64_elf_copy_indirect_symbol (struct bfd_link_info *info, { struct ppc_link_hash_entry *edir, *eind; - edir = (struct ppc_link_hash_entry *) dir; - eind = (struct ppc_link_hash_entry *) ind; + edir = ppc_elf_hash_entry (dir); + eind = ppc_elf_hash_entry (ind); edir->is_func |= eind->is_func; edir->is_func_descriptor |= eind->is_func_descriptor; @@ -3881,20 +3914,20 @@ ppc64_elf_copy_indirect_symbol (struct bfd_link_info *info, return; /* Copy over any dynamic relocs we may have on the indirect sym. */ - if (eind->dyn_relocs != NULL) + if (ind->dyn_relocs != NULL) { - if (edir->dyn_relocs != NULL) + if (dir->dyn_relocs != NULL) { struct elf_dyn_relocs **pp; struct elf_dyn_relocs *p; /* Add reloc counts against the indirect sym to the direct sym list. Merge any entries against the same section. */ - for (pp = &eind->dyn_relocs; (p = *pp) != NULL; ) + for (pp = &ind->dyn_relocs; (p = *pp) != NULL; ) { struct elf_dyn_relocs *q; - for (q = edir->dyn_relocs; q != NULL; q = q->next) + for (q = dir->dyn_relocs; q != NULL; q = q->next) if (q->sec == p->sec) { q->pc_count += p->pc_count; @@ -3905,11 +3938,11 @@ ppc64_elf_copy_indirect_symbol (struct bfd_link_info *info, if (q == NULL) pp = &p->next; } - *pp = edir->dyn_relocs; + *pp = dir->dyn_relocs; } - edir->dyn_relocs = eind->dyn_relocs; - eind->dyn_relocs = NULL; + dir->dyn_relocs = ind->dyn_relocs; + ind->dyn_relocs = NULL; } /* Copy over got entries that we may have already seen to the @@ -3971,8 +4004,8 @@ lookup_fdh (struct ppc_link_hash_entry *fh, struct ppc_link_hash_table *htab) { const char *fd_name = fh->elf.root.root.string + 1; - fdh = (struct ppc_link_hash_entry *) - elf_link_hash_lookup (&htab->elf, fd_name, FALSE, FALSE, FALSE); + fdh = ppc_elf_hash_entry (elf_link_hash_lookup (&htab->elf, fd_name, + FALSE, FALSE, FALSE)); if (fdh == NULL) return fdh; @@ -4100,9 +4133,9 @@ ppc64_elf_merge_symbol (struct elf_link_hash_entry *h, bfd *oldbfd ATTRIBUTE_UNUSED, const asection *oldsec ATTRIBUTE_UNUSED) { - ((struct ppc_link_hash_entry *) h)->fake = 0; + ppc_elf_hash_entry (h)->fake = 0; if ((STO_PPC64_LOCAL_MASK & isym->st_other) != 0) - ((struct ppc_link_hash_entry *) h)->non_zero_localentry = 1; + ppc_elf_hash_entry (h)->non_zero_localentry = 1; return TRUE; } @@ -4124,7 +4157,7 @@ ppc64_elf_archive_symbol_lookup (bfd *abfd, if (h != NULL /* Don't return this sym if it is a fake function descriptor created by add_symbol_adjust. */ - && !((struct ppc_link_hash_entry *) h)->fake) + && !ppc_elf_hash_entry (h)->fake) return h; if (name[0] == '.') @@ -4138,6 +4171,11 @@ ppc64_elf_archive_symbol_lookup (bfd *abfd, memcpy (dot_name + 1, name, len + 1); h = _bfd_elf_archive_symbol_lookup (abfd, info, dot_name); bfd_release (abfd, dot_name); + if (h != NULL) + return h; + + if (strcmp (name, "__tls_get_addr_opt") == 0) + h = _bfd_elf_archive_symbol_lookup (abfd, info, "__tls_get_addr_desc"); return h; } @@ -4413,7 +4451,7 @@ update_local_sym_info (bfd *abfd, Elf_Internal_Shdr *symtab_hdr, break; if (ent == NULL) { - bfd_size_type amt = sizeof (*ent); + size_t amt = sizeof (*ent); ent = bfd_alloc (abfd, amt); if (ent == NULL) return FALSE; @@ -4445,7 +4483,7 @@ update_plt_info (bfd *abfd, struct plt_entry **plist, bfd_vma addend) break; if (ent == NULL) { - bfd_size_type amt = sizeof (*ent); + size_t amt = sizeof (*ent); ent = bfd_alloc (abfd, amt); if (ent == NULL) return FALSE; @@ -4509,15 +4547,6 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, if (bfd_link_relocatable (info)) return TRUE; - /* Don't do anything special with non-loaded, non-alloced sections. - In particular, any relocs in such sections should not affect GOT - and PLT reference counting (ie. we don't allow them to create GOT - or PLT entries), there's no possibility or desire to optimize TLS - relocs, and there's not much point in propagating relocs to shared - libs that the dynamic linker won't relocate. */ - if ((sec->flags & SEC_ALLOC) == 0) - return TRUE; - BFD_ASSERT (is_ppc64_elf (abfd)); htab = ppc_hash_table (info); @@ -4566,14 +4595,14 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, case R_PPC64_DTPREL34: case R_PPC64_PCREL34: case R_PPC64_GOT_PCREL34: - case R_PPC64_GOT_TLSGD34: - case R_PPC64_GOT_TLSLD34: - case R_PPC64_GOT_TPREL34: - case R_PPC64_GOT_DTPREL34: + case R_PPC64_GOT_TLSGD_PCREL34: + case R_PPC64_GOT_TLSLD_PCREL34: + case R_PPC64_GOT_TPREL_PCREL34: + case R_PPC64_GOT_DTPREL_PCREL34: case R_PPC64_PLT_PCREL34: case R_PPC64_PLT_PCREL34_NOTOC: case R_PPC64_PCREL28: - htab->powerxx_stubs = 1; + htab->power10_stubs = 1; break; default: break; @@ -4640,7 +4669,7 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, /* These special tls relocs tie a call to __tls_get_addr with its parameter symbol. */ if (h != NULL) - ((struct ppc_link_hash_entry *) h)->tls_mask |= TLS_TLS | TLS_MARK; + ppc_elf_hash_entry (h)->tls_mask |= TLS_TLS | TLS_MARK; else if (!update_local_sym_info (abfd, symtab_hdr, r_symndx, rel->r_addend, @@ -4653,7 +4682,7 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, case R_PPC64_GOT_TLSLD16_LO: case R_PPC64_GOT_TLSLD16_HI: case R_PPC64_GOT_TLSLD16_HA: - case R_PPC64_GOT_TLSLD34: + case R_PPC64_GOT_TLSLD_PCREL34: tls_type = TLS_TLS | TLS_LD; goto dogottls; @@ -4661,7 +4690,7 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, case R_PPC64_GOT_TLSGD16_LO: case R_PPC64_GOT_TLSGD16_HI: case R_PPC64_GOT_TLSGD16_HA: - case R_PPC64_GOT_TLSGD34: + case R_PPC64_GOT_TLSGD_PCREL34: tls_type = TLS_TLS | TLS_GD; goto dogottls; @@ -4669,7 +4698,7 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, case R_PPC64_GOT_TPREL16_LO_DS: case R_PPC64_GOT_TPREL16_HI: case R_PPC64_GOT_TPREL16_HA: - case R_PPC64_GOT_TPREL34: + case R_PPC64_GOT_TPREL_PCREL34: if (bfd_link_dll (info)) info->flags |= DF_STATIC_TLS; tls_type = TLS_TLS | TLS_TPREL; @@ -4679,7 +4708,7 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, case R_PPC64_GOT_DTPREL16_LO_DS: case R_PPC64_GOT_DTPREL16_HI: case R_PPC64_GOT_DTPREL16_HA: - case R_PPC64_GOT_DTPREL34: + case R_PPC64_GOT_DTPREL_PCREL34: tls_type = TLS_TLS | TLS_DTPREL; dogottls: sec->has_tls_reloc = 1; @@ -4715,7 +4744,7 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, struct ppc_link_hash_entry *eh; struct got_entry *ent; - eh = (struct ppc_link_hash_entry *) h; + eh = ppc_elf_hash_entry (h); for (ent = eh->elf.got.glist; ent != NULL; ent = ent->next) if (ent->addend == rel->r_addend && ent->owner == abfd @@ -4723,7 +4752,7 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, break; if (ent == NULL) { - bfd_size_type amt = sizeof (*ent); + size_t amt = sizeof (*ent); ent = bfd_alloc (abfd, amt); if (ent == NULL) return FALSE; @@ -4743,14 +4772,6 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, if (!update_local_sym_info (abfd, symtab_hdr, r_symndx, rel->r_addend, tls_type)) return FALSE; - - /* We may also need a plt entry if the symbol turns out to be - an ifunc. */ - if (h != NULL && !bfd_link_pic (info) && abiversion (abfd) != 1) - { - if (!update_plt_info (abfd, &h->plt.plist, rel->r_addend)) - return FALSE; - } break; case R_PPC64_PLT16_HA: @@ -4768,8 +4789,8 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, 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; - ((struct ppc_link_hash_entry *) h)->tls_mask |= PLT_KEEP; + ppc_elf_hash_entry (h)->is_func = 1; + ppc_elf_hash_entry (h)->tls_mask |= PLT_KEEP; plt_list = &h->plt.plist; } if (plt_list == NULL) @@ -4923,7 +4944,7 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, 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; + ppc_elf_hash_entry (h)->is_func = 1; if (h == tga || h == dottga) { @@ -4981,11 +5002,7 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, dotlstoc: sec->has_tls_reloc = 1; if (h != NULL) - { - struct ppc_link_hash_entry *eh; - eh = (struct ppc_link_hash_entry *) h; - eh->tls_mask |= tls_type & 0xff; - } + ppc_elf_hash_entry (h)->tls_mask |= tls_type & 0xff; else if (!update_local_sym_info (abfd, symtab_hdr, r_symndx, rel->r_addend, tls_type)) @@ -5043,7 +5060,7 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, && ELF64_R_TYPE ((rel + 1)->r_info) == R_PPC64_TOC) { if (h != NULL) - ((struct ppc_link_hash_entry *) h)->is_func = 1; + ppc_elf_hash_entry (h)->is_func = 1; } /* Fall through. */ @@ -5147,7 +5164,7 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, struct elf_dyn_relocs *p; struct elf_dyn_relocs **head; - head = &((struct ppc_link_hash_entry *) h)->dyn_relocs; + head = &h->dyn_relocs; p = *head; if (p == NULL || p->sec != sec) { @@ -5528,7 +5545,7 @@ is_elfv2_localentry0 (struct elf_link_hash_entry *h) && h->type == STT_FUNC && h->root.type == bfd_link_hash_defined && (STO_PPC64_LOCAL_MASK & h->other) == 0 - && !((struct ppc_link_hash_entry *) h)->non_zero_localentry + && !ppc_elf_hash_entry (h)->non_zero_localentry && is_ppc64_elf (h->root.u.def.section->owner) && abiversion (h->root.u.def.section->owner) >= 2); } @@ -5577,6 +5594,27 @@ defined_func_desc (struct ppc_link_hash_entry *fh) return NULL; } +/* Given H is a symbol that satisfies is_static_defined, return the + value in the output file. */ + +static bfd_vma +defined_sym_val (struct elf_link_hash_entry *h) +{ + return (h->root.u.def.section->output_section->vma + + h->root.u.def.section->output_offset + + h->root.u.def.value); +} + +/* Return true if H matches __tls_get_addr or one of its variants. */ + +static bfd_boolean +is_tls_get_addr (struct elf_link_hash_entry *h, + struct ppc_link_hash_table *htab) +{ + return (h == &htab->tls_get_addr_fd->elf || h == &htab->tga_desc_fd->elf + || h == &htab->tls_get_addr->elf || h == &htab->tga_desc->elf); +} + static bfd_boolean func_desc_adjust (struct elf_link_hash_entry *, void *); /* Garbage collect sections, after first dealing with dot-symbols. */ @@ -5610,8 +5648,8 @@ ppc64_elf_gc_keep (struct bfd_link_info *info) struct ppc_link_hash_entry *eh, *fh; asection *sec; - eh = (struct ppc_link_hash_entry *) - elf_link_hash_lookup (&htab->elf, sym->name, FALSE, FALSE, TRUE); + eh = ppc_elf_hash_entry (elf_link_hash_lookup (&htab->elf, sym->name, + FALSE, FALSE, TRUE)); if (eh == NULL) continue; if (eh->elf.root.type != bfd_link_hash_defined @@ -5643,7 +5681,7 @@ static bfd_boolean ppc64_elf_gc_mark_dynamic_ref (struct elf_link_hash_entry *h, void *inf) { struct bfd_link_info *info = (struct bfd_link_info *) inf; - struct ppc_link_hash_entry *eh = (struct ppc_link_hash_entry *) h; + struct ppc_link_hash_entry *eh = ppc_elf_hash_entry (h); struct ppc_link_hash_entry *fdh; struct bfd_elf_dynamic_list *d = info->dynamic_list; @@ -5727,7 +5765,7 @@ ppc64_elf_gc_mark_hook (asection *sec, { case bfd_link_hash_defined: case bfd_link_hash_defweak: - eh = (struct ppc_link_hash_entry *) h; + eh = ppc_elf_hash_entry (h); fdh = defined_func_desc (eh); if (fdh != NULL) { @@ -5823,8 +5861,8 @@ 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, writing, TRUE, TRUE); + h = ppc_elf_hash_entry (elf_link_hash_lookup (&htab->elf, sym, + writing, TRUE, TRUE)); if (stub_sec != NULL) { if (h != NULL @@ -6051,6 +6089,84 @@ restvr_tail (bfd *abfd, bfd_byte *p, int r) return p + 4; } +#define STDU_R1_0R1 0xf8210001 +#define ADDI_R1_R1 0x38210000 + +/* Emit prologue of wrapper preserving regs around a call to + __tls_get_addr_opt. */ + +static bfd_byte * +tls_get_addr_prologue (bfd *obfd, bfd_byte *p, struct ppc_link_hash_table *htab) +{ + unsigned int i; + + bfd_put_32 (obfd, MFLR_R0, p); + p += 4; + bfd_put_32 (obfd, STD_R0_0R1 + 16, p); + p += 4; + + if (htab->opd_abi) + { + for (i = 4; i < 12; i++) + { + bfd_put_32 (obfd, + STD_R0_0R1 | i << 21 | (-(13 - i) * 8 & 0xffff), p); + p += 4; + } + bfd_put_32 (obfd, STDU_R1_0R1 | (-128 & 0xffff), p); + p += 4; + } + else + { + for (i = 4; i < 12; i++) + { + bfd_put_32 (obfd, + STD_R0_0R1 | i << 21 | (-(12 - i) * 8 & 0xffff), p); + p += 4; + } + bfd_put_32 (obfd, STDU_R1_0R1 | (-96 & 0xffff), p); + p += 4; + } + return p; +} + +/* Emit epilogue of wrapper preserving regs around a call to + __tls_get_addr_opt. */ + +static bfd_byte * +tls_get_addr_epilogue (bfd *obfd, bfd_byte *p, struct ppc_link_hash_table *htab) +{ + unsigned int i; + + if (htab->opd_abi) + { + for (i = 4; i < 12; i++) + { + bfd_put_32 (obfd, LD_R0_0R1 | i << 21 | (128 - (13 - i) * 8), p); + p += 4; + } + bfd_put_32 (obfd, ADDI_R1_R1 | 128, p); + p += 4; + } + else + { + for (i = 4; i < 12; i++) + { + bfd_put_32 (obfd, LD_R0_0R1 | i << 21 | (96 - (12 - i) * 8), p); + p += 4; + } + bfd_put_32 (obfd, ADDI_R1_R1 | 96, p); + p += 4; + } + bfd_put_32 (obfd, LD_R0_0R1 | 16, p); + p += 4; + bfd_put_32 (obfd, MTLR_R0, p); + p += 4; + bfd_put_32 (obfd, BLR, p); + p += 4; + return p; +} + /* Called via elf_link_hash_traverse to transfer dynamic linking information on function code symbol entries to their corresponding function descriptor symbol entries. */ @@ -6064,7 +6180,7 @@ func_desc_adjust (struct elf_link_hash_entry *h, void *inf) struct ppc_link_hash_entry *fdh; bfd_boolean force_local; - fh = (struct ppc_link_hash_entry *) h; + fh = ppc_elf_hash_entry (h); if (fh->elf.root.type == bfd_link_hash_indirect) return TRUE; @@ -6242,25 +6358,6 @@ ppc64_elf_func_desc_adjust (bfd *obfd ATTRIBUTE_UNUSED, return TRUE; } -/* Find dynamic relocs for H that apply to read-only sections. */ - -static asection * -readonly_dynrelocs (struct elf_link_hash_entry *h) -{ - struct ppc_link_hash_entry *eh; - struct elf_dyn_relocs *p; - - eh = (struct ppc_link_hash_entry *) h; - for (p = eh->dyn_relocs; p != NULL; p = p->next) - { - asection *s = p->sec->output_section; - - if (s != NULL && (s->flags & SEC_READONLY) != 0) - return p->sec; - } - return NULL; -} - /* Return true if we have dynamic relocs against H or any of its weak aliases, that apply to read-only sections. Cannot be used after size_dynamic_sections. */ @@ -6268,14 +6365,12 @@ readonly_dynrelocs (struct elf_link_hash_entry *h) 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; + struct ppc_link_hash_entry *eh = ppc_elf_hash_entry (h); do { - if (readonly_dynrelocs (&eh->elf)) + if (_bfd_elf_readonly_dynrelocs (&eh->elf)) return TRUE; - eh = (struct ppc_link_hash_entry *) eh->elf.u.alias; + eh = ppc_elf_hash_entry (eh->elf.u.alias); } while (eh != NULL && &eh->elf != h); @@ -6289,7 +6384,7 @@ pc_dynrelocs (struct ppc_link_hash_entry *eh) { struct elf_dyn_relocs *p; - for (p = eh->dyn_relocs; p != NULL; p = p->next) + for (p = eh->elf.dyn_relocs; p != NULL; p = p->next) if (p->pc_count != 0) return TRUE; return FALSE; @@ -6337,7 +6432,7 @@ ppc64_elf_adjust_dynamic_symbol (struct bfd_link_info *info, || h->type == STT_GNU_IFUNC || h->needs_plt) { - bfd_boolean local = (((struct ppc_link_hash_entry *) h)->save_res + bfd_boolean local = (ppc_elf_hash_entry (h)->save_res || SYMBOL_CALLS_LOCAL (info, h) || UNDEFWEAK_NO_DYNAMIC_RELOC (info, h)); /* Discard dyn_relocs when non-pic if we've decided that a @@ -6352,7 +6447,7 @@ ppc64_elf_adjust_dynamic_symbol (struct bfd_link_info *info, if (!bfd_link_pic (info) && h->type != STT_GNU_IFUNC && local) - ((struct ppc_link_hash_entry *) h)->dyn_relocs = NULL; + h->dyn_relocs = NULL; /* Clear procedure linkage table information for any symbol that won't need a .plt entry. */ @@ -6364,7 +6459,7 @@ ppc64_elf_adjust_dynamic_symbol (struct bfd_link_info *info, || (h->type != STT_GNU_IFUNC && local && (htab->can_convert_all_inline_plt - || (((struct ppc_link_hash_entry *) h)->tls_mask + || (ppc_elf_hash_entry (h)->tls_mask & (TLS_TLS | PLT_KEEP)) != PLT_KEEP))) { h->plt.plist = NULL; @@ -6382,7 +6477,7 @@ ppc64_elf_adjust_dynamic_symbol (struct bfd_link_info *info, extra work in ld.so when resolving these symbols. */ if (global_entry_stub (h)) { - if (!readonly_dynrelocs (h)) + if (!_bfd_elf_readonly_dynrelocs (h)) { h->pointer_equality_needed = 0; /* If we haven't seen a branch reloc and the symbol @@ -6393,14 +6488,14 @@ ppc64_elf_adjust_dynamic_symbol (struct bfd_link_info *info, else if (!bfd_link_pic (info)) /* We are going to be defining the function symbol on the plt stub, so no dyn_relocs needed when non-pic. */ - ((struct ppc_link_hash_entry *) h)->dyn_relocs = NULL; + h->dyn_relocs = NULL; } /* ELFv2 function symbols can't have copy relocs. */ return TRUE; } else if (!h->needs_plt - && !readonly_dynrelocs (h)) + && !_bfd_elf_readonly_dynrelocs (h)) { /* If we haven't seen a branch reloc and the symbol isn't an ifunc then we don't need a plt entry. */ @@ -6423,7 +6518,7 @@ ppc64_elf_adjust_dynamic_symbol (struct bfd_link_info *info, h->root.u.def.value = def->root.u.def.value; if (def->root.u.def.section == htab->elf.sdynbss || def->root.u.def.section == htab->elf.sdynrelro) - ((struct ppc_link_hash_entry *) h)->dyn_relocs = NULL; + h->dyn_relocs = NULL; return TRUE; } @@ -6458,13 +6553,23 @@ ppc64_elf_adjust_dynamic_symbol (struct bfd_link_info *info, || h->protected_def) return TRUE; - if (h->plt.plist != NULL) + if (h->type == STT_FUNC + || h->type == STT_GNU_IFUNC) { - /* We should never get here, but unfortunately there are versions - of gcc out there that improperly (for this ABI) put initialized - function pointers, vtable refs and suchlike in read-only - sections. Allow them to proceed, but warn that this might - break at runtime. */ + /* .dynbss copies of function symbols only work if we have + ELFv1 dot-symbols. ELFv1 compilers since 2004 default to not + use dot-symbols and set the function symbol size to the text + size of the function rather than the size of the descriptor. + That's wrong for copying a descriptor. */ + if (ppc_elf_hash_entry (h)->oh == NULL + || !(h->size == 24 || h->size == 16)) + return TRUE; + + /* We should never get here, but unfortunately there are old + versions of gcc (circa gcc-3.2) that improperly for the + ELFv1 ABI put initialized function pointers, vtable refs and + suchlike in read-only sections. Allow them to proceed, but + warn that this might break at runtime. */ info->callbacks->einfo (_("%P: copy reloc against `%pT' requires lazy plt linking; " "avoid setting LD_BIND_NOW=1 or upgrade gcc\n"), @@ -6503,7 +6608,7 @@ ppc64_elf_adjust_dynamic_symbol (struct bfd_link_info *info, } /* We no longer want dyn_relocs. */ - ((struct ppc_link_hash_entry *) h)->dyn_relocs = NULL; + h->dyn_relocs = NULL; return _bfd_elf_adjust_dynamic_copy (info, h, s); } @@ -6520,7 +6625,7 @@ ppc64_elf_hide_symbol (struct bfd_link_info *info, if (ppc_hash_table (info) == NULL) return; - eh = (struct ppc_link_hash_entry *) h; + eh = ppc_elf_hash_entry (h); if (eh->is_func_descriptor) { struct ppc_link_hash_entry *fh = eh->oh; @@ -6543,8 +6648,8 @@ ppc64_elf_hide_symbol (struct bfd_link_info *info, p = eh->elf.root.root.string - 1; save = *p; *(char *) p = '.'; - fh = (struct ppc_link_hash_entry *) - elf_link_hash_lookup (htab, p, FALSE, FALSE, FALSE); + fh = ppc_elf_hash_entry (elf_link_hash_lookup (htab, p, FALSE, + FALSE, FALSE)); *(char *) p = save; /* Unfortunately, if it so happens that the string we were @@ -6557,8 +6662,8 @@ ppc64_elf_hide_symbol (struct bfd_link_info *info, while (q >= eh->elf.root.root.string && *q == *p) --q, --p; if (q < eh->elf.root.root.string && *p == '.') - fh = (struct ppc_link_hash_entry *) - elf_link_hash_lookup (htab, p, FALSE, FALSE, FALSE); + fh = ppc_elf_hash_entry (elf_link_hash_lookup (htab, p, FALSE, + FALSE, FALSE)); } if (fh != NULL) { @@ -6606,12 +6711,7 @@ get_sym_h (struct elf_link_hash_entry **hp, } if (tls_maskp != NULL) - { - struct ppc_link_hash_entry *eh; - - eh = (struct ppc_link_hash_entry *) h; - *tls_maskp = &eh->tls_mask; - } + *tls_maskp = &ppc_elf_hash_entry (h)->tls_mask; } else { @@ -6782,7 +6882,7 @@ adjust_opd_syms (struct elf_link_hash_entry *h, void *inf ATTRIBUTE_UNUSED) && h->root.type != bfd_link_hash_defweak) return TRUE; - eh = (struct ppc_link_hash_entry *) h; + eh = ppc_elf_hash_entry (h); if (eh->adjust_done) return TRUE; @@ -6930,7 +7030,7 @@ dec_dynrel_count (bfd_vma r_info, { struct elf_dyn_relocs *p; struct elf_dyn_relocs **pp; - pp = &((struct ppc_link_hash_entry *) h)->dyn_relocs; + pp = &h->dyn_relocs; /* elf_gc_sweep may have already removed all dyn relocs associated with local syms for a given section. Also, symbol flags are @@ -7183,11 +7283,9 @@ ppc64_elf_edit_opd (struct bfd_link_info *info) bfd_byte *loc; if (!bfd_malloc_and_get_section (ibfd, sec, &loc)) { - if (loc != NULL) - free (loc); + free (loc); error_ret: - if (local_syms != NULL - && symtab_hdr->contents != (unsigned char *) local_syms) + if (symtab_hdr->contents != (unsigned char *) local_syms) free (local_syms); if (elf_section_data (sec)->relocs != relstart) free (relstart); @@ -7247,7 +7345,7 @@ ppc64_elf_edit_opd (struct bfd_link_info *info) if (h != NULL && h->root.root.string[0] == '.') { - fdh = ((struct ppc_link_hash_entry *) h)->oh; + fdh = ppc_elf_hash_entry (h)->oh; if (fdh != NULL) { fdh = ppc_follow_link (fdh); @@ -7493,7 +7591,7 @@ ppc64_elf_inline_plt (struct bfd_link_info *info) return FALSE; relend = relstart + sec->reloc_count; - for (rel = relstart; rel < relend; ) + for (rel = relstart; rel < relend; rel++) { enum elf_ppc64_reloc_type r_type; unsigned long r_symndx; @@ -7513,8 +7611,7 @@ ppc64_elf_inline_plt (struct bfd_link_info *info) { if (elf_section_data (sec)->relocs != relstart) free (relstart); - if (local_syms != NULL - && symtab_hdr->contents != (bfd_byte *) local_syms) + if (symtab_hdr->contents != (bfd_byte *) local_syms) free (local_syms); return FALSE; } @@ -7563,6 +7660,7 @@ asection * ppc64_elf_tls_setup (struct bfd_link_info *info) { struct ppc_link_hash_table *htab; + struct elf_link_hash_entry *tga, *tga_fd, *desc, *desc_fd; htab = ppc_hash_table (info); if (htab == NULL) @@ -7599,18 +7697,29 @@ ppc64_elf_tls_setup (struct bfd_link_info *info) (_("warning: --plt-localentry is especially dangerous without " "ld.so support to detect ABI violations")); - htab->tls_get_addr = ((struct ppc_link_hash_entry *) - elf_link_hash_lookup (&htab->elf, ".__tls_get_addr", - FALSE, FALSE, TRUE)); + tga = elf_link_hash_lookup (&htab->elf, ".__tls_get_addr", + FALSE, FALSE, TRUE); + htab->tls_get_addr = ppc_elf_hash_entry (tga); + /* Move dynamic linking info to the function descriptor sym. */ - if (htab->tls_get_addr != NULL) - func_desc_adjust (&htab->tls_get_addr->elf, info); - htab->tls_get_addr_fd = ((struct ppc_link_hash_entry *) - elf_link_hash_lookup (&htab->elf, "__tls_get_addr", - FALSE, FALSE, TRUE)); + if (tga != NULL) + func_desc_adjust (tga, info); + tga_fd = elf_link_hash_lookup (&htab->elf, "__tls_get_addr", + FALSE, FALSE, TRUE); + htab->tls_get_addr_fd = ppc_elf_hash_entry (tga_fd); + + desc = elf_link_hash_lookup (&htab->elf, ".__tls_get_addr_desc", + FALSE, FALSE, TRUE); + htab->tga_desc = ppc_elf_hash_entry (desc); + if (desc != NULL) + func_desc_adjust (desc, info); + desc_fd = elf_link_hash_lookup (&htab->elf, "__tls_get_addr_desc", + FALSE, FALSE, TRUE); + htab->tga_desc_fd = ppc_elf_hash_entry (desc_fd); + if (htab->params->tls_get_addr_opt) { - struct elf_link_hash_entry *opt, *opt_fd, *tga, *tga_fd; + struct elf_link_hash_entry *opt, *opt_fd; opt = elf_link_hash_lookup (&htab->elf, ".__tls_get_addr_opt", FALSE, FALSE, TRUE); @@ -7626,24 +7735,49 @@ ppc64_elf_tls_setup (struct bfd_link_info *info) signalled by the presence of __tls_get_addr_opt, and we'll be calling __tls_get_addr via a plt call stub, then make __tls_get_addr point to __tls_get_addr_opt. */ - tga_fd = &htab->tls_get_addr_fd->elf; - if (htab->elf.dynamic_sections_created - && tga_fd != NULL - && (tga_fd->type == STT_FUNC - || tga_fd->needs_plt) - && !(SYMBOL_CALLS_LOCAL (info, tga_fd) - || UNDEFWEAK_NO_DYNAMIC_RELOC (info, tga_fd))) + if (!(htab->elf.dynamic_sections_created + && tga_fd != NULL + && (tga_fd->type == STT_FUNC + || tga_fd->needs_plt) + && !(SYMBOL_CALLS_LOCAL (info, tga_fd) + || UNDEFWEAK_NO_DYNAMIC_RELOC (info, tga_fd)))) + tga_fd = NULL; + if (!(htab->elf.dynamic_sections_created + && desc_fd != NULL + && (desc_fd->type == STT_FUNC + || desc_fd->needs_plt) + && !(SYMBOL_CALLS_LOCAL (info, desc_fd) + || UNDEFWEAK_NO_DYNAMIC_RELOC (info, desc_fd)))) + desc_fd = NULL; + + if (tga_fd != NULL || desc_fd != NULL) { - struct plt_entry *ent; + struct plt_entry *ent = NULL; - for (ent = tga_fd->plt.plist; ent != NULL; ent = ent->next) - if (ent->plt.refcount > 0) - break; + if (tga_fd != NULL) + for (ent = tga_fd->plt.plist; ent != NULL; ent = ent->next) + if (ent->plt.refcount > 0) + break; + if (ent == NULL && desc_fd != NULL) + for (ent = desc_fd->plt.plist; ent != NULL; ent = ent->next) + if (ent->plt.refcount > 0) + break; if (ent != NULL) { - 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); + if (tga_fd != NULL) + { + tga_fd->root.type = bfd_link_hash_indirect; + tga_fd->root.u.i.link = &opt_fd->root; + tga_fd->root.u.i.warning = NULL; + ppc64_elf_copy_indirect_symbol (info, opt_fd, tga_fd); + } + if (desc_fd != NULL) + { + desc_fd->root.type = bfd_link_hash_indirect; + desc_fd->root.u.i.link = &opt_fd->root; + desc_fd->root.u.i.warning = NULL; + ppc64_elf_copy_indirect_symbol (info, opt_fd, desc_fd); + } opt_fd->mark = 1; if (opt_fd->dynindx != -1) { @@ -7654,25 +7788,50 @@ ppc64_elf_tls_setup (struct bfd_link_info *info) if (!bfd_elf_link_record_dynamic_symbol (info, opt_fd)) return NULL; } - htab->tls_get_addr_fd - = (struct ppc_link_hash_entry *) opt_fd; - tga = &htab->tls_get_addr->elf; - if (opt != NULL && tga != NULL) + if (tga_fd != NULL) { - tga->root.type = bfd_link_hash_indirect; - tga->root.u.i.link = &opt->root; - ppc64_elf_copy_indirect_symbol (info, opt, tga); - opt->mark = 1; - _bfd_elf_link_hash_hide_symbol (info, opt, - tga->forced_local); - htab->tls_get_addr = (struct ppc_link_hash_entry *) opt; + htab->tls_get_addr_fd = ppc_elf_hash_entry (opt_fd); + tga = &htab->tls_get_addr->elf; + if (opt != NULL && tga != NULL) + { + tga->root.type = bfd_link_hash_indirect; + tga->root.u.i.link = &opt->root; + tga->root.u.i.warning = NULL; + ppc64_elf_copy_indirect_symbol (info, opt, tga); + opt->mark = 1; + _bfd_elf_link_hash_hide_symbol (info, opt, + tga->forced_local); + htab->tls_get_addr = ppc_elf_hash_entry (opt); + } + htab->tls_get_addr_fd->oh = htab->tls_get_addr; + htab->tls_get_addr_fd->is_func_descriptor = 1; + if (htab->tls_get_addr != NULL) + { + htab->tls_get_addr->oh = htab->tls_get_addr_fd; + htab->tls_get_addr->is_func = 1; + } } - htab->tls_get_addr_fd->oh = htab->tls_get_addr; - htab->tls_get_addr_fd->is_func_descriptor = 1; - if (htab->tls_get_addr != NULL) + if (desc_fd != NULL) { - htab->tls_get_addr->oh = htab->tls_get_addr_fd; - htab->tls_get_addr->is_func = 1; + htab->tga_desc_fd = ppc_elf_hash_entry (opt_fd); + if (opt != NULL && desc != NULL) + { + desc->root.type = bfd_link_hash_indirect; + desc->root.u.i.link = &opt->root; + desc->root.u.i.warning = NULL; + ppc64_elf_copy_indirect_symbol (info, opt, desc); + opt->mark = 1; + _bfd_elf_link_hash_hide_symbol (info, opt, + desc->forced_local); + htab->tga_desc = ppc_elf_hash_entry (opt); + } + htab->tga_desc_fd->oh = htab->tga_desc; + htab->tga_desc_fd->is_func_descriptor = 1; + if (htab->tga_desc != NULL) + { + htab->tga_desc->oh = htab->tga_desc_fd; + htab->tga_desc->is_func = 1; + } } } } @@ -7680,17 +7839,25 @@ ppc64_elf_tls_setup (struct bfd_link_info *info) else if (htab->params->tls_get_addr_opt < 0) htab->params->tls_get_addr_opt = 0; } + + if (htab->tga_desc_fd != NULL + && htab->params->tls_get_addr_opt + && htab->params->no_tls_get_addr_regsave == -1) + htab->params->no_tls_get_addr_regsave = 0; + return _bfd_elf_tls_setup (info->output_bfd, info); } /* Return TRUE iff REL is a branch reloc with a global symbol matching - HASH1 or HASH2. */ + any of HASH1, HASH2, HASH3, or HASH4. */ static bfd_boolean branch_reloc_hash_match (const bfd *ibfd, const Elf_Internal_Rela *rel, const struct ppc_link_hash_entry *hash1, - const struct ppc_link_hash_entry *hash2) + const struct ppc_link_hash_entry *hash2, + const struct ppc_link_hash_entry *hash3, + const struct ppc_link_hash_entry *hash4) { Elf_Internal_Shdr *symtab_hdr = &elf_symtab_hdr (ibfd); enum elf_ppc64_reloc_type r_type = ELF64_R_TYPE (rel->r_info); @@ -7703,7 +7870,8 @@ branch_reloc_hash_match (const bfd *ibfd, h = sym_hashes[r_symndx - symtab_hdr->sh_info]; h = elf_follow_link (h); - if (h == &hash1->elf || h == &hash2->elf) + if (h == &hash1->elf || h == &hash2->elf + || h == &hash3->elf || h == &hash4->elf) return TRUE; } return FALSE; @@ -7784,11 +7952,9 @@ ppc64_elf_tls_optimize (struct bfd_link_info *info) err_free_rel: if (elf_section_data (sec)->relocs != relstart) free (relstart); - if (toc_ref != NULL) - free (toc_ref); - if (locsyms != NULL - && (elf_symtab_hdr (ibfd).contents - != (unsigned char *) locsyms)) + free (toc_ref); + if (elf_symtab_hdr (ibfd).contents + != (unsigned char *) locsyms) free (locsyms); return ret; } @@ -7844,8 +8010,7 @@ ppc64_elf_tls_optimize (struct bfd_link_info *info) if (pass == 0 && sec->nomark_tls_get_addr && h != NULL - && (h == &htab->tls_get_addr->elf - || h == &htab->tls_get_addr_fd->elf) + && is_tls_get_addr (h, htab) && !found_tls_get_addr_arg && is_branch_reloc (r_type)) { @@ -7861,7 +8026,7 @@ ppc64_elf_tls_optimize (struct bfd_link_info *info) { case R_PPC64_GOT_TLSLD16: case R_PPC64_GOT_TLSLD16_LO: - case R_PPC64_GOT_TLSLD34: + case R_PPC64_GOT_TLSLD_PCREL34: expecting_tls_get_addr = 1; found_tls_get_addr_arg = 1; /* Fall through. */ @@ -7882,7 +8047,7 @@ ppc64_elf_tls_optimize (struct bfd_link_info *info) case R_PPC64_GOT_TLSGD16: case R_PPC64_GOT_TLSGD16_LO: - case R_PPC64_GOT_TLSGD34: + case R_PPC64_GOT_TLSGD_PCREL34: expecting_tls_get_addr = 1; found_tls_get_addr_arg = 1; /* Fall through. */ @@ -7899,7 +8064,7 @@ ppc64_elf_tls_optimize (struct bfd_link_info *info) tls_type = TLS_TLS | TLS_GD; break; - case R_PPC64_GOT_TPREL34: + case R_PPC64_GOT_TPREL_PCREL34: case R_PPC64_GOT_TPREL16_DS: case R_PPC64_GOT_TPREL16_LO_DS: case R_PPC64_GOT_TPREL16_HI: @@ -8051,8 +8216,10 @@ ppc64_elf_tls_optimize (struct bfd_link_info *info) if (rel + 1 < relend && branch_reloc_hash_match (ibfd, rel + 1, + htab->tls_get_addr_fd, + htab->tga_desc_fd, htab->tls_get_addr, - htab->tls_get_addr_fd)) + htab->tga_desc)) { if (expecting_tls_get_addr == 2) { @@ -8107,15 +8274,29 @@ ppc64_elf_tls_optimize (struct bfd_link_info *info) { struct plt_entry *ent = NULL; - if (htab->tls_get_addr != NULL) + if (htab->tls_get_addr_fd != NULL) + for (ent = htab->tls_get_addr_fd->elf.plt.plist; + ent != NULL; + ent = ent->next) + if (ent->addend == 0) + break; + + if (ent == NULL && htab->tga_desc_fd != NULL) + for (ent = htab->tga_desc_fd->elf.plt.plist; + ent != NULL; + ent = ent->next) + if (ent->addend == 0) + break; + + if (ent == NULL && htab->tls_get_addr != NULL) for (ent = htab->tls_get_addr->elf.plt.plist; ent != NULL; ent = ent->next) if (ent->addend == 0) break; - if (ent == NULL && htab->tls_get_addr_fd != NULL) - for (ent = htab->tls_get_addr_fd->elf.plt.plist; + if (ent == NULL && htab->tga_desc != NULL) + for (ent = htab->tga_desc->elf.plt.plist; ent != NULL; ent = ent->next) if (ent->addend == 0) @@ -8188,8 +8369,7 @@ ppc64_elf_tls_optimize (struct bfd_link_info *info) } } - if (toc_ref != NULL) - free (toc_ref); + free (toc_ref); htab->do_tls_opt = 1; return TRUE; } @@ -8220,7 +8400,7 @@ adjust_toc_syms (struct elf_link_hash_entry *h, void *inf) && h->root.type != bfd_link_hash_defweak) return TRUE; - eh = (struct ppc_link_hash_entry *) h; + eh = ppc_elf_hash_entry (h); if (eh->adjust_done) return TRUE; @@ -8256,34 +8436,34 @@ adjust_toc_syms (struct elf_link_hash_entry *h, void *inf) static bfd_boolean ok_lo_toc_insn (unsigned int insn, enum elf_ppc64_reloc_type r_type) { - return ((insn & (0x3f << 26)) == 12u << 26 /* addic */ - || (insn & (0x3f << 26)) == 14u << 26 /* addi */ - || (insn & (0x3f << 26)) == 32u << 26 /* lwz */ - || (insn & (0x3f << 26)) == 34u << 26 /* lbz */ - || (insn & (0x3f << 26)) == 36u << 26 /* stw */ - || (insn & (0x3f << 26)) == 38u << 26 /* stb */ - || (insn & (0x3f << 26)) == 40u << 26 /* lhz */ - || (insn & (0x3f << 26)) == 42u << 26 /* lha */ - || (insn & (0x3f << 26)) == 44u << 26 /* sth */ - || (insn & (0x3f << 26)) == 46u << 26 /* lmw */ - || (insn & (0x3f << 26)) == 47u << 26 /* stmw */ - || (insn & (0x3f << 26)) == 48u << 26 /* lfs */ - || (insn & (0x3f << 26)) == 50u << 26 /* lfd */ - || (insn & (0x3f << 26)) == 52u << 26 /* stfs */ - || (insn & (0x3f << 26)) == 54u << 26 /* stfd */ - || (insn & (0x3f << 26)) == 56u << 26 /* lq,lfq */ - || ((insn & (0x3f << 26)) == 57u << 26 /* lxsd,lxssp,lfdp */ + return ((insn & (0x3fu << 26)) == 12u << 26 /* addic */ + || (insn & (0x3fu << 26)) == 14u << 26 /* addi */ + || (insn & (0x3fu << 26)) == 32u << 26 /* lwz */ + || (insn & (0x3fu << 26)) == 34u << 26 /* lbz */ + || (insn & (0x3fu << 26)) == 36u << 26 /* stw */ + || (insn & (0x3fu << 26)) == 38u << 26 /* stb */ + || (insn & (0x3fu << 26)) == 40u << 26 /* lhz */ + || (insn & (0x3fu << 26)) == 42u << 26 /* lha */ + || (insn & (0x3fu << 26)) == 44u << 26 /* sth */ + || (insn & (0x3fu << 26)) == 46u << 26 /* lmw */ + || (insn & (0x3fu << 26)) == 47u << 26 /* stmw */ + || (insn & (0x3fu << 26)) == 48u << 26 /* lfs */ + || (insn & (0x3fu << 26)) == 50u << 26 /* lfd */ + || (insn & (0x3fu << 26)) == 52u << 26 /* stfs */ + || (insn & (0x3fu << 26)) == 54u << 26 /* stfd */ + || (insn & (0x3fu << 26)) == 56u << 26 /* lq,lfq */ + || ((insn & (0x3fu << 26)) == 57u << 26 /* lxsd,lxssp,lfdp */ /* Exclude lfqu by testing reloc. If relocs are ever defined for the reduced D field in psq_lu then those will need testing too. */ && r_type != R_PPC64_TOC16_LO && r_type != R_PPC64_GOT16_LO) - || ((insn & (0x3f << 26)) == 58u << 26 /* ld,lwa */ + || ((insn & (0x3fu << 26)) == 58u << 26 /* ld,lwa */ && (insn & 1) == 0) - || (insn & (0x3f << 26)) == 60u << 26 /* stfq */ - || ((insn & (0x3f << 26)) == 61u << 26 /* lxv,stx{v,sd,ssp},stfdp */ + || (insn & (0x3fu << 26)) == 60u << 26 /* stfq */ + || ((insn & (0x3fu << 26)) == 61u << 26 /* lxv,stx{v,sd,ssp},stfdp */ /* Exclude stfqu. psq_stu as above for psq_lu. */ && r_type != R_PPC64_TOC16_LO && r_type != R_PPC64_GOT16_LO) - || ((insn & (0x3f << 26)) == 62u << 26 /* std,stq */ + || ((insn & (0x3fu << 26)) == 62u << 26 /* std,stq */ && (insn & 1) == 0)); } @@ -8399,6 +8579,15 @@ xlate_pcrel_opt (uint64_t *pinsn1, uint64_t *pinsn2, bfd_signed_vma *poff) off = insn2 & 0xffff; break; + case 6: /* lxvp, stxvp */ + if ((insn2 & 0xe) != 0) + return FALSE; + insn1 = ((1ULL << 58) | (1ULL << 52) + | ((insn2 & 1) == 0 ? 58ULL << 26 : 62ULL << 26) + | (insn2 & (31ULL << 21))); + off = insn2 & 0xfff0; + break; + case 62: /* std, stq */ if ((insn2 & 1) != 0) return FALSE; @@ -8620,18 +8809,14 @@ ppc64_elf_edit_toc (struct bfd_link_info *info) if (used == NULL) { error_ret: - if (local_syms != NULL - && symtab_hdr->contents != (unsigned char *) local_syms) + if (symtab_hdr->contents != (unsigned char *) local_syms) free (local_syms); if (sec != NULL - && relstart != NULL && elf_section_data (sec)->relocs != relstart) free (relstart); - if (toc_relocs != NULL - && elf_section_data (toc)->relocs != toc_relocs) + if (elf_section_data (toc)->relocs != toc_relocs) free (toc_relocs); - if (skip != NULL) - free (skip); + free (skip); return FALSE; } @@ -8998,8 +9183,7 @@ ppc64_elf_edit_toc (struct bfd_link_info *info) rel_hdr->sh_size = toc->reloc_count * sz; } } - else if (toc_relocs != NULL - && elf_section_data (toc)->relocs != toc_relocs) + else if (elf_section_data (toc)->relocs != toc_relocs) free (toc_relocs); if (local_syms != NULL @@ -9050,11 +9234,9 @@ ppc64_elf_edit_toc (struct bfd_link_info *info) if (relstart == NULL) { got_error_ret: - if (local_syms != NULL - && symtab_hdr->contents != (unsigned char *) local_syms) + if (symtab_hdr->contents != (unsigned char *) local_syms) free (local_syms); if (sec != NULL - && relstart != NULL && elf_section_data (sec)->relocs != relstart) free (relstart); return FALSE; @@ -9114,7 +9296,7 @@ ppc64_elf_edit_toc (struct bfd_link_info *info) insn = bfd_get_32 (ibfd, buf); if (insn_check == check_lo ? !ok_lo_toc_insn (insn, r_type) - : ((insn & ((0x3f << 26) | 0x1f << 16)) + : ((insn & ((0x3fu << 26) | 0x1f << 16)) != ((15u << 26) | (2 << 16)) /* addis rt,2,imm */)) { char str[12]; @@ -9157,6 +9339,9 @@ ppc64_elf_edit_toc (struct bfd_link_info *info) || discarded_section (sym_sec)) continue; + if ((h ? h->type : ELF_ST_TYPE (sym->st_info)) == STT_GNU_IFUNC) + continue; + if (!SYMBOL_REFERENCES_LOCAL (info, h)) continue; @@ -9185,7 +9370,7 @@ ppc64_elf_edit_toc (struct bfd_link_info *info) rel->r_offset & ~3, 4)) goto got_error_ret; insn = bfd_get_32 (ibfd, buf); - if (((insn & ((0x3f << 26) | 0x1f << 16)) + if (((insn & ((0x3fu << 26) | 0x1f << 16)) != ((15u << 26) | (2 << 16)) /* addis rt,2,imm */)) continue; break; @@ -9198,7 +9383,7 @@ ppc64_elf_edit_toc (struct bfd_link_info *info) rel->r_offset & ~3, 4)) goto got_error_ret; insn = bfd_get_32 (ibfd, buf); - if ((insn & (0x3f << 26 | 0x3)) != 58u << 26 /* ld */) + if ((insn & (0x3fu << 26 | 0x3)) != 58u << 26 /* ld */) continue; break; @@ -9215,7 +9400,7 @@ ppc64_elf_edit_toc (struct bfd_link_info *info) if ((insn & (-1u << 18)) != ((1u << 26) | (1u << 20))) continue; insn = bfd_get_32 (ibfd, buf + 4); - if ((insn & (0x3f << 26)) != 57u << 26) + if ((insn & (0x3fu << 26)) != 57u << 26) continue; break; } @@ -9272,7 +9457,7 @@ allocate_got (struct elf_link_hash_entry *h, struct got_entry *gent) { struct ppc_link_hash_table *htab = ppc_hash_table (info); - struct ppc_link_hash_entry *eh = (struct ppc_link_hash_entry *) h; + struct ppc_link_hash_entry *eh = ppc_elf_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 @@ -9360,7 +9545,7 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf) if (htab == NULL) return FALSE; - eh = (struct ppc_link_hash_entry *) h; + eh = ppc_elf_hash_entry (h); /* Run through the TLS GD got entries first if we're changing them to TPREL. */ if ((eh->tls_mask & (TLS_TLS | TLS_GDIE)) == (TLS_TLS | TLS_GDIE)) @@ -9426,19 +9611,19 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf) IFUNCs which are handled even in static executables. */ if (!htab->elf.dynamic_sections_created && h->type != STT_GNU_IFUNC) - eh->dyn_relocs = NULL; + h->dyn_relocs = NULL; /* Discard relocs on undefined symbols that must be local. */ else if (h->root.type == bfd_link_hash_undefined && ELF_ST_VISIBILITY (h->other) != STV_DEFAULT) - eh->dyn_relocs = NULL; + h->dyn_relocs = NULL; /* Also discard relocs on undefined weak syms with non-default visibility, or when dynamic_undefined_weak says so. */ else if (UNDEFWEAK_NO_DYNAMIC_RELOC (info, h)) - eh->dyn_relocs = NULL; + h->dyn_relocs = NULL; - if (eh->dyn_relocs != NULL) + if (h->dyn_relocs != NULL) { struct elf_dyn_relocs *p, **pp; @@ -9458,7 +9643,7 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf) avoid writing weird assembly. */ if (SYMBOL_CALLS_LOCAL (info, h)) { - for (pp = &eh->dyn_relocs; (p = *pp) != NULL; ) + for (pp = &h->dyn_relocs; (p = *pp) != NULL; ) { p->count -= p->pc_count; p->pc_count = 0; @@ -9469,7 +9654,7 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf) } } - if (eh->dyn_relocs != NULL) + if (h->dyn_relocs != NULL) { /* Ensure we catch all the cases where this symbol should be made dynamic. */ @@ -9493,14 +9678,14 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf) /* But if that didn't work out, discard dynamic relocs. */ if (h->dynindx == -1) - eh->dyn_relocs = NULL; + h->dyn_relocs = NULL; } else - eh->dyn_relocs = NULL; + h->dyn_relocs = NULL; } /* Finally, allocate space. */ - for (p = eh->dyn_relocs; p != NULL; p = p->next) + for (p = h->dyn_relocs; p != NULL; p = p->next) { asection *sreloc = elf_section_data (p->sec)->sreloc; if (eh->elf.type == STT_GNU_IFUNC) @@ -9521,7 +9706,7 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf) && h->def_regular && !htab->elf.dynamic_sections_created && !htab->can_convert_all_inline_plt - && (((struct ppc_link_hash_entry *) h)->tls_mask + && (ppc_elf_hash_entry (h)->tls_mask & (TLS_TLS | PLT_KEEP)) == PLT_KEEP)) { struct plt_entry *pent; @@ -9679,33 +9864,6 @@ size_global_entry_stubs (struct elf_link_hash_entry *h, void *inf) return TRUE; } -/* Set DF_TEXTREL if we find any dynamic relocs that apply to - read-only sections. */ - -static bfd_boolean -maybe_set_textrel (struct elf_link_hash_entry *h, void *inf) -{ - asection *sec; - - if (h->root.type == bfd_link_hash_indirect) - return TRUE; - - sec = readonly_dynrelocs (h); - if (sec != NULL) - { - struct bfd_link_info *info = (struct bfd_link_info *) inf; - - info->flags |= DF_TEXTREL; - info->callbacks->minfo (_("%pB: dynamic relocation against `%pT'" - " in read-only section `%pA'\n"), - sec->owner, h->root.root.string, sec); - - /* Not an error, just cut short the traversal. */ - return FALSE; - } - return TRUE; -} - /* Set the sizes of the dynamic sections. */ static bfd_boolean @@ -10061,8 +10219,10 @@ ppc64_elf_size_dynamic_sections (bfd *output_bfd, } tls_opt = (htab->params->tls_get_addr_opt - && htab->tls_get_addr_fd != NULL - && htab->tls_get_addr_fd->elf.plt.plist != NULL); + && ((htab->tls_get_addr_fd != NULL + && htab->tls_get_addr_fd->elf.plt.plist != NULL) + || (htab->tga_desc_fd != NULL + && htab->tga_desc_fd->elf.plt.plist != NULL))); if (tls_opt || !htab->opd_abi) { if (!add_dynamic_entry (DT_PPC64_OPT, tls_opt ? PPC64_OPT_TLS : 0)) @@ -10079,7 +10239,8 @@ ppc64_elf_size_dynamic_sections (bfd *output_bfd, /* If any dynamic relocs apply to a read-only section, then we need a DT_TEXTREL entry. */ if ((info->flags & DF_TEXTREL) == 0) - elf_link_hash_traverse (&htab->elf, maybe_set_textrel, info); + elf_link_hash_traverse (&htab->elf, + _bfd_elf_maybe_set_textrel, info); if ((info->flags & DF_TEXTREL) != 0) { @@ -10386,7 +10547,7 @@ emit_relocs_for_offset (struct bfd_link_info *info, Elf_Internal_Rela *r, } static bfd_byte * -build_powerxx_offset (bfd *abfd, bfd_byte *p, bfd_vma off, int odd, +build_power10_offset (bfd *abfd, bfd_byte *p, bfd_vma off, int odd, bfd_boolean load) { uint64_t insn; @@ -10468,7 +10629,7 @@ build_powerxx_offset (bfd *abfd, bfd_byte *p, bfd_vma off, int odd, } static unsigned int -size_powerxx_offset (bfd_vma off, int odd) +size_power10_offset (bfd_vma off, int odd) { if (off - odd + (1ULL << 33) < 1ULL << 34) return odd + 8; @@ -10479,7 +10640,7 @@ size_powerxx_offset (bfd_vma off, int odd) } static unsigned int -num_relocs_for_powerxx_offset (bfd_vma off, int odd) +num_relocs_for_power10_offset (bfd_vma off, int odd) { if (off - odd + (1ULL << 33) < 1ULL << 34) return 1; @@ -10490,7 +10651,7 @@ num_relocs_for_powerxx_offset (bfd_vma off, int odd) } static Elf_Internal_Rela * -emit_relocs_for_powerxx_offset (struct bfd_link_info *info, +emit_relocs_for_power10_offset (struct bfd_link_info *info, Elf_Internal_Rela *r, bfd_vma roff, bfd_vma targ, bfd_vma off, int odd) { @@ -10602,14 +10763,14 @@ plt_stub_size (struct ppc_link_hash_table *htab, if (stub_entry->stub_type >= ppc_stub_plt_call_notoc) { - if (htab->powerxx_stubs) + if (htab->power10_stubs) { bfd_vma start = (stub_entry->stub_offset + stub_entry->group->stub_sec->output_offset + stub_entry->group->stub_sec->output_section->vma); if (stub_entry->stub_type > ppc_stub_plt_call_notoc) start += 4; - size = 8 + size_powerxx_offset (off, start & 4); + size = 8 + size_power10_offset (off, start & 4); } else size = 8 + size_offset (off - 8); @@ -10638,13 +10799,21 @@ plt_stub_size (struct ppc_link_hash_table *htab, size += 4; } if (stub_entry->h != NULL - && (stub_entry->h == htab->tls_get_addr_fd - || stub_entry->h == htab->tls_get_addr) + && is_tls_get_addr (&stub_entry->h->elf, htab) && htab->params->tls_get_addr_opt) { - size += 7 * 4; - if (stub_entry->stub_type == ppc_stub_plt_call_r2save) - size += 6 * 4; + if (htab->params->no_tls_get_addr_regsave) + { + size += 7 * 4; + if (stub_entry->stub_type == ppc_stub_plt_call_r2save) + size += 6 * 4; + } + else + { + size += 30 * 4; + if (stub_entry->stub_type == ppc_stub_plt_call_r2save) + size += 4; + } } return size; } @@ -10700,8 +10869,7 @@ build_plt_stub (struct ppc_link_hash_table *htab, if (!ALWAYS_USE_FAKE_DEP && plt_load_toc && plt_thread_safe - && !((stub_entry->h == htab->tls_get_addr_fd - || stub_entry->h == htab->tls_get_addr) + && !(is_tls_get_addr (&stub_entry->h->elf, htab) && htab->params->tls_get_addr_opt)) { bfd_vma pltoff = stub_entry->plt_ent->plt.offset & ~1; @@ -10860,17 +11028,14 @@ build_plt_stub (struct ppc_link_hash_table *htab, /* Build a special .plt call stub for __tls_get_addr. */ -#define LD_R11_0R3 0xe9630000 +#define LD_R0_0R3 0xe8030000 #define LD_R12_0R3 0xe9830000 #define MR_R0_R3 0x7c601b78 -#define CMPDI_R11_0 0x2c2b0000 +#define CMPDI_R0_0 0x2c200000 #define ADD_R3_R12_R13 0x7c6c6a14 #define BEQLR 0x4d820020 #define MR_R3_R0 0x7c030378 -#define STD_R11_0R1 0xf9610000 #define BCTRL 0x4e800421 -#define LD_R11_0R1 0xe9610000 -#define MTLR_R11 0x7d6803a6 static inline bfd_byte * build_tls_get_addr_stub (struct ppc_link_hash_table *htab, @@ -10879,48 +11044,121 @@ build_tls_get_addr_stub (struct ppc_link_hash_table *htab, { bfd *obfd = htab->params->stub_bfd; bfd_byte *loc = p; + unsigned int i; - bfd_put_32 (obfd, LD_R11_0R3 + 0, p), p += 4; + bfd_put_32 (obfd, LD_R0_0R3 + 0, p), p += 4; bfd_put_32 (obfd, LD_R12_0R3 + 8, p), p += 4; + bfd_put_32 (obfd, CMPDI_R0_0, p), p += 4; bfd_put_32 (obfd, MR_R0_R3, p), p += 4; - bfd_put_32 (obfd, CMPDI_R11_0, p), p += 4; bfd_put_32 (obfd, ADD_R3_R12_R13, p), p += 4; bfd_put_32 (obfd, BEQLR, p), p += 4; bfd_put_32 (obfd, MR_R3_R0, p), p += 4; - if (r != NULL) - r[0].r_offset += 7 * 4; - if (stub_entry->stub_type != ppc_stub_plt_call_r2save) - return build_plt_stub (htab, stub_entry, p, offset, r); + if (htab->params->no_tls_get_addr_regsave) + { + if (r != NULL) + r[0].r_offset += 7 * 4; + if (stub_entry->stub_type != ppc_stub_plt_call_r2save) + return build_plt_stub (htab, stub_entry, p, offset, r); + + bfd_put_32 (obfd, MFLR_R0, p); + p += 4; + bfd_put_32 (obfd, STD_R0_0R1 + STK_LINKER (htab), p); + p += 4; + + if (r != NULL) + r[0].r_offset += 2 * 4; + p = build_plt_stub (htab, stub_entry, p, offset, r); + bfd_put_32 (obfd, BCTRL, p - 4); + + bfd_put_32 (obfd, LD_R2_0R1 + STK_TOC (htab), p); + p += 4; + bfd_put_32 (obfd, LD_R0_0R1 + STK_LINKER (htab), p); + p += 4; + bfd_put_32 (obfd, MTLR_R0, p); + p += 4; + bfd_put_32 (obfd, BLR, p); + p += 4; + } + else + { + p = tls_get_addr_prologue (obfd, p, htab); - bfd_put_32 (obfd, MFLR_R11, p), p += 4; - bfd_put_32 (obfd, STD_R11_0R1 + STK_LINKER (htab), p), p += 4; + if (r != NULL) + r[0].r_offset += 18 * 4; - if (r != NULL) - r[0].r_offset += 2 * 4; - p = build_plt_stub (htab, stub_entry, p, offset, r); - bfd_put_32 (obfd, BCTRL, p - 4); + p = build_plt_stub (htab, stub_entry, p, offset, r); + bfd_put_32 (obfd, BCTRL, p - 4); - bfd_put_32 (obfd, LD_R2_0R1 + STK_TOC (htab), p), p += 4; - bfd_put_32 (obfd, LD_R11_0R1 + STK_LINKER (htab), p), p += 4; - bfd_put_32 (obfd, MTLR_R11, p), p += 4; - bfd_put_32 (obfd, BLR, p), p += 4; + if (stub_entry->stub_type == ppc_stub_plt_call_r2save) + { + bfd_put_32 (obfd, LD_R2_0R1 + STK_TOC (htab), p); + p += 4; + } + + p = tls_get_addr_epilogue (obfd, p, htab); + } if (htab->glink_eh_frame != NULL && htab->glink_eh_frame->size != 0) { bfd_byte *base, *eh; - unsigned int lr_used, delta; base = htab->glink_eh_frame->contents + stub_entry->group->eh_base + 17; eh = base + stub_entry->group->eh_size; - lr_used = stub_entry->stub_offset + (p - 20 - loc); - delta = lr_used - stub_entry->group->lr_restore; - stub_entry->group->lr_restore = lr_used + 16; - eh = eh_advance (htab->elf.dynobj, eh, delta); - *eh++ = DW_CFA_offset_extended_sf; - *eh++ = 65; - *eh++ = -(STK_LINKER (htab) / 8) & 0x7f; - *eh++ = DW_CFA_advance_loc + 4; + if (htab->params->no_tls_get_addr_regsave) + { + unsigned int lr_used, delta; + lr_used = stub_entry->stub_offset + (p - 20 - loc); + delta = lr_used - stub_entry->group->lr_restore; + stub_entry->group->lr_restore = lr_used + 16; + eh = eh_advance (htab->elf.dynobj, eh, delta); + *eh++ = DW_CFA_offset_extended_sf; + *eh++ = 65; + *eh++ = -(STK_LINKER (htab) / 8) & 0x7f; + *eh++ = DW_CFA_advance_loc + 4; + } + else + { + unsigned int cfa_updt, delta; + /* After the bctrl, lr has been modified so we need to emit + .eh_frame info saying the return address is on the stack. In + fact we must put the EH info at or before the call rather + than after it, because the EH info for a call needs to be + specified by that point. + See libgcc/unwind-dw2.c execute_cfa_program. + Any stack pointer update must be described immediately after + the instruction making the change, and since the stdu occurs + after saving regs we put all the reg saves and the cfa + change there. */ + cfa_updt = stub_entry->stub_offset + 18 * 4; + delta = cfa_updt - stub_entry->group->lr_restore; + stub_entry->group->lr_restore + = stub_entry->stub_offset + (p - loc) - 4; + eh = eh_advance (htab->elf.dynobj, eh, delta); + *eh++ = DW_CFA_def_cfa_offset; + if (htab->opd_abi) + { + *eh++ = 128; + *eh++ = 1; + } + else + *eh++ = 96; + *eh++ = DW_CFA_offset_extended_sf; + *eh++ = 65; + *eh++ = (-16 / 8) & 0x7f; + for (i = 4; i < 12; i++) + { + *eh++ = DW_CFA_offset + i; + *eh++ = (htab->opd_abi ? 13 : 12) - i; + } + *eh++ = (DW_CFA_advance_loc + + (stub_entry->group->lr_restore - 8 - cfa_updt) / 4); + *eh++ = DW_CFA_def_cfa_offset; + *eh++ = 0; + for (i = 4; i < 12; i++) + *eh++ = DW_CFA_restore + i; + *eh++ = DW_CFA_advance_loc + 2; + } *eh++ = DW_CFA_restore_extended; *eh++ = 65; stub_entry->group->eh_size = eh - base; @@ -10997,9 +11235,7 @@ use_global_in_relocs (struct ppc_link_hash_table *htab, h = ppc_follow_link (h->oh); BFD_ASSERT (h->elf.root.type == bfd_link_hash_defined || h->elf.root.type == bfd_link_hash_defweak); - symval = (h->elf.root.u.def.value - + h->elf.root.u.def.section->output_offset - + h->elf.root.u.def.section->output_section->vma); + symval = defined_sym_val (&h->elf); while (num_rel-- != 0) { r->r_info = ELF64_R_INFO (symndx, ELF64_R_TYPE (r->r_info)); @@ -11071,6 +11307,25 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg) stub_entry = (struct ppc_stub_hash_entry *) gen_entry; info = in_arg; + /* Fail if the target section could not be assigned to an output + section. The user should fix his linker script. */ + if (stub_entry->target_section != NULL + && stub_entry->target_section->output_section == NULL + && info->non_contiguous_regions) + info->callbacks->einfo (_("%F%P: Could not assign '%pA' to an output section. " + "Retry without --enable-non-contiguous-regions.\n"), + stub_entry->target_section); + + /* Same for the group. */ + if (stub_entry->group->stub_sec != NULL + && stub_entry->group->stub_sec->output_section == NULL + && info->non_contiguous_regions) + info->callbacks->einfo (_("%F%P: Could not assign group %pA target %pA to an " + "output section. Retry without " + "--enable-non-contiguous-regions.\n"), + stub_entry->group->stub_sec, + stub_entry->target_section); + htab = ppc_hash_table (info); if (htab == NULL) return FALSE; @@ -11349,10 +11604,10 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg) relp = p; num_rel = 0; - if (htab->powerxx_stubs) + if (htab->power10_stubs) { bfd_boolean load = stub_entry->stub_type >= ppc_stub_plt_call_notoc; - p = build_powerxx_offset (htab->params->stub_bfd, p, off, odd, load); + p = build_power10_offset (htab->params->stub_bfd, p, off, odd, load); } else { @@ -11388,8 +11643,8 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg) if (info->emitrelocations) { bfd_vma roff = relp - stub_entry->group->stub_sec->contents; - if (htab->powerxx_stubs) - num_rel += num_relocs_for_powerxx_offset (off, odd); + if (htab->power10_stubs) + num_rel += num_relocs_for_power10_offset (off, odd); else { num_rel += num_relocs_for_offset (off); @@ -11398,8 +11653,8 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg) r = get_relocs (stub_entry->group->stub_sec, num_rel); if (r == NULL) return FALSE; - if (htab->powerxx_stubs) - r = emit_relocs_for_powerxx_offset (info, r, roff, targ, off, odd); + if (htab->power10_stubs) + r = emit_relocs_for_power10_offset (info, r, roff, targ, off, odd); else r = emit_relocs_for_offset (info, r, roff, targ, off); if (stub_entry->stub_type == ppc_stub_long_branch_notoc @@ -11416,7 +11671,7 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg) } } - if (!htab->powerxx_stubs + if (!htab->power10_stubs && htab->glink_eh_frame != NULL && htab->glink_eh_frame->size != 0) { @@ -11511,8 +11766,7 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg) r[0].r_addend = targ; } if (stub_entry->h != NULL - && (stub_entry->h == htab->tls_get_addr_fd - || stub_entry->h == htab->tls_get_addr) + && is_tls_get_addr (&stub_entry->h->elf, htab) && htab->params->tls_get_addr_opt) p = build_tls_get_addr_stub (htab, stub_entry, loc, off, r); else @@ -11597,6 +11851,25 @@ ppc_size_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg) if (htab == NULL) return FALSE; + /* Fail if the target section could not be assigned to an output + section. The user should fix his linker script. */ + if (stub_entry->target_section != NULL + && stub_entry->target_section->output_section == NULL + && info->non_contiguous_regions) + info->callbacks->einfo (_("%F%P: Could not assign %pA to an output section. " + "Retry without --enable-non-contiguous-regions.\n"), + stub_entry->target_section); + + /* Same for the group. */ + if (stub_entry->group->stub_sec != NULL + && stub_entry->group->stub_sec->output_section == NULL + && info->non_contiguous_regions) + info->callbacks->einfo (_("%F%P: Could not assign group %pA target %pA to an " + "output section. Retry without " + "--enable-non-contiguous-regions.\n"), + stub_entry->group->stub_sec, + stub_entry->target_section); + /* Make a note of the offset within the stubs for this entry. */ stub_entry->stub_offset = stub_entry->group->stub_sec->size; @@ -11746,16 +12019,16 @@ ppc_size_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg) if (info->emitrelocations) { unsigned int num_rel; - if (htab->powerxx_stubs) - num_rel = num_relocs_for_powerxx_offset (off, odd); + if (htab->power10_stubs) + num_rel = num_relocs_for_power10_offset (off, odd); else num_rel = num_relocs_for_offset (off - 8); stub_entry->group->stub_sec->reloc_count += num_rel; stub_entry->group->stub_sec->flags |= SEC_RELOC; } - if (htab->powerxx_stubs) - extra = size_powerxx_offset (off, odd); + if (htab->power10_stubs) + extra = size_power10_offset (off, odd); else extra = size_offset (off - 8); /* Include branch insn plus those in the offset sequence. */ @@ -11765,7 +12038,7 @@ ppc_size_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg) calculated. */ off -= extra; - if (!htab->powerxx_stubs) + if (!htab->power10_stubs) { /* After the bcl, lr has been modified so we need to emit .eh_frame info saying the return address is in r12. */ @@ -11828,8 +12101,8 @@ ppc_size_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg) if (info->emitrelocations) { unsigned int num_rel; - if (htab->powerxx_stubs) - num_rel = num_relocs_for_powerxx_offset (off, odd); + if (htab->power10_stubs) + num_rel = num_relocs_for_power10_offset (off, odd); else num_rel = num_relocs_for_offset (off - 8); stub_entry->group->stub_sec->reloc_count += num_rel; @@ -11838,7 +12111,7 @@ ppc_size_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg) size = plt_stub_size (htab, stub_entry, off); - if (!htab->powerxx_stubs) + if (!htab->power10_stubs) { /* After the bcl, lr has been modified so we need to emit .eh_frame info saying the return address is in r12. */ @@ -11897,24 +12170,27 @@ ppc_size_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg) size = plt_stub_size (htab, stub_entry, off); if (stub_entry->h != NULL - && (stub_entry->h == htab->tls_get_addr_fd - || stub_entry->h == htab->tls_get_addr) + && is_tls_get_addr (&stub_entry->h->elf, htab) && htab->params->tls_get_addr_opt && stub_entry->stub_type == ppc_stub_plt_call_r2save) { - /* After the bctrl, lr has been modified so we need to - emit .eh_frame info saying the return address is - on the stack. In fact we put the EH info specifying - that the return address is on the stack *at* the - call rather than after it, because the EH info for a - call needs to be specified by that point. - See libgcc/unwind-dw2.c execute_cfa_program. */ - lr_used = stub_entry->stub_offset + size - 20; - /* The eh_frame info will consist of a DW_CFA_advance_loc - or variant, DW_CFA_offset_externed_sf, 65, -stackoff, - DW_CFA_advance_loc+4, DW_CFA_restore_extended, 65. */ - delta = lr_used - stub_entry->group->lr_restore; - stub_entry->group->eh_size += eh_advance_size (delta) + 6; + if (htab->params->no_tls_get_addr_regsave) + { + lr_used = stub_entry->stub_offset + size - 20; + /* The eh_frame info will consist of a DW_CFA_advance_loc + or variant, DW_CFA_offset_externed_sf, 65, -stackoff, + DW_CFA_advance_loc+4, DW_CFA_restore_extended, 65. */ + delta = lr_used - stub_entry->group->lr_restore; + stub_entry->group->eh_size += eh_advance_size (delta) + 6; + } + else + { + /* Adjustments to r1 need to be described. */ + unsigned int cfa_updt = stub_entry->stub_offset + 18 * 4; + delta = cfa_updt - stub_entry->group->lr_restore; + stub_entry->group->eh_size += eh_advance_size (delta); + stub_entry->group->eh_size += htab->opd_abi ? 36 : 35; + } stub_entry->group->lr_restore = size - 4; } break; @@ -11936,7 +12212,7 @@ int ppc64_elf_setup_section_lists (struct bfd_link_info *info) { unsigned int id; - bfd_size_type amt; + size_t amt; struct ppc_link_hash_table *htab = ppc_hash_table (info); if (htab == NULL) @@ -12346,7 +12622,7 @@ toc_adjusting_stub_needed (struct bfd_link_info *info, asection *isec) /* Calls to dynamic lib functions go through a plt call stub that uses r2. */ - eh = (struct ppc_link_hash_entry *) h; + eh = ppc_elf_hash_entry (h); if (eh != NULL && (eh->elf.plt.plist != NULL || (eh->oh != NULL @@ -12457,9 +12733,8 @@ toc_adjusting_stub_needed (struct bfd_link_info *info, asection *isec) } } - if (local_syms != NULL - && (elf_symtab_hdr (isec->owner).contents - != (unsigned char *) local_syms)) + if (elf_symtab_hdr (isec->owner).contents + != (unsigned char *) local_syms) free (local_syms); if (elf_section_data (isec)->relocs != relstart) free (relstart); @@ -12814,6 +13089,40 @@ ppc64_elf_size_stubs (struct bfd_link_info *info) if (!group_sections (info, stub_group_size, stubs_always_before_branch)) return FALSE; + htab->tga_group = NULL; + if (!htab->params->no_tls_get_addr_regsave + && htab->tga_desc_fd != NULL + && (htab->tga_desc_fd->elf.root.type == bfd_link_hash_undefined + || htab->tga_desc_fd->elf.root.type == bfd_link_hash_undefweak) + && htab->tls_get_addr_fd != NULL + && is_static_defined (&htab->tls_get_addr_fd->elf)) + { + asection *sym_sec, *code_sec, *stub_sec; + bfd_vma sym_value; + struct _opd_sec_data *opd; + + sym_sec = htab->tls_get_addr_fd->elf.root.u.def.section; + sym_value = defined_sym_val (&htab->tls_get_addr_fd->elf); + code_sec = sym_sec; + opd = get_opd_info (sym_sec); + if (opd != NULL) + opd_entry_value (sym_sec, sym_value, &code_sec, NULL, FALSE); + htab->tga_group = htab->sec_info[code_sec->id].u.group; + stub_sec = (*htab->params->add_stub_section) (".tga_desc.stub", + htab->tga_group->link_sec); + if (stub_sec == NULL) + return FALSE; + htab->tga_group->stub_sec = stub_sec; + + htab->tga_desc_fd->elf.root.type = bfd_link_hash_defined; + htab->tga_desc_fd->elf.root.u.def.section = stub_sec; + htab->tga_desc_fd->elf.root.u.def.value = 0; + htab->tga_desc_fd->elf.type = STT_FUNC; + htab->tga_desc_fd->elf.def_regular = 1; + htab->tga_desc_fd->elf.non_elf = 0; + _bfd_elf_link_hash_hide_symbol (info, &htab->tga_desc_fd->elf, TRUE); + } + #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 @@ -12919,7 +13228,7 @@ ppc64_elf_size_stubs (struct bfd_link_info *info) if (!get_sym_h (&h, &sym, &sym_sec, NULL, &local_syms, r_indx, input_bfd)) goto error_ret_free_internal; - hash = (struct ppc_link_hash_entry *) h; + hash = ppc_elf_hash_entry (h); ok_dest = FALSE; fdh = NULL; @@ -13055,8 +13364,7 @@ ppc64_elf_size_stubs (struct bfd_link_info *info) if (stub_type != ppc_stub_plt_call && stub_type != ppc_stub_plt_call_notoc && hash != NULL - && (hash == htab->tls_get_addr - || hash == htab->tls_get_addr_fd) + && is_tls_get_addr (&hash->elf, htab) && section->has_tls_reloc && irela != internal_relocs) { @@ -13066,7 +13374,8 @@ ppc64_elf_size_stubs (struct bfd_link_info *info) if (!get_tls_mask (&tls_mask, NULL, NULL, &local_syms, irela - 1, input_bfd)) goto error_ret_free_internal; - if ((*tls_mask & TLS_TLS) != 0) + if ((*tls_mask & TLS_TLS) != 0 + && (*tls_mask & (TLS_GD | TLS_LD)) == 0) continue; } @@ -13178,9 +13487,8 @@ ppc64_elf_size_stubs (struct bfd_link_info *info) if (elf_section_data (section)->relocs == NULL) free (internal_relocs); error_ret_free_local: - if (local_syms != NULL - && (symtab_hdr->contents - != (unsigned char *) local_syms)) + if (symtab_hdr->contents + != (unsigned char *) local_syms) free (local_syms); return FALSE; } @@ -13243,6 +13551,14 @@ ppc64_elf_size_stubs (struct bfd_link_info *info) stub_sec->flags &= ~SEC_RELOC; } } + if (htab->tga_group != NULL) + { + /* See emit_tga_desc and emit_tga_desc_eh_frame. */ + htab->tga_group->eh_size + = 1 + 2 + (htab->opd_abi != 0) + 3 + 8 * 2 + 3 + 8 + 3; + htab->tga_group->lr_restore = 23 * 4; + htab->tga_group->stub_sec->size = 24 * 4; + } if (htab->stub_iteration <= STUB_SHRINK_ITER || htab->brlt->rawsize < htab->brlt->size) @@ -13306,7 +13622,9 @@ ppc64_elf_size_stubs (struct bfd_link_info *info) || (htab->stub_iteration > STUB_SHRINK_ITER && htab->brlt->rawsize > htab->brlt->size)) && (htab->glink_eh_frame == NULL - || htab->glink_eh_frame->rawsize == htab->glink_eh_frame->size)) + || htab->glink_eh_frame->rawsize == htab->glink_eh_frame->size) + && (htab->tga_group == NULL + || htab->stub_iteration > 1)) break; /* Ask the linker to do its stuff. */ @@ -13402,6 +13720,8 @@ ppc64_elf_size_stubs (struct bfd_link_info *info) } maybe_strip_output (info, htab->brlt); + if (htab->relbrlt != NULL) + maybe_strip_output (info, htab->relbrlt); if (htab->glink_eh_frame != NULL) maybe_strip_output (info, htab->glink_eh_frame); @@ -13437,9 +13757,7 @@ ppc64_elf_set_toc (struct bfd_link_info *info, bfd *obfd) && (!is_elf_hash_table (htab) || h->def_regular)) { - TOCstart = (h->root.u.def.value - TOC_BASE_OFF - + h->root.u.def.section->output_offset - + h->root.u.def.section->output_section->vma); + TOCstart = defined_sym_val (h) - TOC_BASE_OFF; _bfd_set_gp_value (obfd, TOCstart); return TOCstart; } @@ -13558,7 +13876,7 @@ build_global_entry_stubs_and_plt (struct elf_link_hash_entry *h, void *inf) { plt = htab->elf.iplt; relplt = htab->elf.irelplt; - htab->local_ifunc_resolver = 1; + htab->elf.ifunc_resolvers = TRUE; if (htab->opd_abi) rela.r_info = ELF64_R_INFO (0, R_PPC64_JMP_IREL); else @@ -13578,10 +13896,7 @@ build_global_entry_stubs_and_plt (struct elf_link_hash_entry *h, void *inf) else relplt = NULL; } - rela.r_addend = (h->root.u.def.value - + h->root.u.def.section->output_offset - + h->root.u.def.section->output_section->vma - + ent->addend); + rela.r_addend = defined_sym_val (h) + ent->addend; if (relplt == NULL) { @@ -13615,7 +13930,7 @@ build_global_entry_stubs_and_plt (struct elf_link_hash_entry *h, void *inf) + ((ent->plt.offset - PLT_INITIAL_ENTRY_SIZE (htab)) / PLT_ENTRY_SIZE (htab) * sizeof (Elf64_External_Rela))); if (h->type == STT_GNU_IFUNC && is_static_defined (h)) - htab->maybe_local_ifunc_resolver = 1; + htab->elf.ifunc_resolvers = TRUE; bfd_elf64_swap_reloca_out (info->output_bfd, &rela, loc); } } @@ -13744,8 +14059,7 @@ write_plt_relocs_for_local_syms (struct bfd_link_info *info) if (!get_sym_h (NULL, &sym, &sym_sec, NULL, &local_syms, lplt - local_plt, ibfd)) { - if (local_syms != NULL - && symtab_hdr->contents != (unsigned char *) local_syms) + if (symtab_hdr->contents != (unsigned char *) local_syms) free (local_syms); return FALSE; } @@ -13758,7 +14072,7 @@ write_plt_relocs_for_local_syms (struct bfd_link_info *info) if (ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC) { - htab->local_ifunc_resolver = 1; + htab->elf.ifunc_resolvers = TRUE; plt = htab->elf.iplt; relplt = htab->elf.irelplt; } @@ -13817,6 +14131,74 @@ write_plt_relocs_for_local_syms (struct bfd_link_info *info) return TRUE; } +/* Emit the static wrapper function preserving registers around a + __tls_get_addr_opt call. */ + +static bfd_boolean +emit_tga_desc (struct ppc_link_hash_table *htab) +{ + asection *stub_sec = htab->tga_group->stub_sec; + unsigned int cfa_updt = 11 * 4; + bfd_byte *p; + bfd_vma to, from, delta; + + BFD_ASSERT (htab->tga_desc_fd->elf.root.type == bfd_link_hash_defined + && htab->tga_desc_fd->elf.root.u.def.section == stub_sec + && htab->tga_desc_fd->elf.root.u.def.value == 0); + to = defined_sym_val (&htab->tls_get_addr_fd->elf); + from = defined_sym_val (&htab->tga_desc_fd->elf) + cfa_updt; + delta = to - from; + if (delta + (1 << 25) >= 1 << 26) + { + _bfd_error_handler (_("__tls_get_addr call offset overflow")); + htab->stub_error = TRUE; + return FALSE; + } + + p = stub_sec->contents; + p = tls_get_addr_prologue (htab->elf.dynobj, p, htab); + bfd_put_32 (stub_sec->owner, B_DOT | 1 | (delta & 0x3fffffc), p); + p += 4; + p = tls_get_addr_epilogue (htab->elf.dynobj, p, htab); + return stub_sec->size == (bfd_size_type) (p - stub_sec->contents); +} + +/* Emit eh_frame describing the static wrapper function. */ + +static bfd_byte * +emit_tga_desc_eh_frame (struct ppc_link_hash_table *htab, bfd_byte *p) +{ + unsigned int cfa_updt = 11 * 4; + unsigned int i; + + *p++ = DW_CFA_advance_loc + cfa_updt / 4; + *p++ = DW_CFA_def_cfa_offset; + if (htab->opd_abi) + { + *p++ = 128; + *p++ = 1; + } + else + *p++ = 96; + *p++ = DW_CFA_offset_extended_sf; + *p++ = 65; + *p++ = (-16 / 8) & 0x7f; + for (i = 4; i < 12; i++) + { + *p++ = DW_CFA_offset + i; + *p++ = (htab->opd_abi ? 13 : 12) - i; + } + *p++ = DW_CFA_advance_loc + 10; + *p++ = DW_CFA_def_cfa_offset; + *p++ = 0; + for (i = 4; i < 12; i++) + *p++ = DW_CFA_restore + i; + *p++ = DW_CFA_advance_loc + 2; + *p++ = DW_CFA_restore_extended; + *p++ = 65; + return p; +} + /* Build all the stubs associated with the current output file. The stubs are kept in a hash table attached to the main linker hash table. This function is called via gldelf64ppc_finish. */ @@ -13976,6 +14358,24 @@ ppc64_elf_build_stubs (struct bfd_link_info *info, } } + if (htab->tga_group != NULL) + { + htab->tga_group->lr_restore = 23 * 4; + htab->tga_group->stub_sec->size = 24 * 4; + if (!emit_tga_desc (htab)) + return FALSE; + if (htab->glink_eh_frame != NULL + && htab->glink_eh_frame->size != 0) + { + size_t align = 4; + + p = htab->glink_eh_frame->contents; + p += (sizeof (glink_eh_frame_cie) + align - 1) & -align; + p += 17; + htab->tga_group->eh_size = emit_tga_desc_eh_frame (htab, p) - p; + } + } + /* Build .glink global entry stubs, and PLT relocs for globals. */ elf_link_hash_traverse (&htab->elf, build_global_entry_stubs_and_plt, info); @@ -14101,42 +14501,46 @@ ppc64_elf_build_stubs (struct bfd_link_info *info, if (stats != NULL) { - size_t len; - *stats = bfd_malloc (500); - if (*stats == NULL) - return FALSE; - - len = sprintf (*stats, - ngettext ("linker stubs in %u group\n", - "linker stubs in %u groups\n", - stub_sec_count), - stub_sec_count); - sprintf (*stats + len, _(" branch %lu\n" - " branch toc adj %lu\n" - " branch notoc %lu\n" - " branch both %lu\n" - " long branch %lu\n" - " long toc adj %lu\n" - " long notoc %lu\n" - " long both %lu\n" - " plt call %lu\n" - " plt call save %lu\n" - " plt call notoc %lu\n" - " plt call both %lu\n" - " global entry %lu"), - htab->stub_count[ppc_stub_long_branch - 1], - htab->stub_count[ppc_stub_long_branch_r2off - 1], - htab->stub_count[ppc_stub_long_branch_notoc - 1], - htab->stub_count[ppc_stub_long_branch_both - 1], - htab->stub_count[ppc_stub_plt_branch - 1], - htab->stub_count[ppc_stub_plt_branch_r2off - 1], - htab->stub_count[ppc_stub_plt_branch_notoc - 1], - htab->stub_count[ppc_stub_plt_branch_both - 1], - htab->stub_count[ppc_stub_plt_call - 1], - htab->stub_count[ppc_stub_plt_call_r2save - 1], - htab->stub_count[ppc_stub_plt_call_notoc - 1], - htab->stub_count[ppc_stub_plt_call_both - 1], - htab->stub_count[ppc_stub_global_entry - 1]); + char *groupmsg; + if (asprintf (&groupmsg, + ngettext ("linker stubs in %u group\n", + "linker stubs in %u groups\n", + stub_sec_count), + stub_sec_count) < 0) + *stats = NULL; + else + { + if (asprintf (stats, _("%s" + " branch %lu\n" + " branch toc adj %lu\n" + " branch notoc %lu\n" + " branch both %lu\n" + " long branch %lu\n" + " long toc adj %lu\n" + " long notoc %lu\n" + " long both %lu\n" + " plt call %lu\n" + " plt call save %lu\n" + " plt call notoc %lu\n" + " plt call both %lu\n" + " global entry %lu"), + groupmsg, + htab->stub_count[ppc_stub_long_branch - 1], + htab->stub_count[ppc_stub_long_branch_r2off - 1], + htab->stub_count[ppc_stub_long_branch_notoc - 1], + htab->stub_count[ppc_stub_long_branch_both - 1], + htab->stub_count[ppc_stub_plt_branch - 1], + htab->stub_count[ppc_stub_plt_branch_r2off - 1], + htab->stub_count[ppc_stub_plt_branch_notoc - 1], + htab->stub_count[ppc_stub_plt_branch_both - 1], + htab->stub_count[ppc_stub_plt_call - 1], + htab->stub_count[ppc_stub_plt_call_r2save - 1], + htab->stub_count[ppc_stub_plt_call_notoc - 1], + htab->stub_count[ppc_stub_plt_call_both - 1], + htab->stub_count[ppc_stub_global_entry - 1]) < 0) + *stats = NULL; + free (groupmsg); + } } return TRUE; } @@ -14422,7 +14826,7 @@ ppc64_elf_relocate_section (bfd *output_bfd, } } } - h = (struct ppc_link_hash_entry *) h_elf; + h = ppc_elf_hash_entry (h_elf); if (sec != NULL && discarded_section (sec)) { @@ -14534,7 +14938,7 @@ ppc64_elf_relocate_section (bfd *output_bfd, case R_PPC64_LO_DS_OPT: insn = bfd_get_32 (input_bfd, contents + rel->r_offset - d_offset); - if ((insn & (0x3f << 26)) != 58u << 26) + if ((insn & (0x3fu << 26)) != 58u << 26) abort (); insn += (14u << 26) - (58u << 26); bfd_put_32 (input_bfd, insn, contents + rel->r_offset - d_offset); @@ -14626,7 +15030,7 @@ ppc64_elf_relocate_section (bfd *output_bfd, } break; - case R_PPC64_GOT_TPREL34: + case R_PPC64_GOT_TPREL_PCREL34: if ((tls_mask & TLS_TLS) != 0 && (tls_mask & TLS_TPREL) == 0) { @@ -14676,7 +15080,7 @@ ppc64_elf_relocate_section (bfd *output_bfd, /* For pcrel IE to LE we already have the full offset and thus don't need an addi here. A nop or mr will do. */ - if ((insn & (0x3f << 26)) == 14 << 26) + if ((insn & (0x3fu << 26)) == 14 << 26) { /* Extract regs from addi rt,ra,si. */ unsigned int rt = (insn >> 21) & 0x1f; @@ -14743,8 +15147,10 @@ ppc64_elf_relocate_section (bfd *output_bfd, if (input_section->nomark_tls_get_addr && rel + 1 < relend && branch_reloc_hash_match (input_bfd, rel + 1, + htab->tls_get_addr_fd, + htab->tga_desc_fd, htab->tls_get_addr, - htab->tls_get_addr_fd)) + htab->tga_desc)) offset = rel[1].r_offset; /* We read the low GOT_TLS (or TOC16) insn because we need to keep the destination reg. It may be @@ -14756,7 +15162,7 @@ ppc64_elf_relocate_section (bfd *output_bfd, { /* IE */ insn1 &= (0x1f << 21) | (0x1f << 16); - insn1 |= 58 << 26; /* ld */ + insn1 |= 58u << 26; /* ld */ insn2 = 0x7c636a14; /* add 3,3,13 */ if (offset != (bfd_vma) -1) rel[1].r_info = ELF64_R_INFO (STN_UNDEF, R_PPC64_NONE); @@ -14817,7 +15223,7 @@ ppc64_elf_relocate_section (bfd *output_bfd, } break; - case R_PPC64_GOT_TLSGD34: + case R_PPC64_GOT_TLSGD_PCREL34: if ((tls_mask & TLS_TLS) != 0 && (tls_mask & TLS_GD) == 0) { pinsn = bfd_get_32 (input_bfd, contents + rel->r_offset); @@ -14827,7 +15233,7 @@ ppc64_elf_relocate_section (bfd *output_bfd, { /* IE, pla -> pld */ pinsn += (-2ULL << 56) + (57ULL << 26) - (14ULL << 26); - r_type = R_PPC64_GOT_TPREL34; + r_type = R_PPC64_GOT_TPREL_PCREL34; } else { @@ -14843,7 +15249,7 @@ ppc64_elf_relocate_section (bfd *output_bfd, } break; - case R_PPC64_GOT_TLSLD34: + case R_PPC64_GOT_TLSLD_PCREL34: if ((tls_mask & TLS_TLS) != 0 && (tls_mask & TLS_LD) == 0) { pinsn = bfd_get_32 (input_bfd, contents + rel->r_offset); @@ -15200,8 +15606,7 @@ ppc64_elf_relocate_section (bfd *output_bfd, || nop == CROR_313131) { if (h != NULL - && (h == htab->tls_get_addr_fd - || h == htab->tls_get_addr) + && is_tls_get_addr (&h->elf, htab) && htab->params->tls_get_addr_opt) { /* Special stub used, leave nop alone. */ @@ -15366,8 +15771,7 @@ ppc64_elf_relocate_section (bfd *output_bfd, || stub_entry->stub_type == ppc_stub_plt_call_r2save || stub_entry->stub_type == ppc_stub_plt_call_both) && !(h != NULL - && (h == htab->tls_get_addr_fd - || h == htab->tls_get_addr) + && is_tls_get_addr (&h->elf, htab) && htab->params->tls_get_addr_opt) && rel + 1 < relend && rel[1].r_offset == rel->r_offset + 4 @@ -15426,12 +15830,14 @@ ppc64_elf_relocate_section (bfd *output_bfd, break; case R_PPC64_GOT16_DS: + if ((h ? h->elf.type : ELF_ST_TYPE (sym->st_info)) == STT_GNU_IFUNC) + break; from = TOCstart + htab->sec_info[input_section->id].toc_off; if (relocation + addend - from + 0x8000 < 0x10000 && SYMBOL_REFERENCES_LOCAL (info, &h->elf)) { insn = bfd_get_32 (input_bfd, contents + (rel->r_offset & ~3)); - if ((insn & (0x3f << 26 | 0x3)) == 58u << 26 /* ld */) + if ((insn & (0x3fu << 26 | 0x3)) == 58u << 26 /* ld */) { insn += (14u << 26) - (58u << 26); bfd_put_32 (input_bfd, insn, contents + (rel->r_offset & ~3)); @@ -15443,19 +15849,21 @@ ppc64_elf_relocate_section (bfd *output_bfd, case R_PPC64_GOT16_LO_DS: case R_PPC64_GOT16_HA: + if ((h ? h->elf.type : ELF_ST_TYPE (sym->st_info)) == STT_GNU_IFUNC) + break; from = TOCstart + htab->sec_info[input_section->id].toc_off; if (relocation + addend - from + 0x80008000ULL < 0x100000000ULL && SYMBOL_REFERENCES_LOCAL (info, &h->elf)) { insn = bfd_get_32 (input_bfd, contents + (rel->r_offset & ~3)); - if ((insn & (0x3f << 26 | 0x3)) == 58u << 26 /* ld */) + if ((insn & (0x3fu << 26 | 0x3)) == 58u << 26 /* ld */) { insn += (14u << 26) - (58u << 26); bfd_put_32 (input_bfd, insn, contents + (rel->r_offset & ~3)); r_type = R_PPC64_TOC16_LO; rel->r_info = ELF64_R_INFO (r_symndx, r_type); } - else if ((insn & (0x3f << 26)) == 15u << 26 /* addis */) + else if ((insn & (0x3fu << 26)) == 15u << 26 /* addis */) { r_type = R_PPC64_TOC16_HA; rel->r_info = ELF64_R_INFO (r_symndx, r_type); @@ -15464,6 +15872,8 @@ ppc64_elf_relocate_section (bfd *output_bfd, break; case R_PPC64_GOT_PCREL34: + if ((h ? h->elf.type : ELF_ST_TYPE (sym->st_info)) == STT_GNU_IFUNC) + break; from = (rel->r_offset + input_section->output_section->vma + input_section->output_offset); @@ -15575,7 +15985,7 @@ ppc64_elf_relocate_section (bfd *output_bfd, case R_PPC64_GOT_TLSGD16_LO: case R_PPC64_GOT_TLSGD16_HI: case R_PPC64_GOT_TLSGD16_HA: - case R_PPC64_GOT_TLSGD34: + case R_PPC64_GOT_TLSGD_PCREL34: tls_type = TLS_TLS | TLS_GD; goto dogot; @@ -15583,7 +15993,7 @@ ppc64_elf_relocate_section (bfd *output_bfd, case R_PPC64_GOT_TLSLD16_LO: case R_PPC64_GOT_TLSLD16_HI: case R_PPC64_GOT_TLSLD16_HA: - case R_PPC64_GOT_TLSLD34: + case R_PPC64_GOT_TLSLD_PCREL34: tls_type = TLS_TLS | TLS_LD; goto dogot; @@ -15591,7 +16001,7 @@ ppc64_elf_relocate_section (bfd *output_bfd, case R_PPC64_GOT_TPREL16_LO_DS: case R_PPC64_GOT_TPREL16_HI: case R_PPC64_GOT_TPREL16_HA: - case R_PPC64_GOT_TPREL34: + case R_PPC64_GOT_TPREL_PCREL34: tls_type = TLS_TLS | TLS_TPREL; goto dogot; @@ -15599,7 +16009,7 @@ ppc64_elf_relocate_section (bfd *output_bfd, case R_PPC64_GOT_DTPREL16_LO_DS: case R_PPC64_GOT_DTPREL16_HI: case R_PPC64_GOT_DTPREL16_HA: - case R_PPC64_GOT_DTPREL34: + case R_PPC64_GOT_DTPREL_PCREL34: tls_type = TLS_TLS | TLS_DTPREL; goto dogot; @@ -15688,10 +16098,8 @@ ppc64_elf_relocate_section (bfd *output_bfd, if (ifunc) { relgot = htab->elf.irelplt; - if (indx == 0) - htab->local_ifunc_resolver = 1; - else if (is_static_defined (&h->elf)) - htab->maybe_local_ifunc_resolver = 1; + if (indx == 0 || is_static_defined (&h->elf)) + htab->elf.ifunc_resolvers = TRUE; } else if (indx != 0 || (bfd_link_pic (info) @@ -15798,10 +16206,10 @@ ppc64_elf_relocate_section (bfd *output_bfd, relocation = got->output_section->vma + got->output_offset + off; addend = 0; if (!(r_type == R_PPC64_GOT_PCREL34 - || r_type == R_PPC64_GOT_TLSGD34 - || r_type == R_PPC64_GOT_TLSLD34 - || r_type == R_PPC64_GOT_TPREL34 - || r_type == R_PPC64_GOT_DTPREL34)) + || r_type == R_PPC64_GOT_TLSGD_PCREL34 + || r_type == R_PPC64_GOT_TLSLD_PCREL34 + || r_type == R_PPC64_GOT_TPREL_PCREL34 + || r_type == R_PPC64_GOT_DTPREL_PCREL34)) addend = -(TOCstart + htab->sec_info[input_section->id].toc_off); } break; @@ -16055,11 +16463,11 @@ ppc64_elf_relocate_section (bfd *output_bfd, if (bfd_link_pic (info) ? ((h == NULL - || h->dyn_relocs != NULL) + || h->elf.dyn_relocs != NULL) && ((h != NULL && pc_dynrelocs (h)) || must_be_dyn_reloc (info, r_type))) : (h != NULL - ? h->dyn_relocs != NULL + ? h->elf.dyn_relocs != NULL : ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC)) { bfd_boolean skip, relocate; @@ -16220,10 +16628,8 @@ ppc64_elf_relocate_section (bfd *output_bfd, : ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC) { sreloc = htab->elf.irelplt; - if (indx == 0) - htab->local_ifunc_resolver = 1; - else if (is_static_defined (&h->elf)) - htab->maybe_local_ifunc_resolver = 1; + if (indx == 0 || is_static_defined (&h->elf)) + htab->elf.ifunc_resolvers = TRUE; } if (sreloc == NULL) abort (); @@ -16415,10 +16821,10 @@ ppc64_elf_relocate_section (bfd *output_bfd, { bfd_byte *p = contents + (rel->r_offset & ~3); insn = bfd_get_32 (input_bfd, p); - if ((insn & (0x3f << 26)) == 12u << 26 /* addic */) + if ((insn & (0x3fu << 26)) == 12u << 26 /* addic */) { /* Transform addic to addi when we change reg. */ - insn &= ~((0x3f << 26) | (0x1f << 16)); + insn &= ~((0x3fu << 26) | (0x1f << 16)); insn |= (14u << 26) | (2 << 16); } else @@ -16435,7 +16841,7 @@ ppc64_elf_relocate_section (bfd *output_bfd, { bfd_byte *p = contents + (rel->r_offset & ~3); insn = bfd_get_32 (input_bfd, p); - if ((insn & ((0x3f << 26) | 0x1f << 16)) + if ((insn & ((0x3fu << 26) | 0x1f << 16)) != ((15u << 26) | (13 << 16)) /* addis rt,13,imm */) /* xgettext:c-format */ info->callbacks->minfo @@ -16544,8 +16950,8 @@ ppc64_elf_relocate_section (bfd *output_bfd, 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)) + if ((insn & (0x3fu << 26)) == (56u << 26) + || ((insn & (0x3fu << 26)) == (61u << 26) && (insn & 3) == 1)) mask = 15; relocation += addend; addend = insn & (mask ^ 3); @@ -16594,15 +17000,15 @@ ppc64_elf_relocate_section (bfd *output_bfd, enum complain_overflow complain = complain_overflow_signed; insn = bfd_get_32 (input_bfd, contents + (rel->r_offset & ~3)); - if ((insn & (0x3f << 26)) == 10u << 26 /* cmpli */) + if ((insn & (0x3fu << 26)) == 10u << 26 /* cmpli */) complain = complain_overflow_bitfield; else if (howto->rightshift == 0 - ? ((insn & (0x3f << 26)) == 28u << 26 /* andi */ - || (insn & (0x3f << 26)) == 24u << 26 /* ori */ - || (insn & (0x3f << 26)) == 26u << 26 /* xori */) - : ((insn & (0x3f << 26)) == 29u << 26 /* andis */ - || (insn & (0x3f << 26)) == 25u << 26 /* oris */ - || (insn & (0x3f << 26)) == 27u << 26 /* xoris */)) + ? ((insn & (0x3fu << 26)) == 28u << 26 /* andi */ + || (insn & (0x3fu << 26)) == 24u << 26 /* ori */ + || (insn & (0x3fu << 26)) == 26u << 26 /* xori */) + : ((insn & (0x3fu << 26)) == 29u << 26 /* andis */ + || (insn & (0x3fu << 26)) == 25u << 26 /* oris */ + || (insn & (0x3fu << 26)) == 27u << 26 /* xoris */)) complain = complain_overflow_unsigned; if (howto->complain_on_overflow != complain) { @@ -16623,10 +17029,10 @@ ppc64_elf_relocate_section (bfd *output_bfd, case R_PPC64_GOT_PCREL34: case R_PPC64_TPREL34: case R_PPC64_DTPREL34: - case R_PPC64_GOT_TLSGD34: - case R_PPC64_GOT_TLSLD34: - case R_PPC64_GOT_TPREL34: - case R_PPC64_GOT_DTPREL34: + case R_PPC64_GOT_TLSGD_PCREL34: + case R_PPC64_GOT_TLSLD_PCREL34: + case R_PPC64_GOT_TPREL_PCREL34: + case R_PPC64_GOT_DTPREL_PCREL34: case R_PPC64_PLT_PCREL34: case R_PPC64_PLT_PCREL34_NOTOC: case R_PPC64_D28: @@ -16727,8 +17133,7 @@ ppc64_elf_relocate_section (bfd *output_bfd, reloc_name, sym_name, (int) r); ret = FALSE; } - if (more_info != NULL) - free (more_info); + free (more_info); } copy_reloc: if (wrel != rel) @@ -16860,9 +17265,7 @@ ppc64_elf_finish_dynamic_symbol (bfd *output_bfd, if (h->dynindx == -1) abort (); - rela.r_offset = (h->root.u.def.value - + h->root.u.def.section->output_section->vma - + h->root.u.def.section->output_offset); + rela.r_offset = defined_sym_val (h); rela.r_info = ELF64_R_INFO (h->dynindx, R_PPC64_COPY); rela.r_addend = 0; if (h->root.u.def.section == htab->elf.sdynrelro) @@ -16990,11 +17393,7 @@ ppc64_elf_finish_dynamic_sections (bfd *output_bfd, break; case DT_TEXTREL: - if (htab->local_ifunc_resolver) - info->callbacks->einfo - (_("%X%P: text relocations and GNU indirect " - "functions will result in a segfault at runtime\n")); - else if (htab->maybe_local_ifunc_resolver) + if (htab->elf.ifunc_resolvers) info->callbacks->einfo (_("%P: warning: text relocations and GNU indirect " "functions may result in a segfault at runtime\n"));