PR ld/1540
[deliverable/binutils-gdb.git] / bfd / elf64-ppc.c
index 115610ac0d2994446191a8f970607ce5322f9cff..d15c77230d714682073eb68918a2672d3ced289e 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 02110-1301, 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
@@ -96,6 +95,7 @@ static bfd_vma opd_entry_value
 #define elf_backend_hide_symbol                      ppc64_elf_hide_symbol
 #define elf_backend_always_size_sections      ppc64_elf_func_desc_adjust
 #define elf_backend_size_dynamic_sections     ppc64_elf_size_dynamic_sections
+#define elf_backend_action_discarded         ppc64_elf_action_discarded
 #define elf_backend_relocate_section         ppc64_elf_relocate_section
 #define elf_backend_finish_dynamic_symbol     ppc64_elf_finish_dynamic_symbol
 #define elf_backend_reloc_type_class         ppc64_elf_reloc_type_class
@@ -2118,8 +2118,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 +2375,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 +2514,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 },
@@ -2709,7 +2719,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)
@@ -3186,7 +3196,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.  */
@@ -3471,10 +3481,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;
 }
@@ -3528,26 +3542,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;
@@ -3667,38 +3681,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;
 }
 
@@ -3725,15 +3764,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;
 
@@ -3806,10 +3844,9 @@ move_plt_plist (struct ppc_link_hash_entry *from,
 /* Copy the extra info we tack onto an elf_link_hash_entry.  */
 
 static void
-ppc64_elf_copy_indirect_symbol
-  (const struct elf_backend_data *bed ATTRIBUTE_UNUSED,
-   struct elf_link_hash_entry *dir,
-   struct elf_link_hash_entry *ind)
+ppc64_elf_copy_indirect_symbol (struct bfd_link_info *info,
+                               struct elf_link_hash_entry *dir,
+                               struct elf_link_hash_entry *ind)
 {
   struct ppc_link_hash_entry *edir, *eind;
 
@@ -3824,10 +3861,7 @@ ppc64_elf_copy_indirect_symbol
          struct ppc_dyn_relocs **pp;
          struct ppc_dyn_relocs *p;
 
-         if (eind->elf.root.type == bfd_link_hash_indirect)
-           abort ();
-
-         /* Add reloc counts against the weak sym to the strong sym
+         /* Add reloc counts against the indirect sym to the direct sym
             list.  Merge any entries against the same section.  */
          for (pp = &eind->dyn_relocs; (p = *pp) != NULL; )
            {
@@ -3907,15 +3941,16 @@ ppc64_elf_copy_indirect_symbol
   /* And plt entries.  */
   move_plt_plist (eind, edir);
 
-  if (edir->elf.dynindx == -1)
+  if (eind->elf.dynindx != -1)
     {
+      if (edir->elf.dynindx != -1)
+       _bfd_elf_strtab_delref (elf_hash_table (info)->dynstr,
+                               edir->elf.dynstr_index);
       edir->elf.dynindx = eind->elf.dynindx;
       edir->elf.dynstr_index = eind->elf.dynstr_index;
       eind->elf.dynindx = -1;
       eind->elf.dynstr_index = 0;
     }
-  else
-    BFD_ASSERT (eind->elf.dynindx == -1);
 }
 
 /* Find the function descriptor hash entry from the given function code
@@ -3998,10 +4033,10 @@ make_fdh (struct bfd_link_info *info,
    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)
@@ -4009,6 +4044,13 @@ 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;
 }
 
@@ -4099,9 +4141,7 @@ add_symbol_adjust (struct elf_link_hash_entry *h, void *inf)
       else
        fdh->elf.ref_regular = 1;
     }
-  else if (fdh != NULL
-          && (fdh->elf.root.type == bfd_link_hash_defined
-              || fdh->elf.root.type == bfd_link_hash_defweak))
+  else if (fdh != NULL)
     {
       unsigned entry_vis = ELF_ST_VISIBILITY (eh->elf.other) - 1;
       unsigned descr_vis = ELF_ST_VISIBILITY (fdh->elf.other) - 1;
@@ -4110,7 +4150,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;
@@ -4122,12 +4164,18 @@ 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;
@@ -4299,7 +4347,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)
@@ -4686,12 +4739,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
                               | 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;
                    }
@@ -4711,13 +4765,15 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
                     easily.  Oh well.  */
 
                  asection *s;
+                 void *vpp;
+
                  s = bfd_section_from_r_symndx (abfd, &htab->sym_sec,
                                                 sec, r_symndx);
                  if (s == NULL)
                    return FALSE;
 
-                 head = ((struct ppc_dyn_relocs **)
-                         &elf_section_data (s)->local_dynrel);
+                 vpp = &elf_section_data (s)->local_dynrel;
+                 head = (struct ppc_dyn_relocs **) vpp;
                }
 
              p = *head;
@@ -4768,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;
@@ -4997,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];
        }
     }
 
