PowerPC64 dot-symbol compatibility bugfixes
authorAlan Modra <amodra@gmail.com>
Sat, 3 Dec 2016 10:30:01 +0000 (21:00 +1030)
committerAlan Modra <amodra@gmail.com>
Sat, 3 Dec 2016 10:30:01 +0000 (21:00 +1030)
Lots of fixes for the compatibility code that handles linking of
-mcall-aixdesc code (or that generated by 12 year old gcc) with
current ELFv1 ABI code.

1) A reference to a dot-symbol in an object file wasn't satisfied by a
   function descriptor in later object files.
2) The as-needed code had bit-rotted;  Shared libs now need a strong
   reference to be counted as needed.
3) --gc-sections involving dot-symbols was broken, needing
   func_desc_adjust to be run early and lots of other fixes.

bfd/
* elf64-ppc.c (struct ppc_link_hash_entry): Delete "was_undefined".
(struct ppc_link_hash_table): Delete "twiddled_syms".  Add
"need_func_desc_adj".
(lookup_fdh): Link direct fdh sym via oh field and set flags.
(make_fdh): Make strong and weak undefined function descriptor
symbols.
(ppc64_elf_merge_symbol): New function.
(elf_backend_merge_symbol): Define.
(ppc64_elf_archive_symbol_lookup): Don't test undefweak for fake
function descriptors.
(add_symbol_adjust): Don't twiddle symbols to undefweak.
Propagate more ref flags to function descriptor symbol.  Make
some function descriptor symbols dynamic.
(ppc64_elf_before_check_relocs): Only run add_symbol_adjust for
ELFv1.  Set need_func_desc_adj.  Don't fix undefs list.
(ppc64_elf_check_relocs): Set non_ir_ref for descriptors.
Don't call lookup_fdh here.
(ppc64_elf_gc_sections): New function.
(bfd_elf64_bfd_gc_sections): Define.
(ppc64_elf_gc_mark_hook): Mark descriptor.
(func_desc_adjust): Don't make fake function descriptor syms strong
here.  Exit earlier on non-dotsyms.  Take note of elf.dynamic
flag when deciding whether a dynamic function descriptor might
be needed.  Transfer elf.dynamic and set elf.needs_plt.  Move
plt regardless of visibility.  Make descriptor dynamic if
entry sym is dynamic, not for other cases.
(ppc64_elf_func_desc_adjust): Don't run func_desc_adjust if
already done.
(ppc64_elf_edit_opd): Use oh field rather than lookup_fdh.
(ppc64_elf_size_stubs): Likewise.
(ppc_build_one_stub): Don't clear was_undefined.  Only set sym
undefweak if stub symbol is defined.
(undo_symbol_twiddle, ppc64_elf_restore_symbols): Delete.
* elf64-ppc.h (ppc64_elf_restore_symbols): Don't declare.
ld/
* emultempl/ppc64elf.em (gld${EMULATION_NAME}_finish): Don't call
ppc64_elf_restore_symbols.
* testsuite/ld-powerpc/dotsym1.d: New.
* testsuite/ld-powerpc/dotsym2.d: New.
* testsuite/ld-powerpc/dotsym3.d: New.
* testsuite/ld-powerpc/dotsym4.d: New.
* testsuite/ld-powerpc/dotsymref.s: New.
* testsuite/ld-powerpc/nodotsym.s: New.
* testsuite/ld-powerpc/powerpc.exp: Run new tests.

12 files changed:
bfd/ChangeLog
bfd/elf64-ppc.c
bfd/elf64-ppc.h
ld/ChangeLog
ld/emultempl/ppc64elf.em
ld/testsuite/ld-powerpc/dotsym1.d [new file with mode: 0644]
ld/testsuite/ld-powerpc/dotsym2.d [new file with mode: 0644]
ld/testsuite/ld-powerpc/dotsym3.d [new file with mode: 0644]
ld/testsuite/ld-powerpc/dotsym4.d [new file with mode: 0644]
ld/testsuite/ld-powerpc/dotsymref.s [new file with mode: 0644]
ld/testsuite/ld-powerpc/nodotsym.s [new file with mode: 0644]
ld/testsuite/ld-powerpc/powerpc.exp

