{
if (abiversion (ibfd) == 0)
set_abiversion (ibfd, 1);
- else if (abiversion (ibfd) == 2)
+ else if (abiversion (ibfd) >= 2)
{
info->callbacks->einfo (_("%P: %B .opd not allowed in ABI"
" version %d\n"),
return TRUE;
}
-/* Return true if we have dynamic relocs that apply to read-only sections. */
+/* Return true if we have dynamic relocs against H that apply to
+ read-only sections. */
static bfd_boolean
readonly_dynrelocs (struct elf_link_hash_entry *h)
return FALSE;
}
+
+/* Return true if a global entry stub will be created for H. Valid
+ for ELFv2 before plt entries have been allocated. */
+
+static bfd_boolean
+global_entry_stub (struct elf_link_hash_entry *h)
+{
+ struct plt_entry *pent;
+
+ if (!h->pointer_equality_needed
+ || h->def_regular)
+ return FALSE;
+
+ for (pent = h->plt.plist; pent != NULL; pent = pent->next)
+ if (pent->plt.refcount > 0
+ && pent->addend == 0)
+ return TRUE;
+
+ return FALSE;
+}
+
/* Adjust a symbol defined by a dynamic object and referenced by a
regular object. The current definition is in some section of the
dynamic object, but we're not including those sections. We have to
h->needs_plt = 0;
h->pointer_equality_needed = 0;
}
- else if (abiversion (info->output_bfd) == 2)
+ else if (abiversion (info->output_bfd) >= 2)
{
/* Taking a function's address in a read/write section
doesn't require us to define the function symbol in the
executable on a global entry stub. A dynamic reloc can
- be used instead. */
- if (h->pointer_equality_needed
- && h->type != STT_GNU_IFUNC
+ be used instead. The reason we prefer a few more dynamic
+ relocs is that calling via a global entry stub costs a
+ few more instructions, and pointer_equality_needed causes
+ extra work in ld.so when resolving these symbols. */
+ if (global_entry_stub (h)
&& !readonly_dynrelocs (h))
{
h->pointer_equality_needed = 0;
+ /* After adjust_dynamic_symbol, non_got_ref set in
+ the non-pic case means that dyn_relocs for this
+ symbol should be discarded. */
h->non_got_ref = 0;
}
- /* After adjust_dynamic_symbol, non_got_ref set in the
- non-shared case means that we have allocated space in
- .dynbss for the symbol and thus dyn_relocs for this
- symbol should be discarded.
- If we get here we know we are making a PLT entry for this
- symbol, and in an executable we'd normally resolve
- relocations against this symbol to the PLT entry. Allow
- dynamic relocs if the reference is weak, and the dynamic
- relocs will not cause text relocation. */
- else if (!h->ref_regular_nonweak
- && h->non_got_ref
- && h->type != STT_GNU_IFUNC
- && !readonly_dynrelocs (h))
- h->non_got_ref = 0;
-
/* If making a plt entry, then we don't need copy relocs. */
return TRUE;
}
struct ppc_link_hash_table *htab;
asection *s;
struct ppc_link_hash_entry *eh;
- struct elf_dyn_relocs *p;
struct got_entry **pgent, *gent;
if (h->root.type == bfd_link_hash_indirect)
allocate_got (h, info, gent);
}
- if (eh->dyn_relocs != NULL
- && (htab->elf.dynamic_sections_created
- || h->type == STT_GNU_IFUNC))
+ if (!htab->elf.dynamic_sections_created
+ && h->type != STT_GNU_IFUNC)
+ eh->dyn_relocs = NULL;
+
+ if (eh->dyn_relocs != NULL)
{
+ struct elf_dyn_relocs *p, **pp;
+
/* In the shared -Bsymbolic case, discard space allocated for
dynamic pc-relative relocs against symbols which turn out to
be defined in regular objects. For the normal shared case,
avoid writing weird assembly. */
if (SYMBOL_CALLS_LOCAL (info, h))
{
- struct elf_dyn_relocs **pp;
-
for (pp = &eh->dyn_relocs; (p = *pp) != NULL; )
{
p->count -= p->pc_count;
}
else if (h->type == STT_GNU_IFUNC)
{
- if (!h->non_got_ref)
+ /* A plt entry is always created when making direct calls to
+ an ifunc, even when building a static executable, but
+ that doesn't cover all cases. We may have only an ifunc
+ initialised function pointer for a given ifunc symbol.
+
+ For ELFv2, dynamic relocations are not required when
+ generating a global entry PLT stub. */
+ if (abiversion (info->output_bfd) >= 2)
+ {
+ if (global_entry_stub (h))
+ eh->dyn_relocs = NULL;
+ }
+
+ /* For ELFv1 we have function descriptors. Descriptors need
+ to be treated like PLT entries and thus have dynamic
+ relocations. One exception is when the function
+ descriptor is copied into .dynbss (which should only
+ happen with ancient versions of gcc). */
+ else if (h->needs_copy)
eh->dyn_relocs = NULL;
}
else if (ELIMINATE_COPY_RELOCS)
{
- /* For the non-shared case, discard space for relocs against
+ /* 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
- && !h->def_regular)
- {
- /* Make sure this symbol is output as a dynamic symbol.
- Undefined weak syms won't yet be marked as dynamic. */
- if (h->dynindx == -1
- && !h->forced_local)
- {
- if (! bfd_elf_link_record_dynamic_symbol (info, h))
- return FALSE;
- }
-
- /* If that succeeded, we know we'll be keeping all the
- relocs. */
- if (h->dynindx != -1)
- goto keep;
- }
-
- eh->dyn_relocs = NULL;
+ /* First make sure this symbol is output as a dynamic symbol.
+ Undefined weak syms won't yet be marked as dynamic. */
+ if (h->root.type == bfd_link_hash_undefweak
+ && !h->non_got_ref
+ && !h->def_regular
+ && h->dynindx == -1
+ && !h->forced_local
+ && !bfd_elf_link_record_dynamic_symbol (info, h))
+ return FALSE;
- keep: ;
+ if (h->non_got_ref
+ || h->def_regular
+ || h->dynindx == -1)
+ eh->dyn_relocs = NULL;
}
/* Finally, allocate space. */
need to define the symbol in the executable on a call stub.
This is to avoid text relocations. */
s->size = (s->size + 15) & -16;
+ h->root.type = bfd_link_hash_defined;
h->root.u.def.section = s;
h->root.u.def.value = s->size;
s->size += 16;
if (NO_OPD_RELOCS && is_opd)
break;
- if ((bfd_link_pic (info)
- && (h == NULL
- || ELF_ST_VISIBILITY (h->elf.other) == STV_DEFAULT
- || h->elf.root.type != bfd_link_hash_undefweak)
- && (must_be_dyn_reloc (info, r_type)
- || !SYMBOL_CALLS_LOCAL (info, &h->elf)))
- || (ELIMINATE_COPY_RELOCS
- && !bfd_link_pic (info)
- && h != NULL
- && h->elf.dynindx != -1
- && !h->elf.non_got_ref
- && !h->elf.def_regular)
- || (!bfd_link_pic (info)
- && (h != NULL
- ? h->elf.type == STT_GNU_IFUNC
- : ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC)))
+ if (bfd_link_pic (info)
+ ? ((h == NULL
+ || ELF_ST_VISIBILITY (h->elf.other) == STV_DEFAULT
+ || h->elf.root.type != bfd_link_hash_undefweak)
+ && (must_be_dyn_reloc (info, r_type)
+ || !SYMBOL_CALLS_LOCAL (info, &h->elf)))
+ : (h == NULL
+ ? ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC
+ : (h->elf.type == STT_GNU_IFUNC
+ ? (abiversion (output_bfd) >= 2
+ ? !(h->elf.pointer_equality_needed
+ && !h->elf.def_regular
+ && h->elf.root.type == bfd_link_hash_defined
+ && h->elf.root.u.def.section == htab->glink)
+ : !h->elf.needs_copy)
+ : (ELIMINATE_COPY_RELOCS
+ && !(h->elf.non_got_ref
+ || h->elf.def_regular
+ || h->elf.dynindx == -1)))))
{
bfd_boolean skip, relocate;
asection *sreloc;