@@ -5446,15 +5502,25 @@ func_desc_adjust (struct elf_link_hash_entry *h, void *inf)
     }
 
   /* Fake function descriptors are made undefweak.  If the function
-     code symbol is strong undefined, make the fake sym the same.  */
+     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
-      && fh->elf.root.type == bfd_link_hash_undefined)
+      && fdh->elf.root.type == bfd_link_hash_undefweak)
     {
-      fdh->elf.root.type = bfd_link_hash_undefined;
-      bfd_link_add_undef (&htab->elf.root, &fdh->elf.root);
+      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);
+       }
     }
 
   if (fdh != NULL
@@ -5646,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
@@ -5931,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;
                  }
            }
@@ -6045,10 +6118,25 @@ dec_dynrel_count (bfd_vma r_info,
 
   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;
+    {
+      if (sym_sec != NULL)
+       {
+         void *vpp = &elf_section_data (sym_sec)->local_dynrel;
+         pp = (struct ppc_dyn_relocs **) vpp;
+       }
+      else
+       {
+         void *vpp = &elf_section_data (sec)->local_dynrel;
+         pp = (struct ppc_dyn_relocs **) vpp;
+       }
+
+      /* elf_gc_sweep may have already removed all dyn relocs associated
+        with local syms for a given section.  Don't report a dynreloc
+        miscount.  */
+      if (*pp == NULL)
+       return TRUE;
+    }
 
   while ((p = *pp) != NULL)
     {
@@ -6078,6 +6166,7 @@ dec_dynrel_count (bfd_vma r_info,
 
 bfd_boolean
 ppc64_elf_edit_opd (bfd *obfd, struct bfd_link_info *info,
+                   bfd_boolean no_opd_opt,
                    bfd_boolean non_overlapping)
 {
   bfd *ibfd;
@@ -6098,7 +6187,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;
@@ -6107,11 +6196,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;
 
@@ -6281,18 +6375,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;
@@ -6391,8 +6483,10 @@ ppc64_elf_edit_opd (bfd *obfd, struct bfd_link_info *info,
 
              if (skip)
                {
-                 if (!dec_dynrel_count (rel->r_info, sec, info,
-                                        NULL, h, sym_sec))
+                 if (!NO_OPD_RELOCS
+                     && !info->relocatable
+                     && !dec_dynrel_count (rel->r_info, sec, info,
+                                           NULL, h, sym_sec))
                    goto error_ret;
                }
              else
@@ -7560,10 +7654,7 @@ ppc64_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
        {
          struct ppc_dyn_relocs *p;
 
-         for (p = *((struct ppc_dyn_relocs **)
-                    &elf_section_data (s)->local_dynrel);
-              p != NULL;
-              p = p->next)
+         for (p = elf_section_data (s)->local_dynrel; p != NULL; p = p->next)
            {
              if (!bfd_is_abs_section (p->sec)
                  && bfd_is_abs_section (p->sec->output_section))
@@ -7650,26 +7741,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;
@@ -7687,12 +7767,20 @@ ppc64_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
 
       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.  */
          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
@@ -7813,26 +7901,34 @@ ppc_type_of_stub (asection *input_sec,
 
   if (h != NULL)
     {
-      if (h->oh != NULL
-         && h->oh->is_func_descriptor)
-       h = h->oh;
+      struct ppc_link_hash_entry *fdh = h;
+      if (fdh->oh != NULL
+         && fdh->oh->is_func_descriptor)
+       fdh = fdh->oh;
 
-      if (h->elf.dynindx != -1)
+      if (fdh->elf.dynindx != -1)
        {
          struct plt_entry *ent;
 
-         for (ent = h->elf.plt.plist; ent != NULL; ent = ent->next)
+         for (ent = fdh->elf.plt.plist; ent != NULL; ent = ent->next)
            if (ent->addend == rel->r_addend
                && ent->plt.offset != (bfd_vma) -1)
              {
-               *hash = h;
+               *hash = fdh;
                return ppc_stub_plt_call;
              }
        }
 
-      if (!(h->elf.root.type == bfd_link_hash_defined
-           || h->elf.root.type == bfd_link_hash_defweak)
-         || h->elf.root.u.def.section->output_section == NULL)
+      /* Here, we know we don't have a plt entry.  If we don't have a
+        either a defined function descriptor or a defined entry symbol
+        in a regular object file, then it is pointless trying to make
+        any other type of stub.  */
+      if (!((fdh->elf.root.type == bfd_link_hash_defined
+           || fdh->elf.root.type == bfd_link_hash_defweak)
+           && fdh->elf.root.u.def.section->output_section != NULL)
+         && !((h->elf.root.type == bfd_link_hash_defined
+               || h->elf.root.type == bfd_link_hash_defweak)
+              && h->elf.root.u.def.section->output_section != NULL))
        return ppc_stub_none;
     }
 
@@ -7940,7 +8036,13 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
        }
       bfd_put_32 (htab->stub_bfd, B_DOT | (off & 0x3fffffc), loc);
 
-      BFD_ASSERT (off + (1 << 25) < (bfd_vma) (1 << 26));
+      if (off + (1 << 25) >= (bfd_vma) (1 << 26))
+       {
+         (*_bfd_error_handler) (_("long branch stub `%s' offset overflow"),
+                                stub_entry->root.string);
+         htab->stub_error = TRUE;
+         return FALSE;
+       }
 
       if (info->emitrelocations)
        {
@@ -8012,7 +8114,7 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
       if (br_entry == NULL)
        {
          (*_bfd_error_handler) (_("can't find branch stub `%s'"),
-                                stub_entry->root.string + 9);
+                                stub_entry->root.string);
          htab->stub_error = TRUE;
          return FALSE;
        }
@@ -8256,7 +8358,7 @@ ppc_size_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
          if (br_entry == NULL)
            {
              (*_bfd_error_handler) (_("can't build branch stub `%s'"),
-                                    stub_entry->root.string + 9);
+                                    stub_entry->root.string);
              htab->stub_error = TRUE;
              return FALSE;
            }
@@ -8677,7 +8779,10 @@ group_sections (struct ppc_link_hash_table *htab,
 
          curr = tail;
          total = tail->size;
-         big_sec = total >= stub_group_size;
+         big_sec = total > stub_group_size;
+         if (big_sec)
+           (*_bfd_error_handler) (_("%B section %A exceeds stub group size"),
+                                    tail->owner, tail);
          curr_toc = htab->stub_group[tail->id].toc_off;
 
          while ((prev = PREV_SEC (curr)) != NULL
@@ -8779,10 +8884,8 @@ ppc64_elf_size_stubs (bfd *output_bfd,
       bfd *input_bfd;
       unsigned int bfd_indx;
       asection *stub_sec;
-      bfd_boolean stub_changed;
 
       htab->stub_iteration += 1;
-      stub_changed = FALSE;
 
       for (input_bfd = info->input_bfds, bfd_indx = 0;
           input_bfd != NULL;
@@ -8869,16 +8972,25 @@ ppc64_elf_size_stubs (bfd *output_bfd,
 
                  ok_dest = FALSE;
                  fdh = NULL;
+                 sym_value = 0;
                  if (hash == NULL)
                    {
                      sym_value = sym->st_value;
                      ok_dest = TRUE;
                    }
-                 else
+                 else if (hash->elf.root.type == bfd_link_hash_defined
+                          || hash->elf.root.type == bfd_link_hash_defweak)
+                   {
+                     sym_value = hash->elf.root.u.def.value;
+                     if (sym_sec->output_section != NULL)
+                       ok_dest = TRUE;
+                   }
+                 else if (hash->elf.root.type == bfd_link_hash_undefweak
+                          || hash->elf.root.type == bfd_link_hash_undefined)
                    {
-                     sym_value = 0;
                      /* Recognise an old ABI func code entry sym, and
-                        use the func descriptor sym instead.  */
+                        use the func descriptor sym instead if it is
+                        defined.  */
                      if (hash->elf.root.root.string[0] == '.'
                          && (fdh = get_fdh (hash, htab)) != NULL)
                        {
@@ -8893,22 +9005,11 @@ ppc64_elf_size_stubs (bfd *output_bfd,
                          else
                            fdh = NULL;
                        }
-                     else if (hash->elf.root.type == bfd_link_hash_defined
-                              || hash->elf.root.type == bfd_link_hash_defweak)
-                       {
-                         sym_value = hash->elf.root.u.def.value;
-                         if (sym_sec->output_section != NULL)
-                           ok_dest = TRUE;
-                       }
-                     else if (hash->elf.root.type == bfd_link_hash_undefweak)
-                       ;
-                     else if (hash->elf.root.type == bfd_link_hash_undefined)
-                       ;
-                     else
-                       {
-                         bfd_set_error (bfd_error_bad_value);
-                         goto error_ret_free_internal;
-                       }
+                   }
+                 else
+                   {
+                     bfd_set_error (bfd_error_bad_value);
+                     goto error_ret_free_internal;
                    }
 
                  destination = 0;
@@ -9031,8 +9132,6 @@ ppc64_elf_size_stubs (bfd *output_bfd,
 
                  if (stub_entry->h != NULL)
                    htab->stub_globals += 1;
-
-                 stub_changed = TRUE;
                }
 
              /* We're done with the internal relocs, free them.  */
@@ -9050,16 +9149,14 @@ ppc64_elf_size_stubs (bfd *output_bfd,
            }
        }
 
-      if (!stub_changed)
-       break;
-
-      /* OK, we've added some stubs.  Find out the new size of the
+      /* We may have added some stubs.  Find out the new size of the
         stub sections.  */
       for (stub_sec = htab->stub_bfd->sections;
           stub_sec != NULL;
           stub_sec = stub_sec->next)
        if ((stub_sec->flags & SEC_LINKER_CREATED) == 0)
          {
+           stub_sec->rawsize = stub_sec->size;
            stub_sec->size = 0;
            stub_sec->reloc_count = 0;
          }
@@ -9070,11 +9167,23 @@ ppc64_elf_size_stubs (bfd *output_bfd,
 
       bfd_hash_traverse (&htab->stub_hash_table, ppc_size_one_stub, info);
 
+      for (stub_sec = htab->stub_bfd->sections;
+          stub_sec != NULL;
+          stub_sec = stub_sec->next)
+       if ((stub_sec->flags & SEC_LINKER_CREATED) == 0
+           && stub_sec->rawsize != stub_sec->size)
+         break;
+
+      /* Exit from this loop when no stubs have been added, and no stubs
+        have changed size.  */
+      if (stub_sec == NULL)
+       break;
+
       /* Ask the linker to do its stuff.  */
       (*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.  */
@@ -9353,6 +9462,21 @@ ppc64_elf_restore_symbols (struct bfd_link_info *info)
   elf_link_hash_traverse (&htab->elf, undo_symbol_twiddle, info);
 }
 
+/* What to do when ld finds relocations against symbols defined in
+   discarded sections.  */
+
+static unsigned int
+ppc64_elf_action_discarded (asection *sec)
+{
+  if (strcmp (".opd", sec->name) == 0)
+    return 0;
+
+  if (strcmp (".toc", sec->name) == 0)
+    return 0;
+
+  return _bfd_elf_default_action_discarded (sec);
+}
+
 /* The RELOCATE_SECTION function is called by the ELF backend linker
    to handle the relocations for a section.
 
@@ -9931,6 +10055,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.037854 seconds and 4 git commands to generate.