index 7721b17407cb616be8abcb4a9949b899901f565e..b0dafb275fc2d4f9eca21bcd6724113337851dae 100644 (file)
@@ -1,3 +1,40 @@
+2016-12-03  Alan Modra  <amodra@gmail.com>
+
+       * elf64-ppc.c (struct ppc_link_hash_entry): Delete "was_undefined".
+       (struct ppc_link_hash_table): Delete "twiddled_syms".  Add
+       "need_func_desc_adj".
+       (lookup_fdh): Link direct fdh sym via oh field and set flags.
+       (make_fdh): Make strong and weak undefined function descriptor
+       symbols.
+       (ppc64_elf_merge_symbol): New function.
+       (elf_backend_merge_symbol): Define.
+       (ppc64_elf_archive_symbol_lookup): Don't test undefweak for fake
+       function descriptors.
+       (add_symbol_adjust): Don't twiddle symbols to undefweak.
+       Propagate more ref flags to function descriptor symbol.  Make
+       some function descriptor symbols dynamic.
+       (ppc64_elf_before_check_relocs): Only run add_symbol_adjust for
+       ELFv1.  Set need_func_desc_adj.  Don't fix undefs list.
+       (ppc64_elf_check_relocs): Set non_ir_ref for descriptors.
+       Don't call lookup_fdh here.
+       (ppc64_elf_gc_sections): New function.
+       (bfd_elf64_bfd_gc_sections): Define.
+       (ppc64_elf_gc_mark_hook): Mark descriptor.
+       (func_desc_adjust): Don't make fake function descriptor syms strong
+       here.  Exit earlier on non-dotsyms.  Take note of elf.dynamic
+       flag when deciding whether a dynamic function descriptor might
+       be needed.  Transfer elf.dynamic and set elf.needs_plt.  Move
+       plt regardless of visibility.  Make descriptor dynamic if
+       entry sym is dynamic, not for other cases.
+       (ppc64_elf_func_desc_adjust): Don't run func_desc_adjust if
+       already done.
+       (ppc64_elf_edit_opd): Use oh field rather than lookup_fdh.
+       (ppc64_elf_size_stubs): Likewise.
+       (ppc_build_one_stub): Don't clear was_undefined.  Only set sym
+       undefweak if stub symbol is defined.
+       (undo_symbol_twiddle, ppc64_elf_restore_symbols): Delete.
+       * elf64-ppc.h (ppc64_elf_restore_symbols): Don't declare.
+
 2016-12-03  Alan Modra  <amodra@gmail.com>
 
        * elf64-ppc.c (ppc64_elf_hide_symbol): Access hash table as
index 27328ecf58638bc6c418de10a68503af7cec72d0..f6248745239f7a8e2826f87215629d87f4db5fa7 100644 (file)
@@ -87,6 +87,7 @@ static bfd_vma opd_entry_value
 #define bfd_elf64_bfd_link_hash_table_create  ppc64_elf_link_hash_table_create
 #define bfd_elf64_get_synthetic_symtab       ppc64_elf_get_synthetic_symtab
 #define bfd_elf64_bfd_link_just_syms         ppc64_elf_link_just_syms
+#define bfd_elf64_bfd_gc_sections            ppc64_elf_gc_sections
 
 #define elf_backend_object_p                 ppc64_elf_object_p
 #define elf_backend_grok_prstatus            ppc64_elf_grok_prstatus
@@ -118,6 +119,7 @@ static bfd_vma opd_entry_value
 #define elf_backend_link_output_symbol_hook   ppc64_elf_output_symbol_hook
 #define elf_backend_special_sections         ppc64_elf_special_sections
 #define elf_backend_merge_symbol_attribute    ppc64_elf_merge_symbol_attribute
+#define elf_backend_merge_symbol             ppc64_elf_merge_symbol
 
 /* The name of the dynamic interpreter.  This is put in the .interp
    section.  */
@@ -3978,9 +3980,6 @@ struct ppc_link_hash_entry
      should be set for all globals defined in any opd/toc section.  */
   unsigned int adjust_done:1;
 
-  /* Set if we twiddled this symbol to weak at some stage.  */
-  unsigned int was_undefined:1;
-
   /* Set if this is an out-of-line register save/restore function,
      with non-standard calling convention.  */
   unsigned int save_res:1;
@@ -4087,8 +4086,8 @@ struct ppc_link_hash_table
   /* Set on error.  */
   unsigned int stub_error:1;
 
-  /* Temp used by ppc64_elf_before_check_relocs.  */
-  unsigned int twiddled_syms:1;
+  /* Whether func_desc_adjust needs to be run over symbols.  */
+  unsigned int need_func_desc_adj:1;
 
   /* Incremented every time we size stubs.  */
   unsigned int stub_iteration;
@@ -4898,32 +4897,29 @@ lookup_fdh (struct ppc_link_hash_entry *fh, struct ppc_link_hash_table *htab)
       fh->oh = fdh;
     }
 
