aboutsummaryrefslogtreecommitdiff
path: root/bfd/elf64-ppc.c
diff options
context:
space:
mode:
authorAlan Modra <amodra@gmail.com>2016-08-19 11:06:41 +0930
committerAlan Modra <amodra@gmail.com>2016-08-19 11:06:41 +0930
commit8a2058b5e3318a337a6fecd61b91349d1131758e (patch)
treedfa9bedd7bf539614107c9e1ededc173a32b5c18 /bfd/elf64-ppc.c
parente47d628fad1517ff91e8d66eb4609d84c35a2b1c (diff)
downloadgdb-8a2058b5e3318a337a6fecd61b91349d1131758e.zip
gdb-8a2058b5e3318a337a6fecd61b91349d1131758e.tar.gz
gdb-8a2058b5e3318a337a6fecd61b91349d1131758e.tar.bz2
PR 20472, PowerPC64 ifunc confusion
This patch fixes quite a lot of confusion in allocate_dynrelocs over ifuncs. Function descriptors make ELFv1 quite different to ELFv2. PR 20472 * elf64-ppc.c (ppc64_elf_before_check_relocs): Tweak abiversion test. (readonly_dynrelocs): Comment fix. (global_entry_stub): New function. (ppc64_elf_adjust_dynamic_symbol): Tweak abiversion test. Match ELFv2 code deciding on dynamic relocs vs. global entry stubs to that in size_global_entry_stubs, handling ifunc too. Delete dead weak sym code. (allocate_dynrelocs): Ensure dyn_relocs field is cleared when no dyn_relocs are needed. Correct handling of ifunc dyn_relocs. Tidy ELIMINATE_COPY_RELOCS code, only setting dynindx for undefweak syms. Expand and correct comments. (size_global_entry_stubs): Ensure symbol is defined. (ppc64_elf_relocate_section): Match condition under which dyn_relocs are emitted to that in allocate_dynrelocs.
Diffstat (limited to 'bfd/elf64-ppc.c')
-rw-r--r--bfd/elf64-ppc.c158
1 files changed, 93 insertions, 65 deletions
diff --git a/bfd/elf64-ppc.c b/bfd/elf64-ppc.c
index 4f854c7..bcf7170 100644
--- a/bfd/elf64-ppc.c
+++ b/bfd/elf64-ppc.c
@@ -5081,7 +5081,7 @@ ppc64_elf_before_check_relocs (bfd *ibfd, struct bfd_link_info *info)
{
if (abiversion (ibfd) == 0)
set_abiversion (ibfd, 1);
- else if (abiversion (ibfd) == 2)
+ else if (abiversion (ibfd) >= 2)
{
info->callbacks->einfo (_("%P: %B .opd not allowed in ABI"
" version %d\n"),
@@ -7102,7 +7102,8 @@ ppc64_elf_func_desc_adjust (bfd *obfd ATTRIBUTE_UNUSED,
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)
@@ -7121,6 +7122,27 @@ 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
@@ -7160,35 +7182,25 @@ ppc64_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
h->needs_plt = 0;
h->pointer_equality_needed = 0;
}
- else if (abiversion (info->output_bfd) == 2)
+ else if (abiversion (info->output_bfd) >= 2)
{
/* Taking a function's address in a read/write section
doesn't require us to define the function symbol in the
executable on a global entry stub. A dynamic reloc can
- be used instead. */
- if (h->pointer_equality_needed
- && h->type != STT_GNU_IFUNC
+ 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;
}
@@ -9538,7 +9550,6 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
struct ppc_link_hash_table *htab;
asection *s;
struct ppc_link_hash_entry *eh;
- struct elf_dyn_relocs *p;
struct got_entry **pgent, *gent;
if (h->root.type == bfd_link_hash_indirect)
@@ -9618,10 +9629,14 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
allocate_got (h, info, gent);
}
- if (eh->dyn_relocs != NULL
- && (htab->elf.dynamic_sections_created
- || h->type == STT_GNU_IFUNC))
+ 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,
@@ -9639,8 +9654,6 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
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;
@@ -9672,36 +9685,47 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
}
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. */
@@ -9818,6 +9842,7 @@ size_global_entry_stubs (struct elf_link_hash_entry *h, void *inf)
need to define the symbol in the executable on a call stub.
This is to avoid text relocations. */
s->size = (s->size + 15) & -16;
+ h->root.type = bfd_link_hash_defined;
h->root.u.def.section = s;
h->root.u.def.value = s->size;
s->size += 16;
@@ -14670,22 +14695,25 @@ ppc64_elf_relocate_section (bfd *output_bfd,
if (NO_OPD_RELOCS && is_opd)
break;
- if ((bfd_link_pic (info)
- && (h == NULL
- || ELF_ST_VISIBILITY (h->elf.other) == STV_DEFAULT
- || h->elf.root.type != bfd_link_hash_undefweak)
- && (must_be_dyn_reloc (info, r_type)
- || !SYMBOL_CALLS_LOCAL (info, &h->elf)))
- || (ELIMINATE_COPY_RELOCS
- && !bfd_link_pic (info)
- && h != NULL
- && h->elf.dynindx != -1
- && !h->elf.non_got_ref
- && !h->elf.def_regular)
- || (!bfd_link_pic (info)
- && (h != NULL
- ? h->elf.type == STT_GNU_IFUNC
- : ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC)))
+ if (bfd_link_pic (info)
+ ? ((h == NULL
+ || 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;