X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=bfd%2Felf32-ppc.c;h=89069715191bec13fb6eb8d4a1984967f647ef58;hb=6c6bc899302deb7c9b14f71da79c0fffc992204e;hp=e71757eab0ff2f533cecf5528c501e9b3b04fcd6;hpb=5499c7c71cc403a1deff90b79ab41d17efc5c4cc;p=binutils-gdb.git diff --git a/bfd/elf32-ppc.c b/bfd/elf32-ppc.c index e71757eab0f..89069715191 100644 --- a/bfd/elf32-ppc.c +++ b/bfd/elf32-ppc.c @@ -134,7 +134,7 @@ static const bfd_vma ppc_elf_vxworks_pic_plt0_entry #define VXWORKS_PLT_NON_JMP_SLOT_RELOCS 3 /* The number of relocations in the PLTResolve slot. */ #define VXWORKS_PLTRESOLVE_RELOCS 2 -/* The number of relocations in the PLTResolve slot when when creating +/* The number of relocations in the PLTResolve slot when creating a shared library. */ #define VXWORKS_PLTRESOLVE_RELOCS_SHLIB 0 @@ -1656,6 +1656,21 @@ static reloc_howto_type ppc_elf_howto_raw[] = { 0x3e007ff, /* dst_mask */ FALSE), /* pcrel_offset */ + /* e_li split20 format. */ + HOWTO (R_PPC_VLE_ADDR20, /* type */ + 16, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 20, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_PPC_VLE_ADDR20", /* name */ + FALSE, /* partial_inplace */ + 0, /* src_mask */ + 0x1f07ff, /* dst_mask */ + FALSE), /* pcrel_offset */ + HOWTO (R_PPC_IRELATIVE, /* type */ 0, /* rightshift */ 2, /* size (0 = byte, 1 = short, 2 = long) */ @@ -1746,6 +1761,21 @@ static reloc_howto_type ppc_elf_howto_raw[] = { 0x1fffc1, /* dst_mask */ TRUE), /* pcrel_offset */ + /* A split-field reloc for addpcis, non-relative (gas internal use only). */ + HOWTO (R_PPC_16DX_HA, /* type */ + 16, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + ppc_elf_addr16_ha_reloc, /* special_function */ + "R_PPC_16DX_HA", /* name */ + FALSE, /* partial_inplace */ + 0, /* src_mask */ + 0x1fffc1, /* dst_mask */ + FALSE), /* pcrel_offset */ + /* GNU extension to record C++ vtable hierarchy. */ HOWTO (R_PPC_GNU_VTINHERIT, /* type */ 0, /* rightshift */ @@ -1791,56 +1821,6 @@ static reloc_howto_type ppc_elf_howto_raw[] = { 0xffff, /* dst_mask */ FALSE), /* pcrel_offset */ }; - -/* External 32-bit PPC structure for PRPSINFO. This structure is - ABI-defined, thus we choose to use char arrays here in order to - avoid dealing with different types in different architectures. - - The PPC 32-bit structure uses int for `pr_uid' and `pr_gid' while - most non-PPC architectures use `short int'. - - This structure will ultimately be written in the corefile's note - section, as the PRPSINFO. */ - -struct elf_external_ppc_linux_prpsinfo32 - { - char pr_state; /* Numeric process state. */ - char pr_sname; /* Char for pr_state. */ - char pr_zomb; /* Zombie. */ - char pr_nice; /* Nice val. */ - char pr_flag[4]; /* Flags. */ - char pr_uid[4]; - char pr_gid[4]; - char pr_pid[4]; - char pr_ppid[4]; - char pr_pgrp[4]; - char pr_sid[4]; - char pr_fname[16]; /* Filename of executable. */ - char pr_psargs[80]; /* Initial part of arg list. */ - }; - -/* Helper function to copy an elf_internal_linux_prpsinfo in host - endian to an elf_external_ppc_linux_prpsinfo32 in target endian. */ - -static inline void -swap_ppc_linux_prpsinfo32_out (bfd *obfd, - const struct elf_internal_linux_prpsinfo *from, - struct elf_external_ppc_linux_prpsinfo32 *to) -{ - bfd_put_8 (obfd, from->pr_state, &to->pr_state); - bfd_put_8 (obfd, from->pr_sname, &to->pr_sname); - bfd_put_8 (obfd, from->pr_zomb, &to->pr_zomb); - bfd_put_8 (obfd, from->pr_nice, &to->pr_nice); - bfd_put_32 (obfd, from->pr_flag, to->pr_flag); - bfd_put_32 (obfd, from->pr_uid, to->pr_uid); - bfd_put_32 (obfd, from->pr_gid, to->pr_gid); - bfd_put_32 (obfd, from->pr_pid, to->pr_pid); - bfd_put_32 (obfd, from->pr_ppid, to->pr_ppid); - bfd_put_32 (obfd, from->pr_pgrp, to->pr_pgrp); - bfd_put_32 (obfd, from->pr_sid, to->pr_sid); - strncpy (to->pr_fname, from->pr_fname, sizeof (to->pr_fname)); - strncpy (to->pr_psargs, from->pr_psargs, sizeof (to->pr_psargs)); -} /* Initialize the ppc_elf_howto_table, so that linear accesses can be done. */ @@ -2002,6 +1982,7 @@ ppc_elf_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED, case BFD_RELOC_LO16_PCREL: r = R_PPC_REL16_LO; break; case BFD_RELOC_HI16_PCREL: r = R_PPC_REL16_HI; break; case BFD_RELOC_HI16_S_PCREL: r = R_PPC_REL16_HA; break; + case BFD_RELOC_PPC_16DX_HA: r = R_PPC_16DX_HA; break; case BFD_RELOC_PPC_REL16DX_HA: r = R_PPC_REL16DX_HA; break; case BFD_RELOC_VTABLE_INHERIT: r = R_PPC_GNU_VTINHERIT; break; case BFD_RELOC_VTABLE_ENTRY: r = R_PPC_GNU_VTENTRY; break; @@ -2029,7 +2010,7 @@ ppc_elf_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, /* Set the howto pointer for a PowerPC ELF reloc. */ static void -ppc_elf_info_to_howto (bfd *abfd ATTRIBUTE_UNUSED, +ppc_elf_info_to_howto (bfd *abfd, arelent *cache_ptr, Elf_Internal_Rela *dst) { @@ -2066,10 +2047,10 @@ ppc_elf_info_to_howto (bfd *abfd ATTRIBUTE_UNUSED, /* Handle the R_PPC_ADDR16_HA and R_PPC_REL16_HA relocs. */ static bfd_reloc_status_type -ppc_elf_addr16_ha_reloc (bfd *abfd ATTRIBUTE_UNUSED, +ppc_elf_addr16_ha_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol, - void *data ATTRIBUTE_UNUSED, + void *data, asection *input_section, bfd *output_bfd, char **error_message ATTRIBUTE_UNUSED) @@ -2377,20 +2358,6 @@ ppc_elf_grok_psinfo (bfd *abfd, Elf_Internal_Note *note) return TRUE; } -char * -elfcore_write_ppc_linux_prpsinfo32 - (bfd *abfd, - char *buf, - int *bufsiz, - const struct elf_internal_linux_prpsinfo *prpsinfo) -{ - struct elf_external_ppc_linux_prpsinfo32 data; - - swap_ppc_linux_prpsinfo32_out (abfd, prpsinfo, &data); - return elfcore_write_note (abfd, buf, bufsiz, - "CORE", NT_PRPSINFO, &data, sizeof (data)); -} - static char * ppc_elf_write_core_note (bfd *abfd, char *buf, int *bufsiz, int note_type, ...) { @@ -2593,7 +2560,7 @@ ppc_elf_modify_segment_map (bfd *abfd, amt += (m->count - j - 1) * sizeof (asection *); n = (struct elf_segment_map *) bfd_zalloc (abfd, amt); if (n == NULL) - return FALSE; + return FALSE; n->p_type = PT_LOAD; n->count = m->count - j; @@ -2632,7 +2599,7 @@ static struct bfd_elf_special_section ppc_alt_plt = { STRING_COMMA_LEN (".plt"), 0, SHT_PROGBITS, SHF_ALLOC }; static const struct bfd_elf_special_section * -ppc_elf_get_sec_type_attr (bfd *abfd ATTRIBUTE_UNUSED, asection *sec) +ppc_elf_get_sec_type_attr (bfd *abfd, asection *sec) { const struct bfd_elf_special_section *ssect; @@ -2833,7 +2800,7 @@ ppc_elf_begin_write_processing (bfd *abfd, struct bfd_link_info *link_info) free (buffer); if (error_message) - _bfd_error_handler (error_message, ibfd, APUINFO_SECTION_NAME); + _bfd_error_handler (error_message, APUINFO_SECTION_NAME, ibfd); } /* Prevent the output section from accumulating the input sections' @@ -3176,9 +3143,9 @@ struct plt_entry bfd_vma glink_offset; }; -/* Of those relocs that might be copied as dynamic relocs, this function - selects those that must be copied when linking a shared library, - even when the symbol is local. */ +/* Of those relocs that might be copied as dynamic relocs, this + function selects those that must be copied when linking a shared + library or PIE, even when the symbol is local. */ static int must_be_dyn_reloc (struct bfd_link_info *info, @@ -3187,6 +3154,10 @@ must_be_dyn_reloc (struct bfd_link_info *info, switch (r_type) { default: + /* Only relative relocs can be resolved when the object load + address isn't fixed. DTPREL32 is excluded because the + dynamic linker needs to differentiate global dynamic from + local dynamic __tls_index pairs when PPC_OPT_TLS is set. */ return 1; case R_PPC_REL24: @@ -3201,7 +3172,9 @@ must_be_dyn_reloc (struct bfd_link_info *info, case R_PPC_TPREL16_LO: case R_PPC_TPREL16_HI: case R_PPC_TPREL16_HA: - return !bfd_link_executable (info); + /* These relocations are relative but in a shared library the + linker doesn't know the thread pointer base. */ + return bfd_link_dll (info); } } @@ -3311,6 +3284,14 @@ struct ppc_elf_link_hash_table /* True if the target system is VxWorks. */ unsigned int is_vxworks: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; + + /* Set if tls optimization is enabled. */ + unsigned int do_tls_opt:1; + /* The size of PLT entries. */ int plt_entry_size; /* The distance between adjacent PLT slots. */ @@ -3613,6 +3594,10 @@ ppc_elf_copy_indirect_symbol (struct bfd_link_info *info, edir->elf.needs_plt |= eind->elf.needs_plt; edir->elf.pointer_equality_needed |= eind->elf.pointer_equality_needed; + /* If we were called to copy over info for a weak sym, that's all. */ + if (eind->elf.root.type != bfd_link_hash_indirect) + return; + if (eind->dyn_relocs != NULL) { if (edir->dyn_relocs != NULL) @@ -3644,16 +3629,6 @@ ppc_elf_copy_indirect_symbol (struct bfd_link_info *info, eind->dyn_relocs = NULL; } - /* If we were called to copy over info for a weak sym, that's all. - You might think dyn_relocs need not be copied over; After all, - both syms will be dynamic or both non-dynamic so we're just - moving reloc accounting around. However, ELIMINATE_COPY_RELOCS - code in ppc_elf_adjust_dynamic_symbol needs to check for - dyn_relocs in read-only sections, and it does so on what is the - DIR sym here. */ - if (eind->elf.root.type != bfd_link_hash_indirect) - return; - /* Copy over the GOT refcount entries that we may have already seen to the symbol which just became indirect. */ edir->elf.got.refcount += eind->elf.got.refcount; @@ -4024,10 +3999,6 @@ ppc_elf_check_relocs (bfd *abfd, while (h->root.type == bfd_link_hash_indirect || h->root.type == bfd_link_hash_warning) h = (struct elf_link_hash_entry *) h->root.u.i.link; - - /* PR15323, ref flags aren't set for references in the same - object. */ - h->root.non_ir_ref = 1; } /* If a relocation refers to _GLOBAL_OFFSET_TABLE_, create the .got. @@ -4123,7 +4094,7 @@ ppc_elf_check_relocs (bfd *abfd, case R_PPC_GOT_TPREL16_LO: case R_PPC_GOT_TPREL16_HI: case R_PPC_GOT_TPREL16_HA: - if (bfd_link_pic (info)) + if (bfd_link_dll (info)) info->flags |= DF_STATIC_TLS; tls_type = TLS_TLS | TLS_TPREL; goto dogottls; @@ -4231,6 +4202,7 @@ ppc_elf_check_relocs (bfd *abfd, case R_PPC_VLE_HI16D: case R_PPC_VLE_HA16A: case R_PPC_VLE_HA16D: + case R_PPC_VLE_ADDR20: break; case R_PPC_EMB_SDA2REL: @@ -4351,6 +4323,7 @@ ppc_elf_check_relocs (bfd *abfd, case R_PPC_RELAX: case R_PPC_RELAX_PLT: case R_PPC_RELAX_PLTREL24: + case R_PPC_16DX_HA: break; /* These should only appear in dynamic objects. */ @@ -4401,13 +4374,13 @@ ppc_elf_check_relocs (bfd *abfd, return FALSE; break; - /* We shouldn't really be seeing these. */ + /* We shouldn't really be seeing TPREL32. */ case R_PPC_TPREL32: case R_PPC_TPREL16: case R_PPC_TPREL16_LO: case R_PPC_TPREL16_HI: case R_PPC_TPREL16_HA: - if (bfd_link_pic (info)) + if (bfd_link_dll (info)) info->flags |= DF_STATIC_TLS; goto dodyn; @@ -4877,9 +4850,9 @@ ppc_elf_merge_private_bfd_data (bfd *ibfd, struct bfd_link_info *info) error = TRUE; _bfd_error_handler /* xgettext:c-format */ - (_("%B: uses different e_flags (0x%lx) fields " - "than previous modules (0x%lx)"), - ibfd, (long) new_flags, (long) old_flags); + (_("%B: uses different e_flags (%#x) fields " + "than previous modules (%#x)"), + ibfd, new_flags, old_flags); } if (error) @@ -4904,7 +4877,7 @@ ppc_elf_vle_split16 (bfd *input_bfd, unsigned int insn, opcode, top5; insn = bfd_get_32 (input_bfd, loc); - opcode = insn & 0xf300f800; + opcode = insn & 0xfc00f800; if (opcode == E_OR2I_INSN || opcode == E_AND2I_DOT_INSN || opcode == E_OR2IS_INSN @@ -4948,6 +4921,23 @@ ppc_elf_vle_split16 (bfd *input_bfd, insn |= value & 0x7ff; bfd_put_32 (input_bfd, insn, loc); } + +static void +ppc_elf_vle_split20 (bfd *output_bfd, bfd_byte *loc, bfd_vma value) +{ + unsigned int insn; + + insn = bfd_get_32 (output_bfd, loc); + /* We have an li20 field, bits 17..20, 11..15, 21..31. */ + /* Top 4 bits of value to 17..20. */ + insn |= (value & 0xf0000) >> 5; + /* Next 5 bits of the value to 11..15. */ + insn |= (value & 0xf800) << 5; + /* And the final 11 bits of the value to bits 21 to 31. */ + insn |= value & 0x7ff; + bfd_put_32 (output_bfd, insn, loc); +} + /* Choose which PLT scheme to use, and set .plt flags appropriately. Returns -1 on error, 0 for old PLT, 1 for new PLT. */ @@ -4974,8 +4964,7 @@ ppc_elf_select_plt_layout (bfd *output_bfd ATTRIBUTE_UNUSED, || h->needs_plt) && h->ref_regular && !(SYMBOL_CALLS_LOCAL (info, h) - || (ELF_ST_VISIBILITY (h->other) != STV_DEFAULT - && h->root.type == bfd_link_hash_undefweak))) + || UNDEFWEAK_NO_DYNAMIC_RELOC (info, h))) { /* Profiling of shared libs (and pies) is not supported with secure plt, because ppc32 does profiling before a @@ -5065,182 +5054,6 @@ ppc_elf_gc_mark_hook (asection *sec, return _bfd_elf_gc_mark_hook (sec, info, rel, h, sym); } - -/* Update the got, plt and dynamic reloc reference counts for the - section being removed. */ - -static bfd_boolean -ppc_elf_gc_sweep_hook (bfd *abfd, - struct bfd_link_info *info, - asection *sec, - const Elf_Internal_Rela *relocs) -{ - struct ppc_elf_link_hash_table *htab; - Elf_Internal_Shdr *symtab_hdr; - struct elf_link_hash_entry **sym_hashes; - bfd_signed_vma *local_got_refcounts; - const Elf_Internal_Rela *rel, *relend; - asection *got2; - - if (bfd_link_relocatable (info)) - return TRUE; - - if ((sec->flags & SEC_ALLOC) == 0) - return TRUE; - - elf_section_data (sec)->local_dynrel = NULL; - - htab = ppc_elf_hash_table (info); - symtab_hdr = &elf_symtab_hdr (abfd); - sym_hashes = elf_sym_hashes (abfd); - local_got_refcounts = elf_local_got_refcounts (abfd); - got2 = bfd_get_section_by_name (abfd, ".got2"); - - relend = relocs + sec->reloc_count; - for (rel = relocs; rel < relend; rel++) - { - unsigned long r_symndx; - enum elf_ppc_reloc_type r_type; - struct elf_link_hash_entry *h = NULL; - - r_symndx = ELF32_R_SYM (rel->r_info); - if (r_symndx >= symtab_hdr->sh_info) - { - struct elf_dyn_relocs **pp, *p; - struct ppc_elf_link_hash_entry *eh; - - h = sym_hashes[r_symndx - symtab_hdr->sh_info]; - while (h->root.type == bfd_link_hash_indirect - || h->root.type == bfd_link_hash_warning) - h = (struct elf_link_hash_entry *) h->root.u.i.link; - eh = (struct ppc_elf_link_hash_entry *) h; - - for (pp = &eh->dyn_relocs; (p = *pp) != NULL; pp = &p->next) - if (p->sec == sec) - { - /* Everything must go for SEC. */ - *pp = p->next; - break; - } - } - - r_type = ELF32_R_TYPE (rel->r_info); - if (!htab->is_vxworks - && h == NULL - && local_got_refcounts != NULL - && (!bfd_link_pic (info) - || is_branch_reloc (r_type))) - { - struct plt_entry **local_plt = (struct plt_entry **) - (local_got_refcounts + symtab_hdr->sh_info); - char *local_got_tls_masks = (char *) - (local_plt + symtab_hdr->sh_info); - if ((local_got_tls_masks[r_symndx] & PLT_IFUNC) != 0) - { - struct plt_entry **ifunc = local_plt + r_symndx; - bfd_vma addend = 0; - struct plt_entry *ent; - - if (r_type == R_PPC_PLTREL24 && bfd_link_pic (info)) - addend = rel->r_addend; - ent = find_plt_ent (ifunc, got2, addend); - if (ent->plt.refcount > 0) - ent->plt.refcount -= 1; - continue; - } - } - - switch (r_type) - { - case R_PPC_GOT_TLSLD16: - case R_PPC_GOT_TLSLD16_LO: - case R_PPC_GOT_TLSLD16_HI: - case R_PPC_GOT_TLSLD16_HA: - case R_PPC_GOT_TLSGD16: - case R_PPC_GOT_TLSGD16_LO: - case R_PPC_GOT_TLSGD16_HI: - case R_PPC_GOT_TLSGD16_HA: - case R_PPC_GOT_TPREL16: - case R_PPC_GOT_TPREL16_LO: - case R_PPC_GOT_TPREL16_HI: - case R_PPC_GOT_TPREL16_HA: - case R_PPC_GOT_DTPREL16: - case R_PPC_GOT_DTPREL16_LO: - case R_PPC_GOT_DTPREL16_HI: - case R_PPC_GOT_DTPREL16_HA: - case R_PPC_GOT16: - case R_PPC_GOT16_LO: - case R_PPC_GOT16_HI: - case R_PPC_GOT16_HA: - if (h != NULL) - { - if (h->got.refcount > 0) - h->got.refcount--; - if (!bfd_link_pic (info)) - { - struct plt_entry *ent; - - ent = find_plt_ent (&h->plt.plist, NULL, 0); - if (ent != NULL && ent->plt.refcount > 0) - ent->plt.refcount -= 1; - } - } - else if (local_got_refcounts != NULL) - { - if (local_got_refcounts[r_symndx] > 0) - local_got_refcounts[r_symndx]--; - } - break; - - case R_PPC_REL24: - case R_PPC_REL14: - case R_PPC_REL14_BRTAKEN: - case R_PPC_REL14_BRNTAKEN: - case R_PPC_REL32: - if (h == NULL || h == htab->elf.hgot) - break; - /* Fall through. */ - - case R_PPC_ADDR32: - case R_PPC_ADDR24: - case R_PPC_ADDR16: - case R_PPC_ADDR16_LO: - case R_PPC_ADDR16_HI: - case R_PPC_ADDR16_HA: - case R_PPC_ADDR14: - case R_PPC_ADDR14_BRTAKEN: - case R_PPC_ADDR14_BRNTAKEN: - case R_PPC_UADDR32: - case R_PPC_UADDR16: - if (bfd_link_pic (info)) - break; - /* Fall through. */ - - case R_PPC_PLT32: - case R_PPC_PLTREL24: - case R_PPC_PLTREL32: - case R_PPC_PLT16_LO: - case R_PPC_PLT16_HI: - case R_PPC_PLT16_HA: - if (h != NULL) - { - bfd_vma addend = 0; - struct plt_entry *ent; - - if (r_type == R_PPC_PLTREL24 && bfd_link_pic (info)) - addend = rel->r_addend; - ent = find_plt_ent (&h->plt.plist, got2, addend); - if (ent != NULL && ent->plt.refcount > 0) - ent->plt.refcount -= 1; - } - break; - - default: - break; - } - } - return TRUE; -} /* Set plt output section type, htab->tls_get_addr, and call the generic ELF tls_setup function. */ @@ -5275,8 +5088,7 @@ ppc_elf_tls_setup (bfd *obfd, struct bfd_link_info *info) && (tga->type == STT_FUNC || tga->needs_plt) && !(SYMBOL_CALLS_LOCAL (info, tga) - || (ELF_ST_VISIBILITY (tga->other) != STV_DEFAULT - && tga->root.type == bfd_link_hash_undefweak))) + || UNDEFWEAK_NO_DYNAMIC_RELOC (info, tga))) { struct plt_entry *ent; for (ent = tga->plt.plist; ent != NULL; ent = ent->next) @@ -5598,12 +5410,13 @@ ppc_elf_tls_optimize (bfd *obfd ATTRIBUTE_UNUSED, symtab_hdr->contents = (unsigned char *) locsyms; } } + htab->do_tls_opt = 1; return TRUE; } -/* Return true if we have dynamic relocs that apply to read-only sections. */ +/* Find dynamic relocs for H that apply to read-only sections. */ -static bfd_boolean +static asection * readonly_dynrelocs (struct elf_link_hash_entry *h) { struct elf_dyn_relocs *p; @@ -5612,11 +5425,40 @@ readonly_dynrelocs (struct elf_link_hash_entry *h) { asection *s = p->sec->output_section; - if (s != NULL - && ((s->flags & (SEC_READONLY | SEC_ALLOC)) - == (SEC_READONLY | SEC_ALLOC))) - return TRUE; + 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. */ + +static bfd_boolean +alias_readonly_dynrelocs (struct elf_link_hash_entry *h) +{ + struct ppc_elf_link_hash_entry *eh = ppc_elf_hash_entry (h); + do + { + if (readonly_dynrelocs (&eh->elf)) + return TRUE; + eh = ppc_elf_hash_entry (eh->elf.u.alias); + } while (eh != NULL && &eh->elf != h); + + return FALSE; +} + +/* Return whether H has pc-relative dynamic relocs. */ + +static bfd_boolean +pc_dynrelocs (struct elf_link_hash_entry *h) +{ + struct elf_dyn_relocs *p; + + for (p = ppc_elf_hash_entry (h)->dyn_relocs; p != NULL; p = p->next) + if (p->pc_count != 0) + return TRUE; return FALSE; } @@ -5643,7 +5485,7 @@ ppc_elf_adjust_dynamic_symbol (struct bfd_link_info *info, BFD_ASSERT (htab->elf.dynobj != NULL && (h->needs_plt || h->type == STT_GNU_IFUNC - || h->u.weakdef != NULL + || h->is_weakalias || (h->def_dynamic && h->ref_regular && !h->def_regular))); @@ -5653,6 +5495,13 @@ ppc_elf_adjust_dynamic_symbol (struct bfd_link_info *info, || h->type == STT_GNU_IFUNC || h->needs_plt) { + bfd_boolean local = (SYMBOL_CALLS_LOCAL (info, h) + || UNDEFWEAK_NO_DYNAMIC_RELOC (info, h)); + /* Discard dyn_relocs when non-pic if we've decided that a + function symbol is local. */ + if (!bfd_link_pic (info) && local) + ppc_elf_hash_entry (h)->dyn_relocs = NULL; + /* Clear procedure linkage table information for any symbol that won't need a .plt entry. */ struct plt_entry *ent; @@ -5660,10 +5509,7 @@ ppc_elf_adjust_dynamic_symbol (struct bfd_link_info *info, if (ent->plt.refcount > 0) break; if (ent == NULL - || (h->type != STT_GNU_IFUNC - && (SYMBOL_CALLS_LOCAL (info, h) - || (ELF_ST_VISIBILITY (h->other) != STV_DEFAULT - && h->root.type == bfd_link_hash_undefweak)))) + || (h->type != STT_GNU_IFUNC && local)) { /* A PLT entry is not required/allowed when: @@ -5691,19 +5537,26 @@ ppc_elf_adjust_dynamic_symbol (struct bfd_link_info *info, resolution of the symbol to be set at load time rather than link time. */ if ((h->pointer_equality_needed - || (!h->ref_regular_nonweak && h->non_got_ref)) + || (h->non_got_ref + && !h->ref_regular_nonweak + && !UNDEFWEAK_NO_DYNAMIC_RELOC (info, h))) && !htab->is_vxworks && !ppc_elf_hash_entry (h)->has_sda_refs && !readonly_dynrelocs (h)) { h->pointer_equality_needed = 0; - /* After adjust_dynamic_symbol, non_got_ref set in the - non-pic case means that dyn_relocs for this symbol - should be discarded. */ - h->non_got_ref = 0; + /* If we haven't seen a branch reloc then we don't need + a plt entry. */ + if (!h->needs_plt) + h->plt.plist = NULL; } + 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. */ + ppc_elf_hash_entry (h)->dyn_relocs = NULL; } h->protected_def = 0; + /* Function symbols can't have copy relocs. */ return TRUE; } else @@ -5712,14 +5565,14 @@ ppc_elf_adjust_dynamic_symbol (struct bfd_link_info *info, /* If this is a weak symbol, and there is a real definition, the processor independent code will have arranged for us to see the real definition first, and we can just use the same value. */ - if (h->u.weakdef != NULL) + if (h->is_weakalias) { - BFD_ASSERT (h->u.weakdef->root.type == bfd_link_hash_defined - || h->u.weakdef->root.type == bfd_link_hash_defweak); - h->root.u.def.section = h->u.weakdef->root.u.def.section; - h->root.u.def.value = h->u.weakdef->root.u.def.value; + struct elf_link_hash_entry *def = weakdef (h); + BFD_ASSERT (def->root.type == bfd_link_hash_defined); + h->root.u.def.section = def->root.u.def.section; + h->root.u.def.value = def->root.u.def.value; if (ELIMINATE_COPY_RELOCS) - h->non_got_ref = h->u.weakdef->non_got_ref; + h->non_got_ref = def->non_got_ref; return TRUE; } @@ -5756,16 +5609,12 @@ ppc_elf_adjust_dynamic_symbol (struct bfd_link_info *info, && htab->params->pic_fixup == 0 && info->disable_target_specific_optimizations <= 1) htab->params->pic_fixup = 1; - h->non_got_ref = 0; return TRUE; } /* If -z nocopyreloc was given, we won't generate them either. */ if (info->nocopyreloc) - { - h->non_got_ref = 0; - return TRUE; - } + return TRUE; /* If we didn't find any dynamic relocs in read-only sections, then we'll be keeping the dynamic relocs and avoiding the copy reloc. @@ -5777,11 +5626,8 @@ ppc_elf_adjust_dynamic_symbol (struct bfd_link_info *info, && !ppc_elf_hash_entry (h)->has_sda_refs && !htab->is_vxworks && !h->def_regular - && !readonly_dynrelocs (h)) - { - h->non_got_ref = 0; - return TRUE; - } + && !alias_readonly_dynrelocs (h)) + return TRUE; /* We must allocate the symbol in our .dynbss section, which will become part of the .bss section of the executable. There will be @@ -5823,6 +5669,8 @@ ppc_elf_adjust_dynamic_symbol (struct bfd_link_info *info, h->needs_copy = 1; } + /* We no longer want dyn_relocs. */ + ppc_elf_hash_entry (h)->dyn_relocs = NULL; return _bfd_elf_adjust_dynamic_copy (info, h, s); } @@ -5916,16 +5764,57 @@ allocate_got (struct ppc_elf_link_hash_table *htab, unsigned int need) return where; } -/* If H is undefined weak, make it dynamic if that makes sense. */ +/* Calculate size of GOT entries for symbol given its TLS_MASK. + TLS_LD is excluded because those go in a special GOT slot. */ + +static inline unsigned int +got_entries_needed (int tls_mask) +{ + unsigned int need; + if ((tls_mask & TLS_TLS) == 0) + need = 4; + else + { + need = 0; + if ((tls_mask & TLS_GD) != 0) + need += 8; + if ((tls_mask & (TLS_TPREL | TLS_TPRELGD)) != 0) + need += 4; + if ((tls_mask & TLS_DTPREL) != 0) + need += 4; + } + return need; +} + +/* Calculate size of relocs needed for symbol given its TLS_MASK and + NEEDed GOT entries. KNOWN says a TPREL offset can be calculated at + link time. */ + +static inline unsigned int +got_relocs_needed (int tls_mask, unsigned int need, bfd_boolean known) +{ + /* All the entries we allocated need relocs. + Except IE in executable with a local symbol. We could also omit + the DTPREL reloc on the second word of a GD entry under the same + condition as that for IE, but ld.so needs to differentiate + LD and GD entries. */ + if ((tls_mask & (TLS_TPREL | TLS_TPRELGD)) != 0 && known) + need -= 4; + return need * sizeof (Elf32_External_Rela) / 4; +} + +/* If H is undefined, make it dynamic if that makes sense. */ static bfd_boolean -ensure_undefweak_dynamic (struct bfd_link_info *info, - struct elf_link_hash_entry *h) +ensure_undef_dynamic (struct bfd_link_info *info, + struct elf_link_hash_entry *h) { struct elf_link_hash_table *htab = elf_hash_table (info); if (htab->dynamic_sections_created - && h->root.type == bfd_link_hash_undefweak + && ((info->dynamic_undefined_weak != 0 + && h->root.type == bfd_link_hash_undefweak) + || h->root.type == bfd_link_hash_undefined) && h->dynindx == -1 && !h->forced_local && ELF_ST_VISIBILITY (h->other) == STV_DEFAULT) @@ -5959,33 +5848,22 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf) { unsigned int need; - /* Make sure this symbol is output as a dynamic symbol. - Undefined weak syms won't yet be marked as dynamic. */ - if (!ensure_undefweak_dynamic (info, &eh->elf)) + /* Make sure this symbol is output as a dynamic symbol. */ + if (!ensure_undef_dynamic (info, &eh->elf)) return FALSE; need = 0; - if ((eh->tls_mask & TLS_TLS) != 0) + if ((eh->tls_mask & TLS_LD) != 0) { - if ((eh->tls_mask & TLS_LD) != 0) - { - if (!eh->elf.def_dynamic) - /* We'll just use htab->tlsld_got.offset. This should - always be the case. It's a little odd if we have - a local dynamic reloc against a non-local symbol. */ - htab->tlsld_got.refcount += 1; - else - need += 8; - } - if ((eh->tls_mask & TLS_GD) != 0) + if (!eh->elf.def_dynamic) + /* We'll just use htab->tlsld_got.offset. This should + always be the case. It's a little odd if we have + a local dynamic reloc against a non-local symbol. */ + htab->tlsld_got.refcount += 1; + else need += 8; - if ((eh->tls_mask & (TLS_TPREL | TLS_TPRELGD)) != 0) - need += 4; - if ((eh->tls_mask & TLS_DTPREL) != 0) - need += 4; } - else - need += 4; + need += got_entries_needed (eh->tls_mask); if (need == 0) eh->elf.got.offset = (bfd_vma) -1; else @@ -5995,29 +5873,42 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf) || (htab->elf.dynamic_sections_created && eh->elf.dynindx != -1 && !SYMBOL_REFERENCES_LOCAL (info, &eh->elf))) - && (ELF_ST_VISIBILITY (eh->elf.other) == STV_DEFAULT - || eh->elf.root.type != bfd_link_hash_undefweak)) + && !UNDEFWEAK_NO_DYNAMIC_RELOC (info, &eh->elf)) { - asection *rsec = htab->elf.srelgot; - + asection *rsec; + bfd_boolean tprel_known = (bfd_link_executable (info) + && SYMBOL_REFERENCES_LOCAL (info, + &eh->elf)); + + need = got_relocs_needed (eh->tls_mask, need, tprel_known); + if ((eh->tls_mask & TLS_LD) != 0 && eh->elf.def_dynamic) + need -= sizeof (Elf32_External_Rela); + rsec = htab->elf.srelgot; if (eh->elf.type == STT_GNU_IFUNC) rsec = htab->elf.irelplt; - /* All the entries we allocated need relocs. - Except LD only needs one. */ - if ((eh->tls_mask & TLS_LD) != 0 - && eh->elf.def_dynamic) - need -= 4; - rsec->size += need * (sizeof (Elf32_External_Rela) / 4); + rsec->size += need; } } } else eh->elf.got.offset = (bfd_vma) -1; + /* If no dynamic sections we can't have dynamic relocs, except for + IFUNCs which are handled even in static executables. */ if (!htab->elf.dynamic_sections_created && h->type != STT_GNU_IFUNC) eh->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; + + /* 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; + if (eh->dyn_relocs == NULL) ; @@ -6062,24 +5953,10 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf) } } - /* Discard relocs on undefined symbols that must be local. */ - if (eh->dyn_relocs != NULL - && h->root.type == bfd_link_hash_undefined - && (ELF_ST_VISIBILITY (h->other) == STV_HIDDEN - || ELF_ST_VISIBILITY (h->other) == STV_INTERNAL)) - eh->dyn_relocs = NULL; - - /* Also discard relocs on undefined weak syms with non-default - visibility. */ - if (eh->dyn_relocs != NULL - && h->root.type == bfd_link_hash_undefweak) + if (eh->dyn_relocs != NULL) { - if (ELF_ST_VISIBILITY (h->other) != STV_DEFAULT) - eh->dyn_relocs = NULL; - - /* Make sure undefined weak symbols are output as a dynamic - symbol in PIEs. */ - else if (!ensure_undefweak_dynamic (info, h)) + /* Make sure this symbol is output as a dynamic symbol. */ + if (!ensure_undef_dynamic (info, h)) return FALSE; } } @@ -6088,16 +5965,16 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf) /* For the non-pic case, discard space for relocs against symbols which turn out to need copy relocs or are not dynamic. */ - if (!h->non_got_ref + if (h->dynamic_adjusted && !h->def_regular + && !ELF_COMMON_DEF_P (h) && !(h->protected_def && eh->has_addr16_ha && eh->has_addr16_lo && htab->params->pic_fixup > 0)) { - /* Make sure this symbol is output as a dynamic symbol. - Undefined weak syms won't yet be marked as dynamic. */ - if (!ensure_undefweak_dynamic (info, h)) + /* Make sure this symbol is output as a dynamic symbol. */ + if (!ensure_undef_dynamic (info, h)) return FALSE; if (h->dynindx == -1) @@ -6269,14 +6146,22 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf) read-only sections. */ static bfd_boolean -maybe_set_textrel (struct elf_link_hash_entry *h, void *info) +maybe_set_textrel (struct elf_link_hash_entry *h, void *info_p) { + asection *sec; + if (h->root.type == bfd_link_hash_indirect) return TRUE; - if (readonly_dynrelocs (h)) + sec = readonly_dynrelocs (h); + if (sec != NULL) { - ((struct bfd_link_info *) info)->flags |= DF_TEXTREL; + struct bfd_link_info *info = (struct bfd_link_info *) info_p; + + info->flags |= DF_TEXTREL; + info->callbacks->minfo + (_("%B: dynamic relocation in read-only section `%A'\n"), + sec->owner, sec); /* Not an error, just cut short the traversal. */ return FALSE; @@ -6381,7 +6266,11 @@ ppc_elf_size_dynamic_sections (bfd *output_bfd, if ((p->sec->output_section->flags & (SEC_READONLY | SEC_ALLOC)) == (SEC_READONLY | SEC_ALLOC)) - info->flags |= DF_TEXTREL; + { + info->flags |= DF_TEXTREL; + info->callbacks->minfo (_("%B: dynamic relocation in read-only section `%A'\n"), + p->sec->owner, p->sec); + } } } } @@ -6400,20 +6289,10 @@ ppc_elf_size_dynamic_sections (bfd *output_bfd, for (; local_got < end_local_got; ++local_got, ++lgot_masks) if (*local_got > 0) { - unsigned int need = 0; - if ((*lgot_masks & TLS_TLS) != 0) - { - if ((*lgot_masks & TLS_GD) != 0) - need += 8; - if ((*lgot_masks & TLS_LD) != 0) - htab->tlsld_got.refcount += 1; - if ((*lgot_masks & (TLS_TPREL | TLS_TPRELGD)) != 0) - need += 4; - if ((*lgot_masks & TLS_DTPREL) != 0) - need += 4; - } - else - need += 4; + unsigned int need; + if ((*lgot_masks & TLS_LD) != 0) + htab->tlsld_got.refcount += 1; + need = got_entries_needed (*lgot_masks); if (need == 0) *local_got = (bfd_vma) -1; else @@ -6421,10 +6300,14 @@ ppc_elf_size_dynamic_sections (bfd *output_bfd, *local_got = allocate_got (htab, need); if (bfd_link_pic (info)) { - asection *srel = htab->elf.srelgot; + asection *srel; + bfd_boolean tprel_known = bfd_link_executable (info); + + need = got_relocs_needed (*lgot_masks, need, tprel_known); + srel = htab->elf.srelgot; if ((*lgot_masks & PLT_IFUNC) != 0) srel = htab->elf.irelplt; - srel->size += need * (sizeof (Elf32_External_Rela) / 4); + srel->size += need; } } } @@ -7885,7 +7768,7 @@ ppc_elf_relocate_section (bfd *output_bfd, wrel->r_addend = 0; /* For ld -r, remove relocations in debug sections against - sections defined in discarded sections. Not done for + symbols defined in discarded sections. Not done for non-debug to preserve relocs in .eh_frame which the eh_frame editing code expects to be present. */ if (bfd_link_relocatable (info) @@ -8233,7 +8116,7 @@ ppc_elf_relocate_section (bfd *output_bfd, wrel->r_info = ELF32_R_INFO (0, R_PPC_ADDR16_HA); wrel->r_addend = got_addr; insn &= ~0xffff; - insn |= ((unsigned int )(got_addr + 0x8000) >> 16) & 0xffff; + insn |= ((unsigned int) (got_addr + 0x8000) >> 16) & 0xffff; bfd_put_32 (input_bfd, insn, p); /* Convert lis to lwz, loading address from GOT. */ @@ -8259,9 +8142,9 @@ ppc_elf_relocate_section (bfd *output_bfd, r_type = R_PPC_GOT16_LO; } else - info->callbacks->einfo + _bfd_error_handler /* xgettext:c-format */ - (_("%H: error: %s with unexpected instruction %x\n"), + (_("%B(%A+%#Lx): error: %s with unexpected instruction %#x"), input_bfd, input_section, rel->r_offset, "R_PPC_ADDR16_HA", insn); } @@ -8294,9 +8177,9 @@ ppc_elf_relocate_section (bfd *output_bfd, rel->r_info = ELF32_R_INFO (0, r_type); } else - info->callbacks->einfo + _bfd_error_handler /* xgettext:c-format */ - (_("%H: error: %s with unexpected instruction %x\n"), + (_("%B(%A+%#Lx): error: %s with unexpected instruction %#x"), input_bfd, input_section, rel->r_offset, "R_PPC_ADDR16_LO", insn); } @@ -8369,6 +8252,7 @@ ppc_elf_relocate_section (bfd *output_bfd, loc += (htab->elf.irelplt->reloc_count++ * sizeof (Elf32_External_Rela)); bfd_elf32_swap_reloca_out (output_bfd, &rela, loc); + htab->local_ifunc_resolver = 1; ent->plt.offset |= 1; } @@ -8396,10 +8280,44 @@ ppc_elf_relocate_section (bfd *output_bfd, } addend = rel->r_addend; - tls_type = 0; howto = NULL; if (r_type < R_PPC_max) howto = ppc_elf_howto_table[r_type]; + + switch (r_type) + { + default: + break; + + case R_PPC_TPREL16_HA: + if (htab->do_tls_opt && relocation + addend + 0x8000 < 0x10000) + { + bfd_byte *p = contents + (rel->r_offset & ~3); + unsigned int insn = bfd_get_32 (input_bfd, p); + if ((insn & ((0x3f << 26) | 0x1f << 16)) + != ((15u << 26) | (2 << 16)) /* addis rt,2,imm */) + /* xgettext:c-format */ + info->callbacks->minfo + (_("%H: warning: %s unexpected insn %#x.\n"), + input_bfd, input_section, rel->r_offset, howto->name, insn); + else + bfd_put_32 (input_bfd, NOP, p); + } + break; + + case R_PPC_TPREL16_LO: + if (htab->do_tls_opt && relocation + addend + 0x8000 < 0x10000) + { + bfd_byte *p = contents + (rel->r_offset & ~3); + unsigned int insn = bfd_get_32 (input_bfd, p); + insn &= ~(0x1f << 16); + insn |= 2 << 16; + bfd_put_32 (input_bfd, insn, p); + } + break; + } + + tls_type = 0; switch (r_type) { default: @@ -8479,8 +8397,7 @@ ppc_elf_relocate_section (bfd *output_bfd, if (!htab->elf.dynamic_sections_created || h->dynindx == -1 || SYMBOL_REFERENCES_LOCAL (info, h) - || (ELF_ST_VISIBILITY (h->other) != STV_DEFAULT - && h->root.type == bfd_link_hash_undefweak)) + || UNDEFWEAK_NO_DYNAMIC_RELOC (info, h)) /* This is actually a static link, or it is a -Bsymbolic link and the symbol is defined locally, or the symbol was forced to be local @@ -8549,15 +8466,23 @@ ppc_elf_relocate_section (bfd *output_bfd, if (indx != 0 || (bfd_link_pic (info) && (h == NULL - || ELF_ST_VISIBILITY (h->other) == STV_DEFAULT - || h->root.type != bfd_link_hash_undefweak - || offp == &htab->tlsld_got.offset))) + || !UNDEFWEAK_NO_DYNAMIC_RELOC (info, h) + || offp == &htab->tlsld_got.offset) + && !(tls_ty == (TLS_TLS | TLS_TPREL) + && bfd_link_executable (info) + && SYMBOL_REFERENCES_LOCAL (info, h)))) { asection *rsec = htab->elf.srelgot; bfd_byte * loc; if (ifunc != NULL) - rsec = htab->elf.irelplt; + { + rsec = htab->elf.irelplt; + if (indx == 0) + htab->local_ifunc_resolver = 1; + else if (is_static_defined (h)) + htab->maybe_local_ifunc_resolver = 1; + } outrel.r_offset = (htab->elf.sgot->output_section->vma + htab->elf.sgot->output_offset + off); @@ -8609,10 +8534,6 @@ ppc_elf_relocate_section (bfd *output_bfd, else { bfd_vma value = relocation; - int tlsopt = (htab->plt_type == PLT_NEW - && !htab->params->no_tls_get_addr_opt - && htab->tls_get_addr != NULL - && htab->tls_get_addr->plt.plist != NULL); if (tls_ty != 0) { @@ -8624,8 +8545,7 @@ ppc_elf_relocate_section (bfd *output_bfd, value = 0; else value -= htab->elf.tls_sec->vma + DTP_OFFSET; - if ((tls_ty & TLS_TPREL) - || (tlsopt && !(tls_ty & TLS_DTPREL))) + if (tls_ty & TLS_TPREL) value += DTP_OFFSET - TP_OFFSET; } @@ -8633,7 +8553,7 @@ ppc_elf_relocate_section (bfd *output_bfd, { bfd_put_32 (input_bfd, value, htab->elf.sgot->contents + off + 4); - value = !tlsopt; + value = 1; } } bfd_put_32 (input_bfd, value, @@ -8760,8 +8680,8 @@ ppc_elf_relocate_section (bfd *output_bfd, if (htab->elf.tls_sec != NULL) addend -= htab->elf.tls_sec->vma + TP_OFFSET; /* The TPREL16 relocs shouldn't really be used in shared - libs as they will result in DT_TEXTREL being set, but - support them anyway. */ + libs or with non-local symbols as that will result in + DT_TEXTREL being set, but support them anyway. */ goto dodyn; case R_PPC_TPREL32: @@ -8827,29 +8747,19 @@ ppc_elf_relocate_section (bfd *output_bfd, || is_vxworks_tls) break; - if ((bfd_link_pic (info) - && !(h != NULL - && ((h->root.type == bfd_link_hash_undefined - && (ELF_ST_VISIBILITY (h->other) == STV_HIDDEN - || ELF_ST_VISIBILITY (h->other) == STV_INTERNAL)) - || (h->root.type == bfd_link_hash_undefweak - && ELF_ST_VISIBILITY (h->other) != STV_DEFAULT))) - && (must_be_dyn_reloc (info, r_type) - || !SYMBOL_CALLS_LOCAL (info, h))) - || (ELIMINATE_COPY_RELOCS - && !bfd_link_pic (info) - && h != NULL - && h->dynindx != -1 - && !h->non_got_ref - && !h->def_regular - && !(h->protected_def - && ppc_elf_hash_entry (h)->has_addr16_ha - && ppc_elf_hash_entry (h)->has_addr16_lo - && htab->params->pic_fixup > 0))) + if (bfd_link_pic (info) + ? ((h == NULL + || ppc_elf_hash_entry (h)->dyn_relocs != NULL) + && ((h != NULL && pc_dynrelocs (h)) + || must_be_dyn_reloc (info, r_type))) + : (h != NULL + && ppc_elf_hash_entry (h)->dyn_relocs != NULL)) { int skip; bfd_byte *loc; asection *sreloc; + long indx = 0; + #ifdef DEBUG fprintf (stderr, "ppc_elf_relocate_section needs to " "create relocation for %s\n", @@ -8860,12 +8770,6 @@ ppc_elf_relocate_section (bfd *output_bfd, /* When generating a shared object, these relocations are copied into the output file to be resolved at run time. */ - sreloc = elf_section_data (input_section)->sreloc; - if (ifunc) - sreloc = htab->elf.irelplt; - if (sreloc == NULL) - return FALSE; - skip = 0; outrel.r_offset = _bfd_elf_section_offset (output_bfd, info, input_section, @@ -8878,14 +8782,12 @@ ppc_elf_relocate_section (bfd *output_bfd, if (skip) memset (&outrel, 0, sizeof outrel); - else if ((h != NULL - && (h->root.type == bfd_link_hash_undefined - || h->root.type == bfd_link_hash_undefweak)) - || !SYMBOL_REFERENCES_LOCAL (info, h)) + else if (!SYMBOL_REFERENCES_LOCAL (info, h)) { - BFD_ASSERT (h->dynindx != -1); + indx = h->dynindx; + BFD_ASSERT (indx != -1); unresolved_reloc = FALSE; - outrel.r_info = ELF32_R_INFO (h->dynindx, r_type); + outrel.r_info = ELF32_R_INFO (indx, r_type); outrel.r_addend = rel->r_addend; } else @@ -8894,8 +8796,6 @@ ppc_elf_relocate_section (bfd *output_bfd, if (r_type != R_PPC_ADDR32) { - long indx = 0; - if (ifunc != NULL) { /* If we get here when building a static @@ -8960,6 +8860,18 @@ ppc_elf_relocate_section (bfd *output_bfd, outrel.r_info = ELF32_R_INFO (0, R_PPC_RELATIVE); } + sreloc = elf_section_data (input_section)->sreloc; + if (ifunc) + { + sreloc = htab->elf.irelplt; + if (indx == 0) + htab->local_ifunc_resolver = 1; + else if (is_static_defined (h)) + htab->maybe_local_ifunc_resolver = 1; + } + if (sreloc == NULL) + return FALSE; + loc = sreloc->contents; loc += sreloc->reloc_count++ * sizeof (Elf32_External_Rela); bfd_elf32_swap_reloca_out (output_bfd, &outrel, loc); @@ -8976,34 +8888,6 @@ ppc_elf_relocate_section (bfd *output_bfd, break; } } - else if (r_type == R_PPC_DTPMOD32 - && htab->plt_type == PLT_NEW - && !htab->params->no_tls_get_addr_opt - && htab->tls_get_addr != NULL - && htab->tls_get_addr->plt.plist != NULL) - { - /* Set up for __tls_get_addr_opt stub when this entry - does not have dynamic relocs. */ - relocation = 0; - /* Set up the next word for local dynamic. If it turns - out to be global dynamic, the reloc will overwrite - this value. */ - if (rel->r_offset + 8 <= input_section->size) - bfd_put_32 (input_bfd, DTP_OFFSET - TP_OFFSET, - contents + rel->r_offset + 4); - } - else if (r_type == R_PPC_DTPREL32 - && htab->plt_type == PLT_NEW - && !htab->params->no_tls_get_addr_opt - && htab->tls_get_addr != NULL - && htab->tls_get_addr->plt.plist != NULL - && rel > relocs - && rel[-1].r_info == ELF32_R_INFO (r_symndx, R_PPC_DTPMOD32) - && rel[-1].r_offset + 4 == rel->r_offset) - { - /* __tls_get_addr_opt stub value. */ - addend += DTP_OFFSET - TP_OFFSET; - } break; case R_PPC_RELAX_PLT: @@ -9471,6 +9355,10 @@ ppc_elf_relocate_section (bfd *output_bfd, } goto copy_reloc; + case R_PPC_VLE_ADDR20: + ppc_elf_vle_split20 (output_bfd, contents + rel->r_offset, relocation); + continue; + /* Relocate against the beginning of the section. */ case R_PPC_SECTOFF: case R_PPC_SECTOFF_LO: @@ -10250,12 +10138,19 @@ ppc_elf_finish_dynamic_symbol (bfd *output_bfd, if (!htab->elf.dynamic_sections_created || h->dynindx == -1) - loc = (htab->elf.irelplt->contents - + (htab->elf.irelplt->reloc_count++ - * sizeof (Elf32_External_Rela))); + { + loc = (htab->elf.irelplt->contents + + (htab->elf.irelplt->reloc_count++ + * sizeof (Elf32_External_Rela))); + htab->local_ifunc_resolver = 1; + } else - loc = (htab->elf.srelplt->contents - + reloc_index * sizeof (Elf32_External_Rela)); + { + loc = (htab->elf.srelplt->contents + + reloc_index * sizeof (Elf32_External_Rela)); + if (h->type == STT_GNU_IFUNC && is_static_defined (h)) + htab->maybe_local_ifunc_resolver = 1; + } bfd_elf32_swap_reloca_out (output_bfd, &rela, loc); if (!h->def_regular) @@ -10355,7 +10250,7 @@ ppc_elf_finish_dynamic_symbol (bfd *output_bfd, if (ppc_elf_hash_entry (h)->has_sda_refs) s = htab->relsbss; - else if ((h->root.u.def.section->flags & SEC_READONLY) != 0) + else if (h->root.u.def.section == htab->elf.sdynrelro) s = htab->elf.sreldynrelro; else s = htab->elf.srelbss; @@ -10460,6 +10355,17 @@ ppc_elf_finish_dynamic_sections (bfd *output_bfd, dyn.d_un.d_ptr = got; 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) + info->callbacks->einfo + (_("%P: warning: text relocations and GNU indirect " + "functions may result in a segfault at runtime\n")); + continue; + default: if (htab->is_vxworks && elf_vxworks_finish_dynamic_entry (output_bfd, &dyn)) @@ -10911,11 +10817,11 @@ ppc_elf_finish_dynamic_sections (bfd *output_bfd, #define elf_backend_object_p ppc_elf_object_p #define elf_backend_gc_mark_hook ppc_elf_gc_mark_hook -#define elf_backend_gc_sweep_hook ppc_elf_gc_sweep_hook #define elf_backend_section_from_shdr ppc_elf_section_from_shdr #define elf_backend_relocate_section ppc_elf_relocate_section #define elf_backend_create_dynamic_sections ppc_elf_create_dynamic_sections #define elf_backend_check_relocs ppc_elf_check_relocs +#define elf_backend_relocs_compatible _bfd_elf_relocs_compatible #define elf_backend_copy_indirect_symbol ppc_elf_copy_indirect_symbol #define elf_backend_adjust_dynamic_symbol ppc_elf_adjust_dynamic_symbol #define elf_backend_add_symbol_hook ppc_elf_add_symbol_hook @@ -10925,7 +10831,7 @@ ppc_elf_finish_dynamic_sections (bfd *output_bfd, #define elf_backend_finish_dynamic_sections ppc_elf_finish_dynamic_sections #define elf_backend_fake_sections ppc_elf_fake_sections #define elf_backend_additional_program_headers ppc_elf_additional_program_headers -#define elf_backend_modify_segment_map ppc_elf_modify_segment_map +#define elf_backend_modify_segment_map ppc_elf_modify_segment_map #define elf_backend_grok_prstatus ppc_elf_grok_prstatus #define elf_backend_grok_psinfo ppc_elf_grok_psinfo #define elf_backend_write_core_note ppc_elf_write_core_note @@ -10973,7 +10879,7 @@ ppc_elf_finish_dynamic_sections (bfd *output_bfd, /* VxWorks uses the elf default section flags for .plt. */ static const struct bfd_elf_special_section * -ppc_elf_vxworks_get_sec_type_attr (bfd *abfd ATTRIBUTE_UNUSED, asection *sec) +ppc_elf_vxworks_get_sec_type_attr (bfd *abfd, asection *sec) { if (sec->name == NULL) return NULL; @@ -10995,7 +10901,7 @@ ppc_elf_vxworks_link_hash_table_create (bfd *abfd) if (ret) { struct ppc_elf_link_hash_table *htab - = (struct ppc_elf_link_hash_table *)ret; + = (struct ppc_elf_link_hash_table *)ret; htab->is_vxworks = 1; htab->plt_type = PLT_VXWORKS; htab->plt_entry_size = VXWORKS_PLT_ENTRY_SIZE; @@ -11010,23 +10916,23 @@ static bfd_boolean ppc_elf_vxworks_add_symbol_hook (bfd *abfd, struct bfd_link_info *info, Elf_Internal_Sym *sym, - const char **namep ATTRIBUTE_UNUSED, - flagword *flagsp ATTRIBUTE_UNUSED, + const char **namep, + flagword *flagsp, asection **secp, bfd_vma *valp) { - if (!elf_vxworks_add_symbol_hook(abfd, info, sym,namep, flagsp, secp, - valp)) + if (!elf_vxworks_add_symbol_hook (abfd, info, sym, namep, flagsp, secp, + valp)) return FALSE; - return ppc_elf_add_symbol_hook(abfd, info, sym,namep, flagsp, secp, valp); + return ppc_elf_add_symbol_hook (abfd, info, sym, namep, flagsp, secp, valp); } static void ppc_elf_vxworks_final_write_processing (bfd *abfd, bfd_boolean linker) { - ppc_elf_final_write_processing(abfd, linker); - elf_vxworks_final_write_processing(abfd, linker); + ppc_elf_final_write_processing (abfd, linker); + elf_vxworks_final_write_processing (abfd, linker); } /* On VxWorks, we emit relocations against _PROCEDURE_LINKAGE_TABLE_, so