-  return ppc_follow_link (fdh);
+  fdh = ppc_follow_link (fdh);
+  fdh->is_func_descriptor = 1;
+  fdh->oh = fh;
+  return fdh;
 }
 
-/* Make a fake function descriptor sym for the code sym FH.  */
+/* Make a fake function descriptor sym for the undefined code sym FH.  */
 
 static struct ppc_link_hash_entry *
 make_fdh (struct bfd_link_info *info,
          struct ppc_link_hash_entry *fh)
 {
-  bfd *abfd;
-  asymbol *newsym;
-  struct bfd_link_hash_entry *bh;
+  bfd *abfd = fh->elf.root.u.undef.abfd;
+  struct bfd_link_hash_entry *bh = NULL;
   struct ppc_link_hash_entry *fdh;
-
-  abfd = fh->elf.root.u.undef.abfd;
-  newsym = bfd_make_empty_symbol (abfd);
-  newsym->name = fh->elf.root.root.string + 1;
-  newsym->section = bfd_und_section_ptr;
-  newsym->value = 0;
-  newsym->flags = BSF_WEAK;
-
-  bh = NULL;
-  if (!_bfd_generic_link_add_one_symbol (info, abfd, newsym->name,
-                                        newsym->flags, newsym->section,
-                                        newsym->value, NULL, FALSE, FALSE,
-                                        &bh))
+  flagword flags = (fh->elf.root.type == bfd_link_hash_undefweak
+                   ? BSF_WEAK
+                   : BSF_GLOBAL);
+
+  if (!_bfd_generic_link_add_one_symbol (info, abfd,
+                                        fh->elf.root.root.string + 1,
+                                        flags, bfd_und_section_ptr, 0,
+                                        NULL, FALSE, FALSE, &bh))
     return NULL;
 
   fdh = (struct ppc_link_hash_entry *) bh;
@@ -5012,6 +5008,22 @@ ppc64_elf_merge_symbol_attribute (struct elf_link_hash_entry *h,
                | ELF_ST_VISIBILITY (h->other));
 }
 
+/* Hook called on merging a symbol.  We use this to clear "fake" since
+   we now have a real symbol.  */
+
+static bfd_boolean
+ppc64_elf_merge_symbol (struct elf_link_hash_entry *h,
+                       const Elf_Internal_Sym *isym ATTRIBUTE_UNUSED,
+                       asection **psec ATTRIBUTE_UNUSED,
+                       bfd_boolean newdef ATTRIBUTE_UNUSED,
+                       bfd_boolean olddef ATTRIBUTE_UNUSED,
+                       bfd *oldbfd ATTRIBUTE_UNUSED,
+                       const asection *oldsec ATTRIBUTE_UNUSED)
+{
+  ((struct ppc_link_hash_entry *) h)->fake = 0;
+  return TRUE;
+}
+
 /* This function makes an old ABI object reference to ".bar" cause the
    inclusion of a new ABI object archive that defines "bar".
    NAME is a symbol defined in an archive.  Return a symbol in the hash
@@ -5030,8 +5042,7 @@ ppc64_elf_archive_symbol_lookup (bfd *abfd,
   if (h != NULL
       /* Don't return this sym if it is a fake function descriptor
         created by add_symbol_adjust.  */
-      && !(h->root.type == bfd_link_hash_undefweak
-          && ((struct ppc_link_hash_entry *) h)->fake))
+      && !((struct ppc_link_hash_entry *) h)->fake)
     return h;
 
   if (name[0] == '.')
@@ -5077,38 +5088,49 @@ add_symbol_adjust (struct ppc_link_hash_entry *eh, struct bfd_link_info *info)
     return FALSE;
 
   fdh = lookup_fdh (eh, htab);
