* config/tc-mips.c (mips_set_options): Add ase_dsp for DSP instructions.
[deliverable/binutils-gdb.git] / bfd / elf64-ppc.c
index c75c34a71364780ade38ac00bba3315089a0294e..3f219fa9d725b33b752cd19ec450251d2935ecfe 100644 (file)
@@ -19,7 +19,7 @@
 
    You should have received a copy of the GNU General Public License along
    with this program; if not, write to the Free Software Foundation, Inc.,
-   59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+   51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.  */
 
 /* The 64-bit PowerPC ELF ABI may be found at
    http://www.linuxbase.org/spec/ELF/ppc64/PPC-elf64abi.txt, and
@@ -67,7 +67,6 @@ static bfd_vma opd_entry_value
 #define elf_backend_want_plt_sym 0
 #define elf_backend_plt_alignment 3
 #define elf_backend_plt_not_loaded 1
-#define elf_backend_got_symbol_offset 0
 #define elf_backend_got_header_size 8
 #define elf_backend_can_gc_sections 1
 #define elf_backend_can_refcount 1
@@ -2118,8 +2117,13 @@ ppc64_elf_info_to_howto (bfd *abfd ATTRIBUTE_UNUSED, arelent *cache_ptr,
     ppc_howto_init ();
 
   type = ELF64_R_TYPE (dst->r_info);
-  BFD_ASSERT (type < (sizeof (ppc64_elf_howto_table)
-                     / sizeof (ppc64_elf_howto_table[0])));
+  if (type >= (sizeof (ppc64_elf_howto_table)
+              / sizeof (ppc64_elf_howto_table[0])))
+    {
+      (*_bfd_error_handler) (_("%B: invalid relocation type %d"),
+                            abfd, (int) type);
+      type = R_PPC64_NONE;
+    }
   cache_ptr->howto = ppc64_elf_howto_table[type];
 }
 
@@ -2370,9 +2374,14 @@ struct ppc64_elf_obj_tdata
   asection *got;
   asection *relgot;
 
-  /* Used during garbage collection.  We attach global symbols defined
-     on removed .opd entries to this section so that the sym is removed.  */
-  asection *deleted_section;
+  union {
+    /* Used during garbage collection.  We attach global symbols defined
+       on removed .opd entries to this section so that the sym is removed.  */
+    asection *deleted_section;
+
+    /* Used when adding symbols.  */
+    bfd_boolean has_dotsym;
+  } u;
 
   /* TLS local dynamic got entry handling.  Suppose for multiple GOT
      sections means we potentially need one of these for each input bfd.  */
@@ -2504,11 +2513,11 @@ ppc64_elf_merge_private_bfd_data (bfd *ibfd, bfd *obfd)
 
 /* Add extra PPC sections.  */
 
