Don't move weak alias dyn_relocs to weakdef
authorAlan Modra <amodra@gmail.com>
Wed, 22 Nov 2017 10:37:03 +0000 (21:07 +1030)
committerAlan Modra <amodra@gmail.com>
Thu, 23 Nov 2017 12:12:33 +0000 (22:42 +1030)
I did this for powerpc64 a while ago.  Not moving weak symbol
dyn_relocs to the strong alias makes for a much simpler test for
dynamic relocs in relocate_section.

This patch implements the change for powerpc and hppa.  Other targets
could benefit from similar changes.

* elf32-hppa.c (pc_dynrelocs): Define.
(elf32_hppa_copy_indirect_symbol): Don't copy dyn_relocs to weakdefs.
(alias_readonly_dynrelocs): New function.
(elf32_hppa_adjust_dynamic_symbol): Don't clear non_got_ref to
indicate dyn_relocs should be discarded, discard them here.
Use alias_readonly_dynrelocs.
(allocate_dynrelocs): Don't test or clear non_got_ref.
(elf32_hppa_relocate_section): Simplify test for dynamic relocs.
* elf32-ppc.c (ppc_elf_copy_indirect_symbol): Don't copy dyn_relocs
to weakdefs.
(alias_readonly_dynrelocs, pc_dynrelocs): New functions.
(ppc_elf_adjust_dynamic_symbol): Don't clear non_got_ref to
indicate dyn_relocs should be discarded, discard them here.
Use alias_readonly_dynrelocs.
(allocate_dynrelocs): Don't test or clear non_got_ref.
(ppc_elf_relocate_section): Simplify test for dynamic relocs.

bfd/ChangeLog
bfd/elf32-hppa.c
bfd/elf32-ppc.c

index 40776497908ea7e52375d294f48233f7b4f41a0b..55fe3b4e61e23419485cd4c2a90c3a4dc14fc347 100644 (file)
@@ -1,3 +1,22 @@
+2017-11-23  Alan Modra  <amodra@gmail.com>
+
+       * elf32-hppa.c (pc_dynrelocs): Define.
+       (elf32_hppa_copy_indirect_symbol): Don't copy dyn_relocs to weakdefs.
+       (alias_readonly_dynrelocs): New function.
+       (elf32_hppa_adjust_dynamic_symbol): Don't clear non_got_ref to
+       indicate dyn_relocs should be discarded, discard them here.
+       Use alias_readonly_dynrelocs.
+       (allocate_dynrelocs): Don't test or clear non_got_ref.
+       (elf32_hppa_relocate_section): Simplify test for dynamic relocs.
+       * elf32-ppc.c (ppc_elf_copy_indirect_symbol): Don't copy dyn_relocs
+       to weakdefs.
+       (alias_readonly_dynrelocs, pc_dynrelocs): New functions.
+       (ppc_elf_adjust_dynamic_symbol): Don't clear non_got_ref to
+       indicate dyn_relocs should be discarded, discard them here.
+       Use alias_readonly_dynrelocs.
+       (allocate_dynrelocs): Don't test or clear non_got_ref.
+       (ppc_elf_relocate_section): Simplify test for dynamic relocs.
+
 2017-11-23  Alan Modra  <amodra@gmail.com>
 
        * elf64-ppc.c (struct ppc_link_hash_entry): Delete weakref field.
index 01060dbef9c38e5123f001decc4addf484ee4969..a0f7060fe1a9ed8f216f9346a5b7c757086e665d 100644 (file)
@@ -162,6 +162,7 @@ static const bfd_byte plt_stub[] =
 #ifndef RELATIVE_DYNRELOCS
 #define RELATIVE_DYNRELOCS 0
 #define IS_ABSOLUTE_RELOC(r_type) 1
+#define pc_dynrelocs(hh) 0
 #endif
 
 /* If ELIMINATE_COPY_RELOCS is non-zero, the linker will try to avoid
@@ -1020,7 +1021,8 @@ elf32_hppa_copy_indirect_symbol (struct bfd_link_info *info,
   hh_dir = hppa_elf_hash_entry (eh_dir);
   hh_ind = hppa_elf_hash_entry (eh_ind);
 
-  if (hh_ind->dyn_relocs != NULL)
+  if (hh_ind->dyn_relocs != NULL
+      && eh_ind->root.type == bfd_link_hash_indirect)
     {
       if (hh_dir->dyn_relocs != NULL)
        {
@@ -1674,6 +1676,24 @@ readonly_dynrelocs (struct elf_link_hash_entry *eh)
   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 *eh)
+{
+  struct elf32_hppa_link_hash_entry *hh = hppa_elf_hash_entry (eh);
+  do
+    {
+      if (readonly_dynrelocs (&hh->eh))
+       return TRUE;
+      hh = hppa_elf_hash_entry (hh->eh.u.alias);
+    } while (hh != NULL && &hh->eh != eh);
+
+  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
@@ -1692,23 +1712,12 @@ elf32_hppa_adjust_dynamic_symbol (struct bfd_link_info *info,
   if (eh->type == STT_FUNC
       || eh->needs_plt)
     {
-      /* Prior to adjust_dynamic_symbol, non_got_ref set means that
-        check_relocs generated dyn_relocs for this symbol.
-        After adjust_dynamic_symbol, non_got_ref clear 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.
-        Unlike other targets, elf32-hppa.c does not define a function
-        symbol in a non-pic executable on PLT stub code, so we don't
-        have a local definition in that case.  */
       bfd_boolean local = (SYMBOL_CALLS_LOCAL (info, eh)
                           || UNDEFWEAK_NO_DYNAMIC_RELOC (info, eh));
