aboutsummaryrefslogtreecommitdiff
path: root/bfd/elf64-ppc.c
diff options
context:
space:
mode:
Diffstat (limited to 'bfd/elf64-ppc.c')
-rw-r--r--bfd/elf64-ppc.c97
1 files changed, 43 insertions, 54 deletions
diff --git a/bfd/elf64-ppc.c b/bfd/elf64-ppc.c
index 1cf7964..181bbdc 100644
--- a/bfd/elf64-ppc.c
+++ b/bfd/elf64-ppc.c
@@ -7177,6 +7177,23 @@ 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
+ || 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 and not an ifunc. We keep dynamic
+ relocs for ifuncs when local rather than always emitting a
+ plt call stub for them and defining the symbol on the call
+ stub. We can't do that for ELFv1 anyway (a function symbol
+ is defined on a descriptor, not code) and it can be faster at
+ run-time due to not needing to bounce through a stub. The
+ dyn_relocs for ifuncs will be applied even in a static
+ executable. */
+ if (!bfd_link_pic (info)
+ && h->type != STT_GNU_IFUNC
+ && local)
+ ((struct ppc_link_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;
@@ -7184,24 +7201,11 @@ ppc64_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)
- || UNDEFWEAK_NO_DYNAMIC_RELOC (info, h)))
- || ((struct ppc_link_hash_entry *) h)->save_res)
+ || (h->type != STT_GNU_IFUNC && local))
{
h->plt.plist = NULL;
h->needs_plt = 0;
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. We either want the symbol to remain
- undefined, or we have a local definition of some sort.
- The "local definition" for non-function symbols may be
- due to creating a local definition in .dynbss, and for
- ELFv2 function symbols, defining the symbol on the PLT
- call stub code. Set non_got_ref here to ensure undef
- weaks stay undefined. */
- h->non_got_ref = 1;
}
else if (abiversion (info->output_bfd) >= 2)
{
@@ -7212,16 +7216,20 @@ ppc64_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
relocs is that calling via a global entry stub costs a
few more instructions, and pointer_equality_needed causes
extra work in ld.so when resolving these symbols. */
- if (global_entry_stub (h)
- && !alias_readonly_dynrelocs (h))
+ if (global_entry_stub (h))
{
- h->pointer_equality_needed = 0;
- /* Say that we do want dynamic relocs. */
- 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;
+ if (!alias_readonly_dynrelocs (h))
+ {
+ h->pointer_equality_needed = 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. */
+ ((struct ppc_link_hash_entry *) h)->dyn_relocs = NULL;
}
/* ELFv2 function symbols can't have copy relocs. */
@@ -7234,7 +7242,6 @@ ppc64_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
plt entry. */
h->plt.plist = NULL;
h->pointer_equality_needed = 0;
- h->non_got_ref = 0;
return TRUE;
}
}
@@ -7282,10 +7289,7 @@ ppc64_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
definition for the variable. Text relocations are preferable
to an incorrect program. */
|| h->protected_def)
- {
- h->non_got_ref = 0;
- return TRUE;
- }
+ return TRUE;
if (h->plt.plist != NULL)
{
@@ -7333,6 +7337,8 @@ ppc64_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
h->needs_copy = 1;
}
+ /* We no longer want dyn_relocs. */
+ ((struct ppc_link_hash_entry *) h)->dyn_relocs = NULL;
return _bfd_elf_adjust_dynamic_copy (info, h, s);
}
@@ -9724,6 +9730,11 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
&& 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))
@@ -9768,36 +9779,14 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
return FALSE;
}
}
- else if (h->type == STT_GNU_IFUNC)
- {
- /* 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)
+ else if (ELIMINATE_COPY_RELOCS && h->type != STT_GNU_IFUNC)
{
/* 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)
+ if (h->dynamic_adjusted
+ && !h->def_regular
+ && !ELF_COMMON_DEF_P (h))
{
/* Make sure this symbol is output as a dynamic symbol. */
if (!ensure_undef_dynamic (info, h))