-  if (fdh == NULL)
-    {
-      if (!bfd_link_relocatable (info)
-         && (eh->elf.root.type == bfd_link_hash_undefined
-             || eh->elf.root.type == bfd_link_hash_undefweak)
-         && eh->elf.ref_regular)
-       {
-         /* Make an undefweak function descriptor sym, which is enough to
-            pull in an --as-needed shared lib, but won't cause link
-            errors.  Archives are handled elsewhere.  */
-         fdh = make_fdh (info, eh);
-         if (fdh == NULL)
-           return FALSE;
-         fdh->elf.ref_regular = 1;
-       }
+  if (fdh == NULL
+      && !bfd_link_relocatable (info)
+      && (eh->elf.root.type == bfd_link_hash_undefined
+         || eh->elf.root.type == bfd_link_hash_undefweak)
+      && eh->elf.ref_regular)
+    {
+      /* Make an undefined function descriptor sym, in order to
+        pull in an --as-needed shared lib.  Archives are handled
+        elsewhere.  */
+      fdh = make_fdh (info, eh);
+      if (fdh == NULL)
+       return FALSE;
     }
-  else
+
+  if (fdh != NULL)
     {
       unsigned entry_vis = ELF_ST_VISIBILITY (eh->elf.other) - 1;
       unsigned descr_vis = ELF_ST_VISIBILITY (fdh->elf.other) - 1;
+
+      /* Make both descriptor and entry symbol have the most
+        constraining visibility of either symbol.  */
       if (entry_vis < descr_vis)
        fdh->elf.other += entry_vis - descr_vis;
       else if (entry_vis > descr_vis)
        eh->elf.other += descr_vis - entry_vis;
 
-      if ((fdh->elf.root.type == bfd_link_hash_defined
-          || fdh->elf.root.type == bfd_link_hash_defweak)
-         && eh->elf.root.type == bfd_link_hash_undefined)
-       {
-         eh->elf.root.type = bfd_link_hash_undefweak;
-         eh->was_undefined = 1;
-         htab->twiddled_syms = 1;
+      /* Propagate reference flags from entry symbol to function
+        descriptor symbol.  */
+      fdh->elf.root.non_ir_ref |= eh->elf.root.non_ir_ref;
+      fdh->elf.ref_regular |= eh->elf.ref_regular;
+      fdh->elf.ref_regular_nonweak |= eh->elf.ref_regular_nonweak;
+
+      if (!fdh->elf.forced_local
+         && fdh->elf.dynindx == -1
+         && fdh->elf.versioned != versioned_hidden
+         && (bfd_link_dll (info)
+             || fdh->elf.def_dynamic
+             || fdh->elf.ref_dynamic)
+         && (eh->elf.ref_regular
+             || eh->elf.def_regular))
+       {
+         if (! bfd_elf_link_record_dynamic_symbol (info, &fdh->elf))
+           return FALSE;
        }
     }
 
@@ -5190,18 +5212,14 @@ ppc64_elf_before_check_relocs (bfd *ibfd, struct bfd_link_info *info)
       else if (htab->elf.hgot == NULL
               && strcmp (eh->elf.root.root.string, ".TOC.") == 0)
        htab->elf.hgot = &eh->elf;
-      else if (!add_symbol_adjust (eh, info))
-       return FALSE;
+      else if (abiversion (ibfd) <= 1)
+       {
+         htab->need_func_desc_adj = 1;
+         if (!add_symbol_adjust (eh, info))
+           return FALSE;
+       }
       p = &eh->u.next_dot_sym;
     }
-
-  /* We need to fix the undefs list for any syms we have twiddled to
-     undefweak.  */
-  if (htab->twiddled_syms)
-    {
-      bfd_link_repair_undef_list (&htab->elf.root);
-      htab->twiddled_syms = 0;
-    }
   return TRUE;
 }
 