-      /* Arrange to discard dyn_relocs if we've decided that a
+      /* Discard dyn_relocs when non-pic if we've decided that a
         function symbol is local.  */
-      if (local)
-       eh->non_got_ref = 0;
+      if (!bfd_link_pic (info) && local)
+       hppa_elf_hash_entry (eh)->dyn_relocs = NULL;
 
       /* If the symbol is used by a plabel, we must allocate a PLT slot.
         The refcounts are not reliable when it has been hidden since
@@ -1732,6 +1741,11 @@ elf32_hppa_adjust_dynamic_symbol (struct bfd_link_info *info,
          eh->needs_plt = 0;
        }
 
+      /* Unlike other targets, elf32-hppa.c does not define a function
+        symbol in a non-pic executable on PLT stub code, so we don't
+        have a local definition in that case.  ie. dyn_relocs can't
+        be discarded.  */
+
       /* Function symbols can't have copy relocs.  */
       return TRUE;
     }
@@ -1772,7 +1786,7 @@ elf32_hppa_adjust_dynamic_symbol (struct bfd_link_info *info,
     return TRUE;
 
   if (ELIMINATE_COPY_RELOCS
-      && !readonly_dynrelocs (eh))
+      && !alias_readonly_dynrelocs (eh))
     {
       /* 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.  */
@@ -1813,7 +1827,7 @@ elf32_hppa_adjust_dynamic_symbol (struct bfd_link_info *info,
     }
 
   /* We no longer want dyn_relocs.  */
-  eh->non_got_ref = 0;
+  hppa_elf_hash_entry (eh)->dyn_relocs = NULL;
   return _bfd_elf_adjust_dynamic_copy (info, eh, sec);
 }
 
@@ -2005,10 +2019,7 @@ allocate_dynrelocs (struct elf_link_hash_entry *eh, void *inf)
     hh->dyn_relocs = NULL;
 
   if (hh->dyn_relocs == NULL)
-    {
-      eh->non_got_ref = 0;
-      return TRUE;
-    }
+    return TRUE;
 
   /* If this is a -Bsymbolic shared link, then we need to discard all
      space allocated for dynamic pc-relative relocs against symbols
@@ -2047,7 +2058,6 @@ allocate_dynrelocs (struct elf_link_hash_entry *eh, void *inf)
         dynamic.  */
 
       if (eh->dynamic_adjusted
-         && eh->non_got_ref
          && !eh->def_regular
          && !ELF_COMMON_DEF_P (eh))
        {
@@ -2055,16 +2065,10 @@ allocate_dynrelocs (struct elf_link_hash_entry *eh, void *inf)
            return FALSE;
 
          if (eh->dynindx == -1)
-           {
-             eh->non_got_ref = 0;
-             hh->dyn_relocs = NULL;
-           }
+           hh->dyn_relocs = NULL;
        }
       else
-       {
-         eh->non_got_ref = 0;
-         hh->dyn_relocs = NULL;
-       }
+       hh->dyn_relocs = NULL;
     }
 
   /* Finally, allocate space.  */
