+2005-02-04  Alan Modra  <amodra@bigpond.net.au>
+
+       * elf64-ppc.c (struct ppc_link_hash_entry): Add "fake".
+       (link_hash_newfunc): Clear all locals using memset.
+       (make_fdh): Remove flags param.  Always create fake func desc
+       weak.  Link the descriptor with the code entry sym.
+       (ppc64_elf_archive_symbol_lookup): Don't return fake syms.
+       (add_symbol_adjust): Adjust make_fdh call.
+       (func_desc_adjust): Likewise.  Twiddle any pre-existing fake
+       descriptor to strong undefined if code entry is strong.
+
 2005-02-04  Alan Modra  <amodra@bigpond.net.au>
 
        * elflink.c (bfd_elf_record_link_assignment): Do "provide" symbol
 
   /* Flag function code and descriptor symbols.  */
   unsigned int is_func:1;
   unsigned int is_func_descriptor:1;
+  unsigned int fake:1;
 
   /* Whether global opd/toc sym has been adjusted or not.
      After ppc64_elf_edit_opd/ppc64_elf_edit_toc has run, this flag
     {
       struct ppc_link_hash_entry *eh = (struct ppc_link_hash_entry *) entry;
 
-      eh->stub_cache = NULL;
-      eh->dyn_relocs = NULL;
-      eh->oh = NULL;
-      eh->is_func = 0;
-      eh->is_func_descriptor = 0;
-      eh->adjust_done = 0;
-      eh->was_undefined = 0;
-      eh->tls_mask = 0;
+      memset (&eh->stub_cache, 0,
+             (sizeof (struct ppc_link_hash_entry)
+              - offsetof (struct ppc_link_hash_entry, stub_cache)));
     }
 
   return entry;
 
 static struct ppc_link_hash_entry *
 make_fdh (struct bfd_link_info *info,
-         struct ppc_link_hash_entry *fh,
-         flagword flags)
+         struct ppc_link_hash_entry *fh)
 {
   bfd *abfd;
   asymbol *newsym;
   newsym->name = fh->elf.root.root.string + 1;
   newsym->section = bfd_und_section_ptr;
   newsym->value = 0;
-  newsym->flags = flags;
+  newsym->flags = BSF_WEAK;
 
   bh = NULL;
   if (!_bfd_generic_link_add_one_symbol (info, abfd, newsym->name,
 
   fdh = (struct ppc_link_hash_entry *) bh;
   fdh->elf.non_elf = 0;
+  fdh->fake = 1;
+  fdh->is_func_descriptor = 1;
+  fdh->oh = fh;
+  fh->is_func = 1;
+  fh->oh = fdh;
   return fdh;
 }
 
 }
 
 /* This function makes an old ABI object reference to ".bar" cause the
-   inclusion of a new ABI object archive that defines "bar".  */
+   inclusion of a new ABI object archive that defines "bar".
+   NAME is a symbol defined in an archive.  Return a symbol in the hash
+   table that might be satisfied by the archive symbols.  */
 
 static struct elf_link_hash_entry *
 ppc64_elf_archive_symbol_lookup (bfd *abfd,
   size_t len;
 
   h = _bfd_elf_archive_symbol_lookup (abfd, info, name);
-  if (h != NULL)
+  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))
     return h;
 
   if (name[0] == '.')
       /* 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 (data->info, eh, BSF_WEAK);
+      fdh = make_fdh (data->info, eh);
       if (fdh == NULL)
        data->ok = FALSE;
       else
       && (fh->elf.root.type == bfd_link_hash_undefined
          || fh->elf.root.type == bfd_link_hash_undefweak))
     {
-      flagword flags = 0;
-      if (fh->elf.root.type == bfd_link_hash_undefweak)
-       flags = BSF_WEAK;
-      fdh = make_fdh (info, fh, flags);
+      fdh = make_fdh (info, fh);
       if (fdh == NULL)
        return FALSE;
     }
 
+  /* Fake function descriptors are made undefweak.  If the function
+     code symbol is strong undefined, make the fake sym the same.  */
+
+  if (fdh != NULL
+      && fdh->fake
+      && fdh->elf.root.type == bfd_link_hash_undefweak
+      && 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);
+    }
+
   if (fdh != NULL
       && !fdh->elf.forced_local
       && (info->shared