@@ -5394,12 +5412,17 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
        h = NULL;
       else
        {
+         struct ppc_link_hash_entry *eh;
+
          h = sym_hashes[r_symndx - symtab_hdr->sh_info];
          h = elf_follow_link (h);
+         eh = (struct ppc_link_hash_entry *) h;
 
          /* PR15323, ref flags aren't set for references in the same
             object.  */
          h->root.non_ir_ref = 1;
+         if (eh->is_func && eh->oh != NULL)
+           eh->oh->elf.root.non_ir_ref = 1;
 
          if (h == htab->elf.hgot)
            sec->has_toc_reloc = 1;
@@ -5809,14 +5832,7 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
              && ELF64_R_TYPE ((rel + 1)->r_info) == R_PPC64_TOC)
            {
              if (h != NULL)
-               {
-                 if (h->root.root.string[0] == '.'
-                     && h->root.root.string[1] != 0
-                     && lookup_fdh ((struct ppc_link_hash_entry *) h, htab))
-                   ;
-                 else
-                   ((struct ppc_link_hash_entry *) h)->is_func = 1;
-               }
+               ((struct ppc_link_hash_entry *) h)->is_func = 1;
              else
                {
                  asection *s;
@@ -6343,6 +6359,23 @@ defined_func_desc (struct ppc_link_hash_entry *fh)
   return NULL;
 }
 
+static bfd_boolean func_desc_adjust (struct elf_link_hash_entry *, void *);
+
+/* Garbage collect sections, after first dealing with dot-symbols.  */
+
+static bfd_boolean
+ppc64_elf_gc_sections (bfd *abfd, struct bfd_link_info *info)
+{
+  struct ppc_link_hash_table *htab = ppc_hash_table (info);
+
+  if (htab != NULL && htab->need_func_desc_adj)
+    {
+      elf_link_hash_traverse (&htab->elf, func_desc_adjust, info);
+      htab->need_func_desc_adj = 0;
+    }
+  return bfd_elf_gc_sections (abfd, info);
+}
+
 /* Mark all our entry sym sections, both opd and code section.  */
 
 static void
@@ -6477,7 +6510,15 @@ ppc64_elf_gc_mark_hook (asection *sec,
              eh = (struct ppc_link_hash_entry *) h;
              fdh = defined_func_desc (eh);
              if (fdh != NULL)
-               eh = fdh;
+               {
+                 /* -mcall-aixdesc code references the dot-symbol on
+                    a call reloc.  Mark the function descriptor too
+                    against garbage collection.  */
+                 fdh->elf.mark = 1;
+                 if (fdh->elf.u.weakdef != NULL)
+                   fdh->elf.u.weakdef->mark = 1;
+                 eh = fdh;
+               }
 
              /* Function descriptor syms cause the associated
                 function code sym section to be marked.  */
@@ -6956,7 +6997,6 @@ func_desc_adjust (struct elf_link_hash_entry *h, void *inf)
 {
   struct bfd_link_info *info;
   struct ppc_link_hash_table *htab;
-  struct plt_entry *ent;
   struct ppc_link_hash_entry *fh;
   struct ppc_link_hash_entry *fdh;
   bfd_boolean force_local;
@@ -6965,18 +7005,29 @@ func_desc_adjust (struct elf_link_hash_entry *h, void *inf)
   if (fh->elf.root.type == bfd_link_hash_indirect)
     return TRUE;
 
+  if (!fh->is_func)
+    return TRUE;
+
+  if (fh->elf.root.root.string[0] != '.'
+      || fh->elf.root.root.string[1] == '\0')
+    return TRUE;
+
   info = inf;
   htab = ppc_hash_table (info);
   if (htab == NULL)
     return FALSE;
 
+  /* Find the corresponding function descriptor symbol.  */
+  fdh = lookup_fdh (fh, htab);
+
   /* Resolve undefined references to dot-symbols as the value
      in the function descriptor, if we have one in a regular object.
      This is to satisfy cases like ".quad .foo".  Calls to functions
      in dynamic objects are handled elsewhere.  */
-  if (fh->elf.root.type == bfd_link_hash_undefweak
-      && fh->was_undefined
-      && (fdh = defined_func_desc (fh)) != NULL
+  if ((fh->elf.root.type == bfd_link_hash_undefined
+       || fh->elf.root.type == bfd_link_hash_undefweak)
+      && (fdh->elf.root.type == bfd_link_hash_defined
+         || fdh->elf.root.type == bfd_link_hash_defweak)
       && get_opd_info (fdh->elf.root.u.def.section) != NULL
       && opd_entry_value (fdh->elf.root.u.def.section,
                          fdh->elf.root.u.def.value,
@@ -6989,23 +7040,18 @@ func_desc_adjust (struct elf_link_hash_entry *h, void *inf)
       fh->elf.def_dynamic = fdh->elf.def_dynamic;
     }
 
-  /* If this is a function code symbol, transfer dynamic linking
-     information to the function descriptor symbol.  */
-  if (!fh->is_func)
-    return TRUE;
-
-  for (ent = fh->elf.plt.plist; ent != NULL; ent = ent->next)
-    if (ent->plt.refcount > 0)
-      break;
-  if (ent == NULL
-      || fh->elf.root.root.string[0] != '.'
-      || fh->elf.root.root.string[1] == '\0')
-    return TRUE;
+  if (!fh->elf.dynamic)
+    {
+      struct plt_entry *ent;
 
-  /* Find the corresponding function descriptor symbol.  Create it
-     as undefined if necessary.  */
+      for (ent = fh->elf.plt.plist; ent != NULL; ent = ent->next)
+       if (ent->plt.refcount > 0)
+         break;
+      if (ent == NULL)
+       return TRUE;
+    }
 
-  fdh = lookup_fdh (fh, htab);
+  /* Create a descriptor as undefined if necessary.  */
   if (fdh == NULL
       && !bfd_link_executable (info)
       && (fh->elf.root.type == bfd_link_hash_undefined
@@ -7016,51 +7062,30 @@ func_desc_adjust (struct elf_link_hash_entry *h, void *inf)
        return FALSE;
     }
 
-  /* Fake function descriptors are made undefweak.  If the function
-     code symbol is strong undefined, make the fake sym the same.
-     If the function code symbol is defined, then force the fake
-     descriptor local;  We can't support overriding of symbols in a
-     shared library on a fake descriptor.  */
-
+  /* We can't support overriding of symbols on a fake descriptor.  */
   if (fdh != NULL
       && fdh->fake
-      && fdh->elf.root.type == bfd_link_hash_undefweak)
-    {
-      if (fh->elf.root.type == bfd_link_hash_undefined)
-       {
-         fdh->elf.root.type = bfd_link_hash_undefined;
-         bfd_link_add_undef (&htab->elf.root, &fdh->elf.root);
-       }
-      else if (fh->elf.root.type == bfd_link_hash_defined
-              || fh->elf.root.type == bfd_link_hash_defweak)
-       {
-         _bfd_elf_link_hash_hide_symbol (info, &fdh->elf, TRUE);
-       }
-    }
+      && (fh->elf.root.type == bfd_link_hash_defined
+         || fh->elf.root.type == bfd_link_hash_defweak))
+    _bfd_elf_link_hash_hide_symbol (info, &fdh->elf, TRUE);
 
-  if (fdh != NULL
-      && !fdh->elf.forced_local
-      && (!bfd_link_executable (info)
-         || fdh->elf.def_dynamic
-         || fdh->elf.ref_dynamic
-         || (fdh->elf.root.type == bfd_link_hash_undefweak
-             && ELF_ST_VISIBILITY (fdh->elf.other) == STV_DEFAULT)))
-    {
-      if (fdh->elf.dynindx == -1)
-       if (! bfd_elf_link_record_dynamic_symbol (info, &fdh->elf))
-         return FALSE;
+  /* Transfer dynamic linking information to the function descriptor.  */
+  if (fdh != NULL)
+    {
       fdh->elf.ref_regular |= fh->elf.ref_regular;
       fdh->elf.ref_dynamic |= fh->elf.ref_dynamic;
       fdh->elf.ref_regular_nonweak |= fh->elf.ref_regular_nonweak;
       fdh->elf.non_got_ref |= fh->elf.non_got_ref;
-      if (ELF_ST_VISIBILITY (fh->elf.other) == STV_DEFAULT)
-       {
-         move_plt_plist (fh, fdh);
-         fdh->elf.needs_plt = 1;
-       }
-      fdh->is_func_descriptor = 1;
-      fdh->oh = fh;
-      fh->oh = fdh;
+      fdh->elf.dynamic |= fh->elf.dynamic;
+      fdh->elf.needs_plt |= (fh->elf.needs_plt
+                            || fh->elf.type == STT_FUNC
+                            || fh->elf.type == STT_GNU_IFUNC);
+      move_plt_plist (fh, fdh);
+
+      if (!fdh->elf.forced_local
+         && fh->elf.dynindx != -1)
+       if (!bfd_elf_link_record_dynamic_symbol (info, &fdh->elf))
+         return FALSE;
     }
 
   /* Now that the info is on the function descriptor, clear the
@@ -7145,7 +7170,11 @@ ppc64_elf_func_desc_adjust (bfd *obfd ATTRIBUTE_UNUSED,
                               | STV_HIDDEN);
     }
 
-  elf_link_hash_traverse (&htab->elf, func_desc_adjust, info);
+  if (htab->need_func_desc_adj)
+    {
+      elf_link_hash_traverse (&htab->elf, func_desc_adjust, info);
+      htab->need_func_desc_adj = 0;
+    }
 
   return TRUE;
 }
@@ -8092,11 +8121,14 @@ ppc64_elf_edit_opd (struct bfd_link_info *info)
              if (h != NULL
                  && h->root.root.string[0] == '.')
                {
-                 fdh = lookup_fdh ((struct ppc_link_hash_entry *) h, htab);
-                 if (fdh != NULL
-                     && fdh->elf.root.type != bfd_link_hash_defined
-                     && fdh->elf.root.type != bfd_link_hash_defweak)
-                   fdh = NULL;
+                 fdh = ((struct ppc_link_hash_entry *) h)->oh;
+                 if (fdh != NULL)
+                   {
+                     fdh = ppc_follow_link (fdh);
+                     if (fdh->elf.root.type != bfd_link_hash_defined
+                         && fdh->elf.root.type != bfd_link_hash_defweak)
+                       fdh = NULL;
+                   }
                }
 
              skip = (sym_sec->owner != ibfd
@@ -11080,10 +11112,10 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
 
          /* If the old-ABI "dot-symbol" is undefined make it weak so
             we don't get a link error from RELOC_FOR_GLOBAL_SYMBOL.  */
-         if (fh->elf.root.type == bfd_link_hash_undefined)
+         if (fh->elf.root.type == bfd_link_hash_undefined
+             && (stub_entry->h->elf.root.type == bfd_link_hash_defined
+                 || stub_entry->h->elf.root.type == bfd_link_hash_defweak))
            fh->elf.root.type = bfd_link_hash_undefweak;
-         /* Stop undo_symbol_twiddle changing it back to undefined.  */
-         fh->was_undefined = 0;
        }
 
       /* Now build the stub.  */
@@ -12412,8 +12444,9 @@ ppc64_elf_size_stubs (struct bfd_link_info *info)
                         use the func descriptor sym instead if it is
                         defined.  */
                      if (hash->elf.root.root.string[0] == '.'
-                         && (fdh = lookup_fdh (hash, htab)) != NULL)
+                         && hash->oh != NULL)
                        {
+                         fdh = ppc_follow_link (hash->oh);
                          if (fdh->elf.root.type == bfd_link_hash_defined
                              || fdh->elf.root.type == bfd_link_hash_defweak)
                            {
@@ -13242,33 +13275,6 @@ ppc64_elf_build_stubs (struct bfd_link_info *info,
   return TRUE;
 }
 
-/* This function undoes the changes made by add_symbol_adjust.  */
-
-static bfd_boolean
-undo_symbol_twiddle (struct elf_link_hash_entry *h, void *inf ATTRIBUTE_UNUSED)
-{
-  struct ppc_link_hash_entry *eh;
-
-  if (h->root.type == bfd_link_hash_indirect)
-    return TRUE;
-
-  eh = (struct ppc_link_hash_entry *) h;
-  if (eh->elf.root.type != bfd_link_hash_undefweak || !eh->was_undefined)
-    return TRUE;
-
-  eh->elf.root.type = bfd_link_hash_undefined;
-  return TRUE;
-}
-
-void
-ppc64_elf_restore_symbols (struct bfd_link_info *info)
-{
-  struct ppc_link_hash_table *htab = ppc_hash_table (info);
-
-  if (htab != NULL)
-    elf_link_hash_traverse (&htab->elf, undo_symbol_twiddle, info);
-}
-
 /* What to do when ld finds relocations against symbols defined in
    discarded sections.  */
 
index 971ba09668873ae7b010afc09872d668840d072a..b1ea550ed2cc8ed4209a1088d05b5f244a93d3e0 100644 (file)
@@ -94,5 +94,3 @@ bfd_boolean ppc64_elf_size_stubs
 (struct bfd_link_info *);
 bfd_boolean ppc64_elf_build_stubs
   (struct bfd_link_info *, char **);
-void ppc64_elf_restore_symbols
-  (struct bfd_link_info *info);
index b1c6b8cd5144ecf573ad232aabf8e1717e80e4b5..90283e3ffdbcbcb6e42348dc4df7a374eb928f70 100644 (file)
@@ -1,3 +1,15 @@
+2016-12-03  Alan Modra  <amodra@gmail.com>
+
+       * emultempl/ppc64elf.em (gld${EMULATION_NAME}_finish): Don't call
+       ppc64_elf_restore_symbols.
+       * testsuite/ld-powerpc/dotsym1.d: New.
+       * testsuite/ld-powerpc/dotsym2.d: New.
+       * testsuite/ld-powerpc/dotsym3.d: New.
+       * testsuite/ld-powerpc/dotsym4.d: New.
+       * testsuite/ld-powerpc/dotsymref.s: New.
+       * testsuite/ld-powerpc/nodotsym.s: New.
+       * testsuite/ld-powerpc/powerpc.exp: Run new tests.
+
 2016-12-03  Alan Modra  <amodra@gmail.com>
 
        * testsuite/ld-elf/indirect1b.c: Give dot-symbol a version too.
index eaa692db607b602a3aaabade4e5bc3d1c2d244d2..b614e07d4ef7774cadb3044f22058f4b013aa257 100644 (file)
@@ -592,7 +592,6 @@ gld${EMULATION_NAME}_finish (void)
   if (msg != NULL)
     free (msg);
 
-  ppc64_elf_restore_symbols (&link_info);
   finish_default ();
 }
 
diff --git a/ld/testsuite/ld-powerpc/dotsym1.d b/ld/testsuite/ld-powerpc/dotsym1.d
new file mode 100644 (file)
index 0000000..1cb9338
--- /dev/null
@@ -0,0 +1,15 @@
+#source: nodotsym.s
+#source: dotsymref.s
+#as: -a64
+#ld: -melf64ppc -Ttext=0x10000000 -e foo
+#objdump: -d
+
+.*:     file format .*
+
+Disassembly of section \.text:
+
+0+10000000 <\.foo>:
+.*:    (4e 80 00 20|20 00 80 4e)       blr
+.*:    (60 00 00 00|00 00 00 60)       nop
+.*:    (00 00 00 00|00 00 00 10)       .*
+.*:    (10 00 00 00|00 00 00 00)       .*
diff --git a/ld/testsuite/ld-powerpc/dotsym2.d b/ld/testsuite/ld-powerpc/dotsym2.d
new file mode 100644 (file)
index 0000000..7704db7
--- /dev/null
@@ -0,0 +1,16 @@
+#source: dotsymref.s
+#source: nodotsym.s
+#as: -a64
+#ld: -melf64ppc -Ttext=0x10000000 -e foo
+#objdump: -d
+
+.*:     file format .*
+
+Disassembly of section \.text:
+
+0+10000000 <\.foo-0x8>:
+.*:    (00 00 00 00|08 00 00 10)       .*
+.*:    (10 00 00 08|00 00 00 00)       .*
+
+0+10000008 <\.foo>:
+.*:    (4e 80 00 20|20 00 80 4e)       blr
diff --git a/ld/testsuite/ld-powerpc/dotsym3.d b/ld/testsuite/ld-powerpc/dotsym3.d
new file mode 100644 (file)
index 0000000..fac2f8e
--- /dev/null
@@ -0,0 +1,16 @@
+#source: nodotsym.s
+#source: dotsymref.s
+#as: -a64
+#ld: -melf64ppc -Ttext=0x1000 -shared
+#objdump: -dR
+
+.*:     file format .*
+
+Disassembly of section \.text:
+
+0+1000 <\.foo>:
+.*:    (4e 80 00 20|20 00 80 4e)       blr
+.*:    (60 00 00 00|00 00 00 60)       nop
+.*:    (00 00 00 00|00 10 00 00)       .*
+.*: R_PPC64_RELATIVE   \*ABS\*\+0x1000
+.*:    (00 00 10 00|00 00 00 00)       .*
diff --git a/ld/testsuite/ld-powerpc/dotsym4.d b/ld/testsuite/ld-powerpc/dotsym4.d
new file mode 100644 (file)
index 0000000..fdd92f3
--- /dev/null
@@ -0,0 +1,17 @@
+#source: dotsymref.s
+#source: nodotsym.s
+#as: -a64
+#ld: -melf64ppc -Ttext=0x1000 -shared
+#objdump: -dR
+
+.*:     file format .*
+
+Disassembly of section \.text:
+
+0+1000 <\.foo-0x8>:
+.*:    (00 00 00 00|08 10 00 00)       .*
+.*: R_PPC64_RELATIVE   \*ABS\*\+0x1008
+.*:    (00 00 10 08|00 00 00 00)       .*
+
+0+1008 <\.foo>:
+.*:    (4e 80 00 20|20 00 80 4e)       blr
diff --git a/ld/testsuite/ld-powerpc/dotsymref.s b/ld/testsuite/ld-powerpc/dotsymref.s
new file mode 100644 (file)
index 0000000..54c6f5c
--- /dev/null
@@ -0,0 +1,4 @@
+ .abiversion 1
+ .text
+ .p2align 3
+ .quad .foo
diff --git a/ld/testsuite/ld-powerpc/nodotsym.s b/ld/testsuite/ld-powerpc/nodotsym.s
new file mode 100644 (file)
index 0000000..dbc44ec
--- /dev/null
@@ -0,0 +1,11 @@
+ .section .opd,"aw"
+ .p2align 3
+ .global foo
+ .type foo,@function
+foo:
+ .quad .L.foo,.TOC.@tocbase,0
+
+ .text
+.L.foo:
+ blr
+ .size foo,.-.L.foo
index 07226c63c4011d104599048389dde8296c376c76..18a8e62c0522f1356cb620b8cf7056b02ccb675d 100644 (file)
@@ -299,6 +299,10 @@ if [ supports_ppc64 ] then {
     run_dump_test "tlsld"
     run_dump_test "relocsort"
     run_dump_test "addpcis"
+    run_dump_test "dotsym1"
+    run_dump_test "dotsym2"
+    run_dump_test "dotsym3"
+    run_dump_test "dotsym4"
 }
 
 run_dump_test "tlsld32"