@@ -3895,23 +3899,13 @@ elf32_hppa_relocate_section (bfd *output_bfd,
          if ((input_section->flags & SEC_ALLOC) == 0)
            break;
 
-         /* The reloc types handled here and this conditional
-            expression must match the code in ..check_relocs and
-            allocate_dynrelocs.  ie. We need exactly the same condition
-            as in ..check_relocs, with some extra conditions (dynindx
-            test in this case) to cater for relocs removed by
-            allocate_dynrelocs.  */
-         if ((bfd_link_pic (info)
-              && !(hh != NULL
-                   && ((hh->eh.root.type == bfd_link_hash_undefined
-                        && ELF_ST_VISIBILITY (hh->eh.other) != STV_DEFAULT)
-                       || UNDEFWEAK_NO_DYNAMIC_RELOC (info, &hh->eh)))
-              && (IS_ABSOLUTE_RELOC (r_type)
-                  || !SYMBOL_CALLS_LOCAL (info, &hh->eh)))
-             || (ELIMINATE_COPY_RELOCS
-                 && !bfd_link_pic (info)
-                 && hh != NULL
-                 && hh->eh.non_got_ref))
+         if (bfd_link_pic (info)
+             ? ((hh == NULL
+                 || hh->dyn_relocs != NULL)
+                && ((hh != NULL && pc_dynrelocs (hh))
+                    || IS_ABSOLUTE_RELOC (r_type)))
+             : (hh != NULL
+                && hh->dyn_relocs != NULL))
            {
              Elf_Internal_Rela outrel;
              bfd_boolean skip;
index 756523b1dd32126e900b0f7c1100cf961c560f4c..81e5315322458c224ffa251a754e08f4314d028f 100644 (file)
@@ -3594,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)
@@ -3625,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;
@@ -5441,6 +5435,37 @@ readonly_dynrelocs (struct elf_link_hash_entry *h)
   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;
+}
+
 /* 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
@@ -5474,35 +5499,12 @@ ppc_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
       || h->type == STT_GNU_IFUNC
       || h->needs_plt)
     {
-      /* Prior to adjust_dynamic_symbol, non_got_ref set means that
-        we might need to generate a copy reloc for this symbol.
-        After adjust_dynamic_symbol, non_got_ref is only relevant for
-        non-pic and means that the symbol might have dynamic
-        relocations.  If it is clear then 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 function
-        symbols, defining the symbol on the PLT call stub code.  */
       bfd_boolean local = (SYMBOL_CALLS_LOCAL (info, h)
                           || UNDEFWEAK_NO_DYNAMIC_RELOC (info, h));
-      /* Arrange to discard dyn_relocs if we've decided that a
-        function symbol is local.  It might be possible to discard
-        dyn_relocs here, but when a symbol has a weakdef they have
-        been transferred to the weakdef symbol for the benefit of
-        readonly_dynrelocs.  (See ppc_elf_copy_indirect_symbol.)
-        Not only would we need to handle weakdefs here, but also in
-        allocate_dynrelocs and relocate_section.  The latter is
-        impossible since the weakdef field has been overwritten by
-        that time.  In relocate_section we need a proxy for
-        dyn_relocs and non_got_ref is that proxy.
-        Note that function symbols are not supposed to have weakdefs,
-        but since symbols may not be correctly typed we handle them
-        here.  */
-      h->non_got_ref = (h->is_weakalias
-                       ? weakdef (h)->non_got_ref
-                       : !local && (((struct ppc_elf_link_hash_entry *) h)
-                                    ->dyn_relocs != NULL));
+      /* 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.  */
@@ -5552,10 +5554,10 @@ ppc_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
              if (!h->needs_plt)
                h->plt.plist = NULL;
            }
-         else
+         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.  */
-           h->non_got_ref = 0;
+           ppc_elf_hash_entry (h)->dyn_relocs = NULL;
        }
       h->protected_def = 0;
       /* Function symbols can't have copy relocs.  */
@@ -5628,7 +5630,7 @@ 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))
+      && !alias_readonly_dynrelocs (h))
     return TRUE;
 
   /* We must allocate the symbol in our .dynbss section, which will
@@ -5672,7 +5674,7 @@ ppc_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
     }
 
   /* We no longer want dyn_relocs.  */
-  h->non_got_ref = 0;
+  ppc_elf_hash_entry (h)->dyn_relocs = NULL;
   return _bfd_elf_adjust_dynamic_copy (info, h, s);
 }
 \f
@@ -5912,7 +5914,7 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
     eh->dyn_relocs = NULL;
 
   if (eh->dyn_relocs == NULL)
-    h->non_got_ref = 0;
+    ;
 
   /* In the shared -Bsymbolic case, discard space allocated for
      dynamic pc-relative relocs against symbols which turn out to be
@@ -5968,7 +5970,6 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
         symbols which turn out to need copy relocs or are not
         dynamic.  */
       if (h->dynamic_adjusted
-         && h->non_got_ref
          && !h->def_regular
          && !ELF_COMMON_DEF_P (h)
          && !(h->protected_def
@@ -5981,16 +5982,10 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
            return FALSE;
 
          if (h->dynindx == -1)
-           {
-             h->non_got_ref = 0;
-             eh->dyn_relocs = NULL;
-           }
+           eh->dyn_relocs = NULL;
        }
       else
-       {
-         h->non_got_ref = 0;
-         eh->dyn_relocs = NULL;
-       }
+       eh->dyn_relocs = NULL;
     }
 
   /* Allocate space.  */
@@ -8756,17 +8751,13 @@ 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_DEFAULT)
-                       || UNDEFWEAK_NO_DYNAMIC_RELOC (info, h)))
-              && (must_be_dyn_reloc (info, r_type)
-                  || !SYMBOL_CALLS_LOCAL (info, h)))
-             || (ELIMINATE_COPY_RELOCS
-                 && !bfd_link_pic (info)
-                 && h != NULL
-                 && h->non_got_ref))
+         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;