-static struct bfd_elf_special_section const ppc64_elf_special_sections[]=
+static const struct bfd_elf_special_section ppc64_elf_special_sections[]=
 {
-  { ".sdata",   6, -2, SHT_PROGBITS, SHF_ALLOC + SHF_WRITE },
-  { ".sbss",    5, -2, SHT_NOBITS,   SHF_ALLOC + SHF_WRITE },
   { ".plt",     4,  0, SHT_NOBITS,   0 },
+  { ".sbss",    5, -2, SHT_NOBITS,   SHF_ALLOC + SHF_WRITE },
+  { ".sdata",   6, -2, SHT_PROGBITS, SHF_ALLOC + SHF_WRITE },
   { ".toc",     4,  0, SHT_PROGBITS, SHF_ALLOC + SHF_WRITE },
   { ".toc1",    5,  0, SHT_PROGBITS, SHF_ALLOC + SHF_WRITE },
   { ".tocbss",  7,  0, SHT_NOBITS,   SHF_ALLOC + SHF_WRITE },
@@ -2687,7 +2696,7 @@ ppc64_elf_get_synthetic_symtab (bfd *abfd,
 
   syms = bfd_malloc ((symcount + 1) * sizeof (*syms));
   if (syms == NULL)
-    return 0;
+    return -1;
 
   if (!relocatable && static_count != 0 && dyn_count != 0)
     {
@@ -2709,7 +2718,7 @@ ppc64_elf_get_synthetic_symtab (bfd *abfd,
       long j;
       /* Trim duplicate syms, since we may have merged the normal and
         dynamic symbols.  Actually, we only care about syms that have
-        different values, so trim any with the same value.  */ 
+        different values, so trim any with the same value.  */
       for (i = 1, j = 1; i < symcount; ++i)
        if (syms[i - 1]->value + syms[i - 1]->section->vma
            != syms[i]->value + syms[i]->section->vma)
@@ -2758,11 +2767,15 @@ ppc64_elf_get_synthetic_symtab (bfd *abfd,
 
       slurp_relocs = get_elf_backend_data (abfd)->s->slurp_reloc_table;
       relcount = (opd->flags & SEC_RELOC) ? opd->reloc_count : 0;
-
-      if (! relcount
-         || ! (*slurp_relocs) (abfd, opd, static_syms, FALSE))
+      if (relcount == 0)
        goto done;
 
+      if (!(*slurp_relocs) (abfd, opd, static_syms, FALSE))
+       {
+         count = -1;
+         goto done;
+       }
+
       size = 0;
       for (i = secsymend, r = opd->relocation; i < opdsymend; ++i)
        {
@@ -2794,7 +2807,7 @@ ppc64_elf_get_synthetic_symtab (bfd *abfd,
       s = *ret = bfd_malloc (size);
       if (s == NULL)
        {
-         count = 0;
+         count = -1;
          goto done;
        }
 
@@ -2847,6 +2860,7 @@ ppc64_elf_get_synthetic_symtab (bfd *abfd,
            free_contents_and_exit:
              free (contents);
            }
+         count = -1;
          goto done;
        }
 
@@ -2866,10 +2880,7 @@ ppc64_elf_get_synthetic_symtab (bfd *abfd,
 
       s = *ret = bfd_malloc (size);
       if (s == NULL)
-       {
-         count = 0;
-         goto free_contents_and_exit;
-       }
+       goto free_contents_and_exit;
 
       names = (char *) (s + count);
 
@@ -3184,7 +3195,7 @@ struct ppc_branch_hash_entry {
   /* Base hash table entry structure.  */
   struct bfd_hash_entry root;
 
-  /* Offset within .branch_lt.  */
+  /* Offset within branch lookup table.  */
   unsigned int offset;
 
   /* Generation marker.  */
@@ -3208,6 +3219,7 @@ struct ppc_link_hash_entry
   /* 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
@@ -3430,14 +3442,9 @@ link_hash_newfunc (struct bfd_hash_entry *entry,
     {
       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;
@@ -3473,10 +3480,14 @@ ppc64_elf_link_hash_table_create (bfd *abfd)
      only care about glist, but when compiled on a 32-bit host the
      bfd_vma fields are larger.  Setting the bfd_vma to zero makes
      debugger inspection of these fields look nicer.  */
-  htab->elf.init_refcount.refcount = 0;
-  htab->elf.init_refcount.glist = NULL;
-  htab->elf.init_offset.offset = 0;
-  htab->elf.init_offset.glist = NULL;
+  htab->elf.init_got_refcount.refcount = 0;
+  htab->elf.init_got_refcount.glist = NULL;
+  htab->elf.init_plt_refcount.refcount = 0;
+  htab->elf.init_plt_refcount.glist = NULL;
+  htab->elf.init_got_offset.offset = 0;
+  htab->elf.init_got_offset.glist = NULL;
+  htab->elf.init_plt_offset.offset = 0;
+  htab->elf.init_plt_offset.glist = NULL;
 
   return &htab->elf.root;
 }
@@ -3530,26 +3541,26 @@ ppc_stub_name (const asection *input_section,
     {
       len = 8 + 1 + strlen (h->elf.root.root.string) + 1 + 8 + 1;
       stub_name = bfd_malloc (len);
-      if (stub_name != NULL)
-       {
-         sprintf (stub_name, "%08x.%s+%x",
-                  input_section->id & 0xffffffff,
-                  h->elf.root.root.string,
-                  (int) rel->r_addend & 0xffffffff);
-       }
+      if (stub_name == NULL)
+       return stub_name;
+
+      sprintf (stub_name, "%08x.%s+%x",
+              input_section->id & 0xffffffff,
+              h->elf.root.root.string,
+              (int) rel->r_addend & 0xffffffff);
     }
   else
     {
       len = 8 + 1 + 8 + 1 + 8 + 1 + 8 + 1;
       stub_name = bfd_malloc (len);
-      if (stub_name != NULL)
-       {
-         sprintf (stub_name, "%08x.%x:%x+%x",
-                  input_section->id & 0xffffffff,
-                  sym_sec->id & 0xffffffff,
-                  (int) ELF64_R_SYM (rel->r_info) & 0xffffffff,
-                  (int) rel->r_addend & 0xffffffff);
-       }
+      if (stub_name == NULL)
+       return stub_name;
+
+      sprintf (stub_name, "%08x.%x:%x+%x",
+              input_section->id & 0xffffffff,
+              sym_sec->id & 0xffffffff,
+              (int) ELF64_R_SYM (rel->r_info) & 0xffffffff,
+              (int) rel->r_addend & 0xffffffff);
     }
   if (stub_name[len - 2] == '+' && stub_name[len - 1] == '0')
     stub_name[len - 2] = 0;
@@ -3669,38 +3680,63 @@ create_linkage_sections (bfd *dynobj, struct bfd_link_info *info)
   /* Create .sfpr for code to save and restore fp regs.  */
   flags = (SEC_ALLOC | SEC_LOAD | SEC_CODE | SEC_READONLY
           | SEC_HAS_CONTENTS | SEC_IN_MEMORY | SEC_LINKER_CREATED);
-  htab->sfpr = bfd_make_section_anyway (dynobj, ".sfpr");
+  htab->sfpr = bfd_make_section_anyway_with_flags (dynobj, ".sfpr",
+                                                  flags);
   if (htab->sfpr == NULL
-      || ! bfd_set_section_flags (dynobj, htab->sfpr, flags)
       || ! bfd_set_section_alignment (dynobj, htab->sfpr, 2))
     return FALSE;
 
   /* Create .glink for lazy dynamic linking support.  */
-  htab->glink = bfd_make_section_anyway (dynobj, ".glink");
+  htab->glink = bfd_make_section_anyway_with_flags (dynobj, ".glink",
+                                                   flags);
   if (htab->glink == NULL
-      || ! bfd_set_section_flags (dynobj, htab->glink, flags)
       || ! bfd_set_section_alignment (dynobj, htab->glink, 2))
     return FALSE;
 
-  /* Create .branch_lt for plt_branch stubs.  */
-  flags = (SEC_ALLOC | SEC_LOAD
-          | SEC_HAS_CONTENTS | SEC_IN_MEMORY | SEC_LINKER_CREATED);
-  htab->brlt = bfd_make_section_anyway (dynobj, ".branch_lt");
+  /* Create branch lookup table for plt_branch stubs.  */
+  if (info->shared)
+    {
+      flags = (SEC_ALLOC | SEC_LOAD
+              | SEC_HAS_CONTENTS | SEC_IN_MEMORY | SEC_LINKER_CREATED);
+      htab->brlt
+       = bfd_make_section_anyway_with_flags (dynobj, ".data.rel.ro.brlt",
+                                             flags);
+    }
+  else
+    {
+      flags = (SEC_ALLOC | SEC_LOAD | SEC_READONLY
+              | SEC_HAS_CONTENTS | SEC_IN_MEMORY | SEC_LINKER_CREATED);
+      htab->brlt
+       = bfd_make_section_anyway_with_flags (dynobj, ".rodata.brlt", flags);
+    }
+
   if (htab->brlt == NULL
-      || ! bfd_set_section_flags (dynobj, htab->brlt, flags)
       || ! bfd_set_section_alignment (dynobj, htab->brlt, 3))
     return FALSE;
 
-  if (info->shared || info->emitrelocations)
+  if (info->shared)
     {
       flags = (SEC_ALLOC | SEC_LOAD | SEC_READONLY
               | SEC_HAS_CONTENTS | SEC_IN_MEMORY | SEC_LINKER_CREATED);
-      htab->relbrlt = bfd_make_section_anyway (dynobj, ".rela.branch_lt");
-      if (!htab->relbrlt
-         || ! bfd_set_section_flags (dynobj, htab->relbrlt, flags)
-         || ! bfd_set_section_alignment (dynobj, htab->relbrlt, 3))
-       return FALSE;
+      htab->relbrlt
+       = bfd_make_section_anyway_with_flags (dynobj, ".rela.data.rel.ro.brlt",
+                                             flags);
     }
+  else if (info->emitrelocations)
+    {
+      flags = (SEC_ALLOC | SEC_LOAD | SEC_READONLY
+              | SEC_HAS_CONTENTS | SEC_IN_MEMORY | SEC_LINKER_CREATED);
+      htab->relbrlt
+       = bfd_make_section_anyway_with_flags (dynobj, ".rela.rodata.brlt",
+                                             flags);
+    }
+  else
+    return TRUE;
+
+  if (!htab->relbrlt
+      || ! bfd_set_section_alignment (dynobj, htab->relbrlt, 3))
+    return FALSE;
+
   return TRUE;
 }
 
@@ -3727,15 +3763,14 @@ create_got_section (bfd *abfd, struct bfd_link_info *info)
   flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY
           | SEC_LINKER_CREATED);
 
-  got = bfd_make_section (abfd, ".got");
+  got = bfd_make_section_anyway_with_flags (abfd, ".got", flags);
   if (!got
-      || !bfd_set_section_flags (abfd, got, flags)
       || !bfd_set_section_alignment (abfd, got, 3))
     return FALSE;
 
-  relgot = bfd_make_section (abfd, ".rela.got");
+  relgot = bfd_make_section_anyway_with_flags (abfd, ".rela.got",
+                                              flags | SEC_READONLY);
   if (!relgot
-      || ! bfd_set_section_flags (abfd, relgot, flags | SEC_READONLY)
       || ! bfd_set_section_alignment (abfd, relgot, 3))
     return FALSE;
 
@@ -3770,6 +3805,41 @@ ppc64_elf_create_dynamic_sections (bfd *dynobj, struct bfd_link_info *info)
   return TRUE;
 }
 
+/* Merge PLT info on FROM with that on TO.  */
+
+static void
+move_plt_plist (struct ppc_link_hash_entry *from,
+               struct ppc_link_hash_entry *to)
+{
+  if (from->elf.plt.plist != NULL)
+    {
+      if (to->elf.plt.plist != NULL)
+       {
+         struct plt_entry **entp;
+         struct plt_entry *ent;
+
+         for (entp = &from->elf.plt.plist; (ent = *entp) != NULL; )
+           {
+             struct plt_entry *dent;
+
+             for (dent = to->elf.plt.plist; dent != NULL; dent = dent->next)
+               if (dent->addend == ent->addend)
+                 {
+                   dent->plt.refcount += ent->plt.refcount;
+                   *entp = ent->next;
+                   break;
+                 }
+             if (dent == NULL)
+               entp = &ent->next;
+           }
+         *entp = to->elf.plt.plist;
+       }
+
+      to->elf.plt.plist = from->elf.plt.plist;
+      from->elf.plt.plist = NULL;
+    }
+}
+
 /* Copy the extra info we tack onto an elf_link_hash_entry.  */
 
 static void
@@ -3872,33 +3942,7 @@ ppc64_elf_copy_indirect_symbol
     }
 
   /* And plt entries.  */
-  if (eind->elf.plt.plist != NULL)
-    {
-      if (edir->elf.plt.plist != NULL)
-       {
-         struct plt_entry **entp;
-         struct plt_entry *ent;
-
-         for (entp = &eind->elf.plt.plist; (ent = *entp) != NULL; )
-           {
-             struct plt_entry *dent;
-
-             for (dent = edir->elf.plt.plist; dent != NULL; dent = dent->next)
-               if (dent->addend == ent->addend)
-                 {
-                   dent->plt.refcount += ent->plt.refcount;
-                   *entp = ent->next;
-                   break;
-                 }
-             if (dent == NULL)
-               entp = &ent->next;
-           }
-         *entp = edir->elf.plt.plist;
-       }
-
-      edir->elf.plt.plist = eind->elf.plt.plist;
-      eind->elf.plt.plist = NULL;
-    }
+  move_plt_plist (eind, edir);
 
   if (edir->elf.dynindx == -1)
     {
@@ -3937,6 +3981,41 @@ get_fdh (struct ppc_link_hash_entry *fh, struct ppc_link_hash_table *htab)
   return fdh;
 }
 
+/* Make a fake function descriptor sym for the 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;
+  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))
+    return NULL;
+
+  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;
+}
+
 /* Hacks to support old ABI code.
    When making function calls, old ABI code references function entry
    points (dot symbols), while new ABI code references the function
@@ -3956,10 +4035,10 @@ get_fdh (struct ppc_link_hash_entry *fh, struct ppc_link_hash_table *htab)
    function type.  */
 
 static bfd_boolean
-ppc64_elf_add_symbol_hook (bfd *ibfd ATTRIBUTE_UNUSED,
+ppc64_elf_add_symbol_hook (bfd *ibfd,
                           struct bfd_link_info *info ATTRIBUTE_UNUSED,
                           Elf_Internal_Sym *isym,
-                          const char **name ATTRIBUTE_UNUSED,
+                          const char **name,
                           flagword *flags ATTRIBUTE_UNUSED,
                           asection **sec,
                           bfd_vma *value ATTRIBUTE_UNUSED)
@@ -3967,11 +4046,20 @@ ppc64_elf_add_symbol_hook (bfd *ibfd ATTRIBUTE_UNUSED,
   if (*sec != NULL
       && strcmp (bfd_get_section_name (ibfd, *sec), ".opd") == 0)
     isym->st_info = ELF_ST_INFO (ELF_ST_BIND (isym->st_info), STT_FUNC);
+
+  if ((*name)[0] == '.'
+      && ELF_ST_BIND (isym->st_info) == STB_GLOBAL
+      && ELF_ST_TYPE (isym->st_info) < STT_SECTION
+      && is_ppc64_elf_target (ibfd->xvec))
+    ppc64_elf_tdata (ibfd)->u.has_dotsym = 1;
+
   return TRUE;
 }
 
 /* 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,
@@ -3983,7 +4071,11 @@ 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] == '.')
@@ -4009,10 +4101,16 @@ ppc64_elf_archive_symbol_lookup (bfd *abfd,
    most restrictive visibility of the function descriptor and the
    function entry symbol is used.  */
 
+struct add_symbol_adjust_data
+{
+  struct bfd_link_info *info;
+  bfd_boolean ok;
+};
+
 static bfd_boolean
 add_symbol_adjust (struct elf_link_hash_entry *h, void *inf)
 {
-  struct bfd_link_info *info;
+  struct add_symbol_adjust_data *data;
   struct ppc_link_hash_table *htab;
   struct ppc_link_hash_entry *eh;
   struct ppc_link_hash_entry *fdh;
@@ -4026,11 +4124,26 @@ add_symbol_adjust (struct elf_link_hash_entry *h, void *inf)
   if (h->root.root.string[0] != '.')
     return TRUE;
 
-  info = inf;
-  htab = ppc_hash_table (info);
+  data = inf;
+  htab = ppc_hash_table (data->info);
   eh = (struct ppc_link_hash_entry *) h;
   fdh = get_fdh (eh, htab);
-  if (fdh != NULL)
+  if (fdh == NULL
+      && !data->info->relocatable
+      && (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 (data->info, eh);
+      if (fdh == NULL)
+       data->ok = FALSE;
+      else
+       fdh->elf.ref_regular = 1;
+    }
+  else if (fdh != NULL)
     {
       unsigned entry_vis = ELF_ST_VISIBILITY (eh->elf.other) - 1;
       unsigned descr_vis = ELF_ST_VISIBILITY (fdh->elf.other) - 1;
@@ -4039,7 +4152,9 @@ add_symbol_adjust (struct elf_link_hash_entry *h, void *inf)
       else if (entry_vis > descr_vis)
        eh->elf.other += descr_vis - entry_vis;
 
-      if (eh->elf.root.type == bfd_link_hash_undefined)
+      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;
@@ -4051,16 +4166,25 @@ add_symbol_adjust (struct elf_link_hash_entry *h, void *inf)
 }
 
 static bfd_boolean
-ppc64_elf_check_directives (bfd *abfd ATTRIBUTE_UNUSED,
-                           struct bfd_link_info *info)
+ppc64_elf_check_directives (bfd *abfd, struct bfd_link_info *info)
 {
   struct ppc_link_hash_table *htab;
+  struct add_symbol_adjust_data data;
+
+  if (!is_ppc64_elf_target (abfd->xvec))
+    return TRUE;
+
+  if (!ppc64_elf_tdata (abfd)->u.has_dotsym)
+    return TRUE;
+  ppc64_elf_tdata (abfd)->u.deleted_section = NULL;
 
   htab = ppc_hash_table (info);
   if (!is_ppc64_elf_target (htab->elf.root.creator))
     return TRUE;
 
-  elf_link_hash_traverse (&htab->elf, add_symbol_adjust, info);
+  data.info = info;
+  data.ok = TRUE;
+  elf_link_hash_traverse (&htab->elf, add_symbol_adjust, &data);
 
   /* We need to fix the undefs list for any syms we have twiddled to
      undef_weak.  */
@@ -4069,7 +4193,7 @@ ppc64_elf_check_directives (bfd *abfd ATTRIBUTE_UNUSED,
       bfd_link_repair_undef_list (&htab->elf.root);
       htab->twiddled_syms = 0;
     }
-  return TRUE;
+  return data.ok;
 }
 
 static bfd_boolean
@@ -4141,7 +4265,9 @@ update_plt_info (bfd *abfd, struct ppc_link_hash_entry *eh, bfd_vma addend)
     }
   ent->plt.refcount += 1;
   eh->elf.needs_plt = 1;
-  eh->is_func = 1;
+  if (eh->elf.root.root.string[0] == '.'
+      && eh->elf.root.root.string[1] != '\0')
+    eh->is_func = 1;
   return TRUE;
 }
 
@@ -4223,7 +4349,12 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
       if (r_symndx < symtab_hdr->sh_info)
        h = NULL;
       else
-       h = sym_hashes[r_symndx - symtab_hdr->sh_info];
+       {
+         h = sym_hashes[r_symndx - symtab_hdr->sh_info];
+         while (h->root.type == bfd_link_hash_indirect
+                || h->root.type == bfd_link_hash_warning)
+           h = (struct elf_link_hash_entry *) h->root.u.i.link;
+       }
 
       r_type = ELF64_R_TYPE (rel->r_info);
       switch (r_type)
@@ -4610,13 +4741,13 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
                    {
                      flagword flags;
 
-                     sreloc = bfd_make_section (dynobj, name);
                      flags = (SEC_HAS_CONTENTS | SEC_READONLY
-                              | SEC_IN_MEMORY | SEC_LINKER_CREATED);
-                     if ((sec->flags & SEC_ALLOC) != 0)
-                       flags |= SEC_ALLOC | SEC_LOAD;
+                              | SEC_IN_MEMORY | SEC_LINKER_CREATED
+                              | SEC_ALLOC | SEC_LOAD);
+                     sreloc = bfd_make_section_with_flags (dynobj,
+                                                           name,
+                                                           flags);
                      if (sreloc == NULL
-                         || ! bfd_set_section_flags (dynobj, sreloc, flags)
                          || ! bfd_set_section_alignment (dynobj, sreloc, 3))
                        return FALSE;
                    }
@@ -4693,7 +4824,7 @@ opd_entry_value (asection *opd_sec,
 
       if (!bfd_get_section_contents (opd_bfd, opd_sec, &val, offset, 8))
        return (bfd_vma) -1;
-      
+
       if (code_sec != NULL)
        {
          asection *sec, *likely = NULL;
@@ -4822,7 +4953,9 @@ ppc64_elf_gc_mark_hook (asection *sec,
              && eh->elf.root.type != bfd_link_hash_defweak)
            continue;
 
-         if (eh->is_func_descriptor)
+         if (eh->is_func_descriptor
+             && (eh->oh->elf.root.type == bfd_link_hash_defined
+                 || eh->oh->elf.root.type == bfd_link_hash_defweak))
            rsec = eh->oh->elf.root.u.def.section;
          else if (get_opd_info (eh->elf.root.u.def.section) != NULL
                   && opd_entry_value (eh->elf.root.u.def.section,
@@ -4868,12 +5001,17 @@ ppc64_elf_gc_mark_hook (asection *sec,
            case bfd_link_hash_defined:
            case bfd_link_hash_defweak:
              eh = (struct ppc_link_hash_entry *) h;
-             if (eh->oh != NULL && eh->oh->is_func_descriptor)
+             if (eh->oh != NULL
+                 && eh->oh->is_func_descriptor
+                 && (eh->oh->elf.root.type == bfd_link_hash_defined
+                     || eh->oh->elf.root.type == bfd_link_hash_defweak))
                eh = eh->oh;
 
              /* Function descriptor syms cause the associated
                 function code sym section to be marked.  */
-             if (eh->is_func_descriptor)
+             if (eh->is_func_descriptor
+                 && (eh->oh->elf.root.type == bfd_link_hash_defined
+                     || eh->oh->elf.root.type == bfd_link_hash_defweak))
                {
                  /* They also mark their opd section.  */
                  if (!eh->elf.root.u.def.section->gc_mark)
@@ -4915,7 +5053,7 @@ ppc64_elf_gc_mark_hook (asection *sec,
          if (!rsec->gc_mark)
            _bfd_elf_gc_mark (info, rsec, ppc64_elf_gc_mark_hook);
 
-         rsec = opd_sym_section[sym->st_value / 8];
+         rsec = opd_sym_section[(sym->st_value + rel->r_addend) / 8];
        }
     }
 
@@ -5358,30 +5496,31 @@ func_desc_adjust (struct elf_link_hash_entry *h, void *inf)
       && (fh->elf.root.type == bfd_link_hash_undefined
          || fh->elf.root.type == bfd_link_hash_undefweak))
     {
-      bfd *abfd;
-      asymbol *newsym;
-      struct bfd_link_hash_entry *bh;
-
-      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_OBJECT;
-      if (fh->elf.root.type == bfd_link_hash_undefweak)
-       newsym->flags |= BSF_WEAK;
-
-      bh = &fdh->elf.root;
-      if ( !(_bfd_generic_link_add_one_symbol
-            (info, abfd, newsym->name, newsym->flags,
-             newsym->section, newsym->value, NULL, FALSE, FALSE, &bh)))
+      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 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.  */
+
+  if (fdh != NULL
+      && fdh->fake
+      && fdh->elf.root.type == bfd_link_hash_undefweak)
+    {
+      if (fh->elf.root.type == bfd_link_hash_undefined)
        {
-         return FALSE;
+         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);
        }
-      fdh = (struct ppc_link_hash_entry *) bh;
-      fdh->elf.non_elf = 0;
-      fdh->elf.size = 24;
-      fdh->elf.type = STT_OBJECT;
     }
 
   if (fdh != NULL
@@ -5401,11 +5540,7 @@ func_desc_adjust (struct elf_link_hash_entry *h, void *inf)
       fdh->elf.non_got_ref |= fh->elf.non_got_ref;
       if (ELF_ST_VISIBILITY (fh->elf.other) == STV_DEFAULT)
        {
-         struct plt_entry **ep = &fdh->elf.plt.plist;
-         while (*ep != NULL)
-           ep = &(*ep)->next;
-         *ep = fh->elf.plt.plist;
-         fh->elf.plt.plist = NULL;
+         move_plt_plist (fh, fdh);
          fdh->elf.needs_plt = 1;
        }
       fdh->is_func_descriptor = 1;
@@ -5420,12 +5555,10 @@ func_desc_adjust (struct elf_link_hash_entry *h, void *inf)
      been imported from another library.  Function code syms that
      are really in the library we must leave global to prevent the
      linker dragging in a definition from a static library.  */
-  force_local
-    = (info->shared
-       && (!fh->elf.def_regular
-          || fdh == NULL
-          || !fdh->elf.def_regular
-          || fdh->elf.forced_local));
+  force_local = (!fh->elf.def_regular
+                || fdh == NULL
+                || !fdh->elf.def_regular
+                || fdh->elf.forced_local);
   _bfd_elf_link_hash_hide_symbol (info, &fh->elf, force_local);
 
   return TRUE;
@@ -5472,7 +5605,7 @@ ppc64_elf_func_desc_adjust (bfd *obfd ATTRIBUTE_UNUSED,
   elf_link_hash_traverse (&htab->elf, func_desc_adjust, info);
 
   if (htab->sfpr->size == 0)
-    _bfd_strip_section_from_output (info, htab->sfpr);
+    htab->sfpr->flags |= SEC_EXCLUDE;
 
   return TRUE;
 }
@@ -5579,6 +5712,13 @@ ppc64_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
   /* This is a reference to a symbol defined by a dynamic object which
      is not a function.  */
 
+  if (h->size == 0)
+    {
+      (*_bfd_error_handler) (_("dynamic variable `%s' is zero size"),
+                            h->root.root.string);
+      return TRUE;
+    }
+
   /* We must allocate the symbol in our .dynbss section, which will
      become part of the .bss section of the executable.  There will be
      an entry for this symbol in the .dynsym section.  The dynamic
@@ -5864,13 +6004,13 @@ adjust_opd_syms (struct elf_link_hash_entry *h, void *inf ATTRIBUTE_UNUSED)
       if (adjust == -1)
        {
          /* This entry has been deleted.  */
-         asection *dsec = ppc64_elf_tdata (sym_sec->owner)->deleted_section;
+         asection *dsec = ppc64_elf_tdata (sym_sec->owner)->u.deleted_section;
          if (dsec == NULL)
            {
              for (dsec = sym_sec->owner->sections; dsec; dsec = dsec->next)
                if (elf_discarded_section (dsec))
                  {
-                   ppc64_elf_tdata (sym_sec->owner)->deleted_section = dsec;
+                   ppc64_elf_tdata (sym_sec->owner)->u.deleted_section = dsec;
                    break;
                  }
            }
@@ -5884,6 +6024,125 @@ adjust_opd_syms (struct elf_link_hash_entry *h, void *inf ATTRIBUTE_UNUSED)
   return TRUE;
 }
 
+/* Handles decrementing dynamic reloc counts for the reloc specified by
+   R_INFO in section SEC.  If LOCAL_SYMS is NULL, then H and SYM_SEC
+   have already been determined.  */
+
+static bfd_boolean
+dec_dynrel_count (bfd_vma r_info,
+                 asection *sec,
+                 struct bfd_link_info *info,
+                 Elf_Internal_Sym **local_syms,
+                 struct elf_link_hash_entry *h,
+                 asection *sym_sec)
+{
+  enum elf_ppc64_reloc_type r_type;
+  struct ppc_dyn_relocs *p;
+  struct ppc_dyn_relocs **pp;
+
+  /* Can this reloc be dynamic?  This switch, and later tests here
+     should be kept in sync with the code in check_relocs.  */
+  r_type = ELF64_R_TYPE (r_info);
+  switch (r_type)
+    {
+    default:
+      return TRUE;
+
+    case R_PPC64_TPREL16:
+    case R_PPC64_TPREL16_LO:
+    case R_PPC64_TPREL16_HI:
+    case R_PPC64_TPREL16_HA:
+    case R_PPC64_TPREL16_DS:
+    case R_PPC64_TPREL16_LO_DS:
+    case R_PPC64_TPREL16_HIGHER:
+    case R_PPC64_TPREL16_HIGHERA:
+    case R_PPC64_TPREL16_HIGHEST:
+    case R_PPC64_TPREL16_HIGHESTA:
+      if (!info->shared)
+       return TRUE;
+
+    case R_PPC64_TPREL64:
+    case R_PPC64_DTPMOD64:
+    case R_PPC64_DTPREL64:
+    case R_PPC64_ADDR64:
+    case R_PPC64_REL30:
+    case R_PPC64_REL32:
+    case R_PPC64_REL64:
+    case R_PPC64_ADDR14:
+    case R_PPC64_ADDR14_BRNTAKEN:
+    case R_PPC64_ADDR14_BRTAKEN:
+    case R_PPC64_ADDR16:
+    case R_PPC64_ADDR16_DS:
+    case R_PPC64_ADDR16_HA:
+    case R_PPC64_ADDR16_HI:
+    case R_PPC64_ADDR16_HIGHER:
+    case R_PPC64_ADDR16_HIGHERA:
+    case R_PPC64_ADDR16_HIGHEST:
+    case R_PPC64_ADDR16_HIGHESTA:
+    case R_PPC64_ADDR16_LO:
+    case R_PPC64_ADDR16_LO_DS:
+    case R_PPC64_ADDR24:
+    case R_PPC64_ADDR32:
+    case R_PPC64_UADDR16:
+    case R_PPC64_UADDR32:
+    case R_PPC64_UADDR64:
+    case R_PPC64_TOC:
+      break;
+    }
+
+  if (local_syms != NULL)
+    {
+      unsigned long r_symndx;
+      Elf_Internal_Sym *sym;
+      bfd *ibfd = sec->owner;
+
+      r_symndx = ELF64_R_SYM (r_info);
+      if (!get_sym_h (&h, &sym, &sym_sec, NULL, local_syms, r_symndx, ibfd))
+       return FALSE;
+    }
+
+  if ((info->shared
+       && (MUST_BE_DYN_RELOC (r_type)
+          || (h != NULL
+              && (!info->symbolic
+                  || h->root.type == bfd_link_hash_defweak
+                  || !h->def_regular))))
+      || (ELIMINATE_COPY_RELOCS
+         && !info->shared
+         && h != NULL
+         && (h->root.type == bfd_link_hash_defweak
+             || !h->def_regular)))
+    ;
+  else
+    return TRUE;
+
+  if (h != NULL)
+    pp = &((struct ppc_link_hash_entry *) h)->dyn_relocs;
+  else if (sym_sec != NULL)
+    pp = (struct ppc_dyn_relocs **) &elf_section_data (sym_sec)->local_dynrel;
+  else
+    pp = (struct ppc_dyn_relocs **) &elf_section_data (sec)->local_dynrel;
+
+  while ((p = *pp) != NULL)
+    {
+      if (p->sec == sec)
+       {
+         if (!MUST_BE_DYN_RELOC (r_type))
+           p->pc_count -= 1;
+         p->count -= 1;
+         if (p->count == 0)
+           *pp = p->next;
+         return TRUE;
+       }
+      pp = &p->next;
+    }
+
+  (*_bfd_error_handler) (_("dynreloc miscount for %B, section %A"),
+                          sec->owner, sec);
+  bfd_set_error (bfd_error_bad_value);
+  return FALSE;
+}
+
 /* Remove unused Official Procedure Descriptor entries.  Currently we
    only remove those associated with functions in discarded link-once
    sections, or weakly defined functions that have been overridden.  It
@@ -5892,6 +6151,7 @@ adjust_opd_syms (struct elf_link_hash_entry *h, void *inf ATTRIBUTE_UNUSED)
 
 bfd_boolean
 ppc64_elf_edit_opd (bfd *obfd, struct bfd_link_info *info,
+                   bfd_boolean no_opd_opt,
                    bfd_boolean non_overlapping)
 {
   bfd *ibfd;
@@ -5912,7 +6172,7 @@ ppc64_elf_edit_opd (bfd *obfd, struct bfd_link_info *info,
       bfd_size_type cnt_16b = 0;
 
       sec = bfd_get_section_by_name (ibfd, ".opd");
-      if (sec == NULL)
+      if (sec == NULL || sec->size == 0)
        continue;
 
       amt = sec->size * sizeof (long) / 8;
@@ -5921,11 +6181,16 @@ ppc64_elf_edit_opd (bfd *obfd, struct bfd_link_info *info,
        {
          /* check_relocs hasn't been called.  Must be a ld -r link
             or --just-symbols object.   */
-         opd_adjust = bfd_zalloc (obfd, amt);
+         opd_adjust = bfd_alloc (obfd, amt);
+         if (opd_adjust == NULL)
+           return FALSE;
          ppc64_elf_section_data (sec)->opd.adjust = opd_adjust;
        }
       memset (opd_adjust, 0, amt);
 
+      if (no_opd_opt)
+       continue;
+
       if (sec->sec_info_type == ELF_INFO_TYPE_JUST_SYMS)
        continue;
 
@@ -6000,7 +6265,8 @@ ppc64_elf_edit_opd (bfd *obfd, struct bfd_link_info *info,
              if (h != NULL)
                sym_name = h->root.root.string;
              else
-               sym_name = bfd_elf_sym_name (ibfd, symtab_hdr, sym);
+               sym_name = bfd_elf_sym_name (ibfd, symtab_hdr, sym,
+                                            sym_sec);
 
              (*_bfd_error_handler)
                (_("%B: undefined sym `%s' in .opd section"),
@@ -6094,18 +6360,16 @@ ppc64_elf_edit_opd (bfd *obfd, struct bfd_link_info *info,
 
          elf_section_data (sec)->relocs = relstart;
 
-         wptr = sec->contents;
-         rptr = sec->contents;
          new_contents = sec->contents;
-
          if (add_aux_fields)
            {
              new_contents = bfd_malloc (sec->size + cnt_16b * 8);
              if (new_contents == NULL)
                return FALSE;
              need_pad = FALSE;
-             wptr = new_contents;
            }
+         wptr = new_contents;
+         rptr = sec->contents;
 
          write_rel = relstart;
          skip = FALSE;
@@ -6141,8 +6405,14 @@ ppc64_elf_edit_opd (bfd *obfd, struct bfd_link_info *info,
 
                  if (h != NULL
                      && h->root.root.string[0] == '.')
-                   fdh = get_fdh ((struct ppc_link_hash_entry *) h,
-                                  ppc_hash_table (info));
+                   {
+                     fdh = get_fdh ((struct ppc_link_hash_entry *) h,
+                                    ppc_hash_table (info));
+                     if (fdh != NULL
+                         && fdh->elf.root.type != bfd_link_hash_defined
+                         && fdh->elf.root.type != bfd_link_hash_defweak)
+                       fdh = NULL;
+                   }
 
                  skip = (sym_sec->owner != ibfd
                          || sym_sec->output_section == bfd_abs_section_ptr);
@@ -6198,33 +6468,10 @@ ppc64_elf_edit_opd (bfd *obfd, struct bfd_link_info *info,
 
              if (skip)
                {
-                 BFD_ASSERT (MUST_BE_DYN_RELOC (ELF64_R_TYPE (rel->r_info)));
-                 if (info->shared)
-                   {
-                     /* We won't be needing dynamic relocs here.  */
-                     struct ppc_dyn_relocs **pp;
-                     struct ppc_dyn_relocs *p;
-
-                     if (h != NULL)
-                       pp = &((struct ppc_link_hash_entry *) h)->dyn_relocs;
-                     else if (sym_sec != NULL)
-                       pp = ((struct ppc_dyn_relocs **)
-                             &elf_section_data (sym_sec)->local_dynrel);
-                     else
-                       pp = ((struct ppc_dyn_relocs **)
-                             &elf_section_data (sec)->local_dynrel);
-                     while ((p = *pp) != NULL)
-                       {
-                         if (p->sec == sec)
-                           {
-                             p->count -= 1;
-                             if (p->count == 0)
-                               *pp = p->next;
-                             break;
-                           }
-                         pp = &p->next;
-                       }
-                   }
+                 if (!info->relocatable
+                     && !dec_dynrel_count (rel->r_info, sec, info,
+                                           NULL, h, sym_sec))
+                   goto error_ret;
                }
              else
                {
@@ -6326,7 +6573,9 @@ ppc64_elf_tls_setup (bfd *obfd, struct bfd_link_info *info)
 
       if (htab->tls_get_addr_fd == NULL
          && h->oh != NULL
-         && h->oh->is_func_descriptor)
+         && h->oh->is_func_descriptor
+         && (h->oh->elf.root.type == bfd_link_hash_defined
+             || h->oh->elf.root.type == bfd_link_hash_defweak))
        htab->tls_get_addr_fd = h->oh;
     }
 
@@ -6593,29 +6842,20 @@ ppc64_elf_tls_optimize (bfd *obfd ATTRIBUTE_UNUSED, struct bfd_link_info *info)
                          ent->got.refcount -= 1;
                      }
                  }
-               else if (h != NULL)
+               else
                  {
-                   struct ppc_link_hash_entry * eh;
-                   struct ppc_dyn_relocs **pp;
-                   struct ppc_dyn_relocs *p;
-
-                   /* Adjust dynamic relocs.  */
-                   eh = (struct ppc_link_hash_entry *) h;
-                   for (pp = &eh->dyn_relocs;
-                        (p = *pp) != NULL;
-                        pp = &p->next)
-                     if (p->sec == sec)
-                       {
-                         /* If we got rid of a DTPMOD/DTPREL reloc
-                            pair then we'll lose one or two dyn
-                            relocs.  */
-                         if (tls_set == (TLS_EXPLICIT | TLS_GD))
-                           p->count -= 1;
-                         p->count -= 1;
-                         if (p->count == 0)
-                           *pp = p->next;
-                         break;
-                       }
+                   /* If we got rid of a DTPMOD/DTPREL reloc pair then
+                      we'll lose one or two dyn relocs.  */
+                   if (!dec_dynrel_count (rel->r_info, sec, info,
+                                          NULL, h, sym_sec))
+                     return FALSE;
+
+                   if (tls_set == (TLS_EXPLICIT | TLS_GD))
+                     {
+                       if (!dec_dynrel_count ((rel + 1)->r_info, sec, info,
+                                              NULL, h, sym_sec))
+                         return FALSE;
+                     }
                  }
 
                *tls_mask |= tls_set;
@@ -6708,13 +6948,14 @@ ppc64_elf_edit_toc (bfd *obfd ATTRIBUTE_UNUSED, struct bfd_link_info *info)
       Elf_Internal_Shdr *symtab_hdr;
       Elf_Internal_Sym *local_syms;
       struct elf_link_hash_entry **sym_hashes;
-      Elf_Internal_Rela *relstart, *rel, *wrel;
+      Elf_Internal_Rela *relstart, *rel;
       unsigned long *skip, *drop;
       unsigned char *used;
       unsigned char *keep, last, some_unused;
 
       toc = bfd_get_section_by_name (ibfd, ".toc");
       if (toc == NULL
+         || toc->size == 0
          || toc->sec_info_type == ELF_INFO_TYPE_JUST_SYMS
          || elf_discarded_section (toc))
        continue;
@@ -6959,25 +7200,36 @@ ppc64_elf_edit_toc (bfd *obfd ATTRIBUTE_UNUSED, struct bfd_link_info *info)
          toc->rawsize = toc->size;
          toc->size = src - contents - off;
 
-         /* Read toc relocs.  */
-         relstart = _bfd_elf_link_read_relocs (ibfd, toc, NULL, NULL, TRUE);
-         if (relstart == NULL)
-           goto error_ret;
+         if (toc->reloc_count != 0)
+           {
+             Elf_Internal_Rela *wrel;
+             bfd_size_type sz;
 
-         /* Remove unused toc relocs, and adjust those we keep.  */
-         wrel = relstart;
-         for (rel = relstart; rel < relstart + toc->reloc_count; ++rel)
-           if (skip[rel->r_offset >> 3] != (unsigned long) -1)
-             {
-               wrel->r_offset = rel->r_offset - skip[rel->r_offset >> 3];
-               wrel->r_info = rel->r_info;
-               wrel->r_addend = rel->r_addend;
-               ++wrel;
-             }
-         toc->reloc_count = wrel - relstart;
-         elf_section_data (toc)->rel_hdr.sh_size
-           = toc->reloc_count * elf_section_data (toc)->rel_hdr.sh_entsize;
-         BFD_ASSERT (elf_section_data (toc)->rel_hdr2 == NULL);
+             /* Read toc relocs.  */
+             relstart = _bfd_elf_link_read_relocs (ibfd, toc, NULL, NULL,
+                                                   TRUE);
+             if (relstart == NULL)
+               goto error_ret;
+
+             /* Remove unused toc relocs, and adjust those we keep.  */
+             wrel = relstart;
+             for (rel = relstart; rel < relstart + toc->reloc_count; ++rel)
+               if (skip[rel->r_offset >> 3] != (unsigned long) -1)
+                 {
+                   wrel->r_offset = rel->r_offset - skip[rel->r_offset >> 3];
+                   wrel->r_info = rel->r_info;
+                   wrel->r_addend = rel->r_addend;
+                   ++wrel;
+                 }
+               else if (!dec_dynrel_count (rel->r_info, toc, info,
+                                           &local_syms, NULL, NULL))
+                 goto error_ret;
+
+             toc->reloc_count = wrel - relstart;
+             sz = elf_section_data (toc)->rel_hdr.sh_entsize;
+             elf_section_data (toc)->rel_hdr.sh_size = toc->reloc_count * sz;
+             BFD_ASSERT (elf_section_data (toc)->rel_hdr2 == NULL);
+           }
 
          /* Adjust addends for relocs against the toc section sym.  */
          for (sec = ibfd->sections; sec != NULL; sec = sec->next)
@@ -7048,7 +7300,8 @@ ppc64_elf_edit_toc (bfd *obfd ATTRIBUTE_UNUSED, struct bfd_link_info *info)
                      {
                        (*_bfd_error_handler)
                          (_("%s defined in removed toc entry"),
-                          bfd_elf_sym_name (ibfd, symtab_hdr, sym));
+                          bfd_elf_sym_name (ibfd, symtab_hdr, sym,
+                                            NULL));
                        sym->st_value = 0;
                        sym->st_shndx = SHN_ABS;
                      }
@@ -7475,26 +7728,15 @@ ppc64_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
        continue;
       else if (s == htab->got
               || s == htab->plt
-              || s == htab->glink)
+              || s == htab->glink
+              || s == htab->dynbss)
        {
          /* Strip this section if we don't need it; see the
             comment below.  */
        }
       else if (strncmp (bfd_get_section_name (dynobj, s), ".rela", 5) == 0)
        {
-         if (s->size == 0)
-           {
-             /* If we don't need this section, strip it from the
-                output file.  This is mostly to handle .rela.bss and
-                .rela.plt.  We must create both sections in
-                create_dynamic_sections, because they must be created
-                before the linker maps input sections to output
-                sections.  The linker does that before
-                adjust_dynamic_symbol is called, and it is that
-                function which decides whether anything needs to go
-                into these sections.  */
-           }
-         else
+         if (s->size != 0)
            {
              if (s != htab->relplt)
                relocs = TRUE;
@@ -7512,12 +7754,20 @@ ppc64_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
 
       if (s->size == 0)
        {
-         _bfd_strip_section_from_output (info, s);
+         /* If we don't need this section, strip it from the
+            output file.  This is mostly to handle .rela.bss and
+            .rela.plt.  We must create both sections in
+            create_dynamic_sections, because they must be created
+            before the linker maps input sections to output
+            sections.  The linker does that before
+            adjust_dynamic_symbol is called, and it is that
+            function which decides whether anything needs to go
+            into these sections.  */
+         s->flags |= SEC_EXCLUDE;
          continue;
        }
 
-      /* .plt is in the bss section.  We don't initialise it.  */
-      if (s == htab->plt)
+      if ((s->flags & SEC_HAS_CONTENTS) == 0)
        continue;
 
       /* Allocate memory for the section contents.  We use bfd_zalloc
@@ -7541,7 +7791,7 @@ ppc64_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
       if (s != NULL && s != htab->got)
        {
          if (s->size == 0)
-           _bfd_strip_section_from_output (info, s);
+           s->flags |= SEC_EXCLUDE;
          else
            {
              s->contents = bfd_zalloc (ibfd, s->size);
@@ -7553,7 +7803,7 @@ ppc64_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
       if (s != NULL)
        {
          if (s->size == 0)
-           _bfd_strip_section_from_output (info, s);
+           s->flags |= SEC_EXCLUDE;
          else
            {
              s->contents = bfd_zalloc (ibfd, s->size);
@@ -8161,7 +8411,7 @@ ppc64_elf_setup_section_lists (bfd *output_bfd,
 
   /* We can't use output_bfd->section_count here to find the top output
      section index as some sections may have been removed, and
-     _bfd_strip_section_from_output doesn't renumber the indices.  */
+     strip_excluded_output_sections doesn't renumber the indices.  */
   for (section = output_bfd->sections, top_index = 0;
        section != NULL;
        section = section->next)
@@ -8287,13 +8537,27 @@ toc_adjusting_stub_needed (struct bfd_link_info *info, asection *isec)
          break;
        }
 
-      /* Ignore branches to undefined syms.  */
+      /* Calls to dynamic lib functions go through a plt call stub
+        that uses r2.  Branches to undefined symbols might be a call
+        using old-style dot symbols that can be satisfied by a plt
+        call into a new-style dynamic library.  */
       if (sym_sec == NULL)
-       continue;
+       {
+         struct ppc_link_hash_entry *eh = (struct ppc_link_hash_entry *) h;
+         if (eh != NULL
+             && eh->oh != NULL
+             && eh->oh->elf.plt.plist != NULL)
+           {
+             ret = 1;
+             break;
+           }
 
-      /* Calls to dynamic lib functions go through a plt call stub
-        that uses r2.  Assume branches to other sections not included
-        in the link need stubs too, to cover -R and absolute syms.  */
+         /* Ignore other undefined symbols.  */
+         continue;
+       }
+
+      /* Assume branches to other sections not included in the link need
+        stubs too, to cover -R and absolute syms.  */
       if (sym_sec->output_section == NULL)
        {
          ret = 1;
@@ -8315,7 +8579,6 @@ toc_adjusting_stub_needed (struct bfd_link_info *info, asection *isec)
       opd_adjust = get_opd_info (sym_sec);
       if (opd_adjust != NULL)
        {
-
          if (h == NULL)
            {
              long adjust;
@@ -8691,8 +8954,7 @@ ppc64_elf_size_stubs (bfd *output_bfd,
                      sym_value = 0;
                      /* Recognise an old ABI func code entry sym, and
                         use the func descriptor sym instead.  */
-                     if (hash->elf.root.type == bfd_link_hash_undefweak
-                         && hash->elf.root.root.string[0] == '.'
+                     if (hash->elf.root.root.string[0] == '.'
                          && (fdh = get_fdh (hash, htab)) != NULL)
                        {
                          if (fdh->elf.root.type == bfd_link_hash_defined
@@ -8887,7 +9149,7 @@ ppc64_elf_size_stubs (bfd *output_bfd,
       (*htab->layout_sections_again) ();
     }
 
-  /* It would be nice to strip .branch_lt from the output if the
+  /* It would be nice to strip htab->brlt from the output if the
      section is empty, but it's too late.  If we strip sections here,
      the dynamic symbol table is corrupted since the section symbol
      for the stripped section isn't written.  */
@@ -9288,7 +9550,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
 
          sym = local_syms + r_symndx;
          sec = local_sections[r_symndx];
-         sym_name = bfd_elf_sym_name (input_bfd, symtab_hdr, sym);
+         sym_name = bfd_elf_sym_name (input_bfd, symtab_hdr, sym, sec);
          sym_type = ELF64_ST_TYPE (sym->st_info);
          relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel);
          opd_adjust = get_opd_info (sec);
@@ -9744,6 +10006,8 @@ ppc64_elf_relocate_section (bfd *output_bfd,
                      br = bfd_get_32 (input_bfd, contents + rel->r_offset);
                      if ((br & 1) == 0)
                        can_plt_call = TRUE;
+                     else
+                       stub_entry = NULL;
                    }
                  else if (h != NULL
                           && strcmp (h->elf.root.root.string,
This page took 0.042572 seconds and 4 git commands to generate.