aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlan Modra <amodra@gmail.com>2016-08-19 11:06:53 +0930
committerAlan Modra <amodra@gmail.com>2016-08-19 11:06:53 +0930
commitd311bc8bf85f8358df21301fe8a357aa1212f80c (patch)
treef588003f96a1c10700bec9c4e59e9631b7d82185
parent8a2058b5e3318a337a6fecd61b91349d1131758e (diff)
downloadbinutils-d311bc8bf85f8358df21301fe8a357aa1212f80c.zip
binutils-d311bc8bf85f8358df21301fe8a357aa1212f80c.tar.gz
binutils-d311bc8bf85f8358df21301fe8a357aa1212f80c.tar.bz2
PowerPC64, Don't copy weak symbol dyn_relocs to weakdef.
At the cost of an extra field in the symbol table hash entries, this simplification to the relocate_section dynamic reloc test should help maintainability. * elf64-ppc.c (struct ppc_link_hash_entry): Add weakref. (ppc64_elf_copy_indirect_symbol): Set weakref. Don't merge dyn_relocs for weakdefs. (alias_readonly_dynrelocs): New function. (ppc64_elf_adjust_dynamic_symbol): Use alias_readonly_dynrelocs. (ppc64_elf_relocate_section): Simplify condition under which dyn_relocs are emitted.
-rw-r--r--bfd/ChangeLog10
-rw-r--r--bfd/elf64-ppc.c98
2 files changed, 77 insertions, 31 deletions
diff --git a/bfd/ChangeLog b/bfd/ChangeLog
index c579a02..bb40525 100644
--- a/bfd/ChangeLog
+++ b/bfd/ChangeLog
@@ -1,5 +1,15 @@
2016-08-19 Alan Modra <amodra@gmail.com>
+ * elf64-ppc.c (struct ppc_link_hash_entry): Add weakref.
+ (ppc64_elf_copy_indirect_symbol): Set weakref. Don't merge
+ dyn_relocs for weakdefs.
+ (alias_readonly_dynrelocs): New function.
+ (ppc64_elf_adjust_dynamic_symbol): Use alias_readonly_dynrelocs.
+ (ppc64_elf_relocate_section): Simplify condition under which
+ dyn_relocs are emitted.
+
+2016-08-19 Alan Modra <amodra@gmail.com>
+
PR 20472
* elf64-ppc.c (ppc64_elf_before_check_relocs): Tweak abiversion test.
(readonly_dynrelocs): Comment fix.
diff --git a/bfd/elf64-ppc.c b/bfd/elf64-ppc.c
index bcf7170..286130c 100644
--- a/bfd/elf64-ppc.c
+++ b/bfd/elf64-ppc.c
@@ -3950,6 +3950,9 @@ struct ppc_link_hash_entry
/* Track dynamic relocs copied for this symbol. */
struct elf_dyn_relocs *dyn_relocs;
+ /* Chain of aliases referring to a weakdef. */
+ struct ppc_link_hash_entry *weakref;
+
/* Link between function code and descriptor symbols. */
struct ppc_link_hash_entry *oh;
@@ -4738,6 +4741,45 @@ ppc64_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, don't copy
+ dyn_relocs, plt/got info, or dynindx. We used to copy dyn_relocs
+ in order to simplify readonly_dynrelocs and save a field in the
+ symbol hash entry, but that means dyn_relocs can't be used in any
+ tests about a specific symbol, or affect other symbol flags which
+ are then tested.
+ Chain weakdefs so we can get from the weakdef back to an alias.
+ The list is circular so that we don't need to use u.weakdef as
+ well as this list to look at all aliases. */
+ if (eind->elf.root.type != bfd_link_hash_indirect)
+ {
+ struct ppc_link_hash_entry *cur, *add, *next;
+
+ add = eind;
+ do
+ {
+ cur = edir->weakref;
+ if (cur != NULL)
+ {
+ do
+ {
+ /* We can be called twice for the same symbols.
+ Don't make multiple loops. */
+ if (cur == add)
+ return;
+ cur = cur->weakref;
+ } while (cur != edir);
+ }
+ next = add->weakref;
+ if (cur != add)
+ {
+ add->weakref = edir->weakref != NULL ? edir->weakref : edir;
+ edir->weakref = add;
+ }
+ add = next;
+ } while (add != NULL && add != eind);
+ return;
+ }
+
/* Copy over any dynamic relocs we may have on the indirect sym. */
if (eind->dyn_relocs != NULL)
{
@@ -4770,16 +4812,6 @@ ppc64_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 ppc64_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 got entries that we may have already seen to the
symbol which just became indirect. */
if (eind->elf.got.glist != NULL)
@@ -7122,6 +7154,24 @@ readonly_dynrelocs (struct elf_link_hash_entry *h)
return FALSE;
}
+/* Return true if we have dynamic relocs against H or any of its weak
+ aliases, that apply to read-only sections. */
+
+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;
+ do
+ {
+ if (readonly_dynrelocs (&eh->elf))
+ return TRUE;
+ eh = eh->weakref;
+ } while (eh != NULL && &eh->elf != h);
+
+ return FALSE;
+}
/* Return true if a global entry stub will be created for H. Valid
for ELFv2 before plt entries have been allocated. */
@@ -7192,7 +7242,7 @@ ppc64_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
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))
+ && !alias_readonly_dynrelocs (h))
{
h->pointer_equality_needed = 0;
/* After adjust_dynamic_symbol, non_got_ref set in
@@ -7242,7 +7292,7 @@ ppc64_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
/* 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. */
- || (ELIMINATE_COPY_RELOCS && !readonly_dynrelocs (h))
+ || (ELIMINATE_COPY_RELOCS && !alias_readonly_dynrelocs (h))
/* Protected variables do not work with .dynbss. The copy in
.dynbss won't be used by the shared library with the protected
@@ -14695,25 +14745,11 @@ 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)))
- : (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)))))
+ if (h != NULL
+ ? h->dyn_relocs != NULL
+ : (bfd_link_pic (info)
+ ? must_be_dyn_reloc (info, r_type)
+ : ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC))
{
bfd_boolean skip, relocate;
asection *sreloc;