Better handking for unresolved symbols
[deliverable/binutils-gdb.git] / bfd / elf64-ppc.c
index 07ba432c4ee996bc59ea4673ff509a55acc5db15..2042e6ae3234fd0bd7933bf1fb08c5e35f411fba 100644 (file)
@@ -28,7 +28,6 @@
 #include "bfdlink.h"
 #include "libbfd.h"
 #include "elf-bfd.h"
-#include "elf/ppc.h"
 #include "elf/ppc64.h"
 #include "elf64-ppc.h"
 
@@ -3036,7 +3035,7 @@ ppc_stub_name (const asection *input_section,
       stub_name = bfd_malloc (len);
       if (stub_name != NULL)
        {
-         sprintf (stub_name, "%08x_%s+%x",
+         sprintf (stub_name, "%08x.%s+%x",
                   input_section->id & 0xffffffff,
                   h->elf.root.root.string,
                   (int) rel->r_addend & 0xffffffff);
@@ -3048,7 +3047,7 @@ ppc_stub_name (const asection *input_section,
       stub_name = bfd_malloc (len);
       if (stub_name != NULL)
        {
-         sprintf (stub_name, "%08x_%x:%x+%x",
+         sprintf (stub_name, "%08x.%x:%x+%x",
                   input_section->id & 0xffffffff,
                   sym_sec->id & 0xffffffff,
                   (int) ELF64_R_SYM (rel->r_info) & 0xffffffff,
@@ -3277,9 +3276,10 @@ ppc64_elf_create_dynamic_sections (bfd *dynobj, struct bfd_link_info *info)
 /* Copy the extra info we tack onto an elf_link_hash_entry.  */
 
 static void
-ppc64_elf_copy_indirect_symbol (struct elf_backend_data *bed ATTRIBUTE_UNUSED,
-                               struct elf_link_hash_entry *dir,
-                               struct elf_link_hash_entry *ind)
+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)
 {
   struct ppc_link_hash_entry *edir, *eind;
   flagword mask;
@@ -3509,6 +3509,31 @@ update_plt_info (bfd *abfd, struct ppc_link_hash_entry *eh, bfd_vma addend)
   return TRUE;
 }
 
+/* Find the function descriptor hash entry from the given function code
+   hash entry FH.  Link the entries via their OH fields.  */
+static struct ppc_link_hash_entry *
+get_fdh (struct ppc_link_hash_entry *fh, struct ppc_link_hash_table *htab)
+{
+  struct ppc_link_hash_entry *fdh = (struct ppc_link_hash_entry *) fh->oh;
+
+  if (fdh == NULL)
+    {
+      const char *fd_name = fh->elf.root.root.string + 1;
+
+      fdh = (struct ppc_link_hash_entry *)
+       elf_link_hash_lookup (&htab->elf, fd_name, FALSE, FALSE, FALSE);
+      if (fdh != NULL)
+       {
+         fdh->is_func_descriptor = 1;
+         fdh->oh = &fh->elf;
+         fh->is_func = 1;
+         fh->oh = &fdh->elf;
+       }
+    }
+
+  return fdh;
+}
+
 /* Look through the relocs for a section during the first phase, and
    calculate needed space in the global offset table, procedure
    linkage table, and dynamic reloc sections.  */
@@ -3837,19 +3862,8 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
              && h != NULL
              && h->root.root.string[0] == '.'
              && h->root.root.string[1] != 0)
-           {
-             struct elf_link_hash_entry *fdh;
+           get_fdh ((struct ppc_link_hash_entry *) h, htab);
 
-             fdh = elf_link_hash_lookup (&htab->elf, h->root.root.string + 1,
-                                         FALSE, FALSE, FALSE);
-             if (fdh != NULL)
-               {
-                 ((struct ppc_link_hash_entry *) fdh)->is_func_descriptor = 1;
-                 ((struct ppc_link_hash_entry *) fdh)->oh = h;
-                 ((struct ppc_link_hash_entry *) h)->is_func = 1;
-                 ((struct ppc_link_hash_entry *) h)->oh = fdh;
-               }
-           }
          if (opd_sym_map != NULL
              && h == NULL
              && rel + 1 < rel_end
@@ -4247,117 +4261,118 @@ 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;
 
-  if (h->root.type == bfd_link_hash_indirect)
+  fh = (struct ppc_link_hash_entry *) h;
+  if (fh->elf.root.type == bfd_link_hash_indirect)
     return TRUE;
 
-  if (h->root.type == bfd_link_hash_warning)
-    h = (struct elf_link_hash_entry *) h->root.u.i.link;
+  if (fh->elf.root.type == bfd_link_hash_warning)
+    fh = (struct ppc_link_hash_entry *) fh->elf.root.u.i.link;
 
   info = inf;
   htab = ppc_hash_table (info);
 
   /* If this is a function code symbol, transfer dynamic linking
      information to the function descriptor symbol.  */
-  if (!((struct ppc_link_hash_entry *) h)->is_func)
+  if (!fh->is_func)
     return TRUE;
 
-  if (h->root.type == bfd_link_hash_undefweak
-      && (h->elf_link_hash_flags & ELF_LINK_HASH_REF_REGULAR))
+  if (fh->elf.root.type == bfd_link_hash_undefweak
+      && (fh->elf.elf_link_hash_flags & ELF_LINK_HASH_REF_REGULAR))
     htab->have_undefweak = TRUE;
 
-  for (ent = h->plt.plist; ent != NULL; ent = ent->next)
+  for (ent = fh->elf.plt.plist; ent != NULL; ent = ent->next)
     if (ent->plt.refcount > 0)
       break;
-  if (ent != NULL
-      && h->root.root.string[0] == '.'
-      && h->root.root.string[1] != '\0')
-    {
-      struct elf_link_hash_entry *fdh = ((struct ppc_link_hash_entry *) h)->oh;
-      bfd_boolean force_local;
+  if (ent == NULL
+      || fh->elf.root.root.string[0] != '.'
+      || fh->elf.root.root.string[1] == '\0')
+    return TRUE;
 
-      /* Find the corresponding function descriptor symbol.  Create it
-        as undefined if necessary.  */
+  /* Find the corresponding function descriptor symbol.  Create it
+     as undefined if necessary.  */
 
-      if (fdh == NULL)
-       fdh = elf_link_hash_lookup (&htab->elf, h->root.root.string + 1,
-                                   FALSE, FALSE, TRUE);
+  fdh = get_fdh (fh, htab);
+  if (fdh != NULL)
+    while (fdh->elf.root.type == bfd_link_hash_indirect
+          || fdh->elf.root.type == bfd_link_hash_warning)
+      fdh = (struct ppc_link_hash_entry *) fdh->elf.root.u.i.link;
 
-      if (fdh == NULL
-         && info->shared
-         && (h->root.type == bfd_link_hash_undefined
-             || h->root.type == bfd_link_hash_undefweak))
+  if (fdh == NULL
+      && info->shared
+      && (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)))
        {
-         bfd *abfd;
-         asymbol *newsym;
-         struct bfd_link_hash_entry *bh;
-
-         abfd = h->root.u.undef.abfd;
-         newsym = bfd_make_empty_symbol (abfd);
-         newsym->name = h->root.root.string + 1;
-         newsym->section = bfd_und_section_ptr;
-         newsym->value = 0;
-         newsym->flags = BSF_OBJECT;
-         if (h->root.type == bfd_link_hash_undefweak)
-           newsym->flags |= BSF_WEAK;
-
-         bh = &fdh->root;
-         if ( !(_bfd_generic_link_add_one_symbol
-                (info, abfd, newsym->name, newsym->flags,
-                 newsym->section, newsym->value, NULL, FALSE, FALSE, &bh)))
-           {
-             return FALSE;
-           }
-         fdh = (struct elf_link_hash_entry *) bh;
-         fdh->elf_link_hash_flags &= ~ELF_LINK_NON_ELF;
-         fdh->size = 24;
-         fdh->type = STT_OBJECT;
+         return FALSE;
        }
+      fdh = (struct ppc_link_hash_entry *) bh;
+      fdh->elf.elf_link_hash_flags &= ~ELF_LINK_NON_ELF;
+      fdh->elf.size = 24;
+      fdh->elf.type = STT_OBJECT;
+    }
 
-      if (fdh != NULL
-         && (fdh->elf_link_hash_flags & ELF_LINK_FORCED_LOCAL) == 0
-         && (info->shared
-             || (fdh->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC) != 0
-             || (fdh->elf_link_hash_flags & ELF_LINK_HASH_REF_DYNAMIC) != 0
-             || (fdh->root.type == bfd_link_hash_undefweak
-                 && ELF_ST_VISIBILITY (fdh->other) == STV_DEFAULT)))
+  if (fdh != NULL
+      && (fdh->elf.elf_link_hash_flags & ELF_LINK_FORCED_LOCAL) == 0
+      && (info->shared
+         || (fdh->elf.elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC) != 0
+         || (fdh->elf.elf_link_hash_flags & ELF_LINK_HASH_REF_DYNAMIC) != 0
+         || (fdh->elf.root.type == bfd_link_hash_undefweak
+             && ELF_ST_VISIBILITY (fdh->elf.other) == STV_DEFAULT)))
+    {
+      if (fdh->elf.dynindx == -1)
+       if (! bfd_elf64_link_record_dynamic_symbol (info, &fdh->elf))
+         return FALSE;
+      fdh->elf.elf_link_hash_flags
+       |= (fh->elf.elf_link_hash_flags & (ELF_LINK_HASH_REF_REGULAR
+                                     | ELF_LINK_HASH_REF_DYNAMIC
+                                     | ELF_LINK_HASH_REF_REGULAR_NONWEAK
+                                     | ELF_LINK_NON_GOT_REF));
+      if (ELF_ST_VISIBILITY (fh->elf.other) == STV_DEFAULT)
        {
-         if (fdh->dynindx == -1)
-           if (! bfd_elf64_link_record_dynamic_symbol (info, fdh))
-             return FALSE;
-         fdh->elf_link_hash_flags |= (h->elf_link_hash_flags
-                                      & (ELF_LINK_HASH_REF_REGULAR
-                                         | ELF_LINK_HASH_REF_DYNAMIC
-                                         | ELF_LINK_HASH_REF_REGULAR_NONWEAK
-                                         | ELF_LINK_NON_GOT_REF));
-         if (ELF_ST_VISIBILITY (h->other) == STV_DEFAULT)
-           {
-             fdh->plt.plist = h->plt.plist;
-             fdh->elf_link_hash_flags |= ELF_LINK_HASH_NEEDS_PLT;
-           }
-         ((struct ppc_link_hash_entry *) fdh)->is_func_descriptor = 1;
-         ((struct ppc_link_hash_entry *) fdh)->oh = h;
-         ((struct ppc_link_hash_entry *) h)->oh = fdh;
+         fdh->elf.plt.plist = fh->elf.plt.plist;
+         fdh->elf.elf_link_hash_flags |= ELF_LINK_HASH_NEEDS_PLT;
        }
-
-      /* Now that the info is on the function descriptor, clear the
-        function code sym info.  Any function code syms for which we
-        don't have a definition in a regular file, we force local.
-        This prevents a shared library from exporting syms that have
-        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
-                    && ((h->elf_link_hash_flags
-                         & ELF_LINK_HASH_DEF_REGULAR) == 0
-                        || fdh == NULL
-                        || (fdh->elf_link_hash_flags
-                            & ELF_LINK_HASH_DEF_REGULAR) == 0
-                        || (fdh->elf_link_hash_flags
-                            & ELF_LINK_FORCED_LOCAL) != 0));
-      _bfd_elf_link_hash_hide_symbol (info, h, force_local);
+      fdh->is_func_descriptor = 1;
+      fdh->oh = &fh->elf;
+      fh->oh = &fdh->elf;
     }
 
+  /* Now that the info is on the function descriptor, clear the
+     function code sym info.  Any function code syms for which we
+     don't have a definition in a regular file, we force local.
+     This prevents a shared library from exporting syms that have
+     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.elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0
+          || fdh == NULL
+          || (fdh->elf.elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0
+          || (fdh->elf.elf_link_hash_flags & ELF_LINK_FORCED_LOCAL) != 0));
+  _bfd_elf_link_hash_hide_symbol (info, &fh->elf, force_local);
+
   return TRUE;
 }
 
@@ -4568,7 +4583,17 @@ ppc64_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
     }
 
   if (h->plt.plist != NULL)
-    return TRUE;
+    {
+      /* We should never get here, but unfortunately there are versions
+        of gcc out there that improperly (for this ABI) put initialized
+        function pointers, vtable refs and suchlike in read-only
+        sections.  Allow them to proceed, but warn that this might
+        break at runtime.  */
+      (*_bfd_error_handler)
+       (_("copy reloc against `%s' requires lazy plt linking; "
+          "avoid setting LD_BIND_NOW=1 or upgrade gcc"),
+        h->root.root.string);
+    }
 
   /* This is a reference to a symbol defined by a dynamic object which
      is not a function.  */
@@ -4874,7 +4899,7 @@ ppc64_elf_edit_opd (bfd *obfd, struct bfd_link_info *info)
       need_edit = FALSE;
       offset = 0;
       relend = relstart + sec->reloc_count;
-      for (rel = relstart; rel < relend; rel++)
+      for (rel = relstart; rel < relend; )
        {
          enum elf_ppc64_reloc_type r_type;
          unsigned long r_symndx;
@@ -4885,26 +4910,9 @@ ppc64_elf_edit_opd (bfd *obfd, struct bfd_link_info *info)
          /* .opd contains a regular array of 24 byte entries.  We're
             only interested in the reloc pointing to a function entry
             point.  */
-         r_type = ELF64_R_TYPE (rel->r_info);
-         if (r_type == R_PPC64_TOC)
-           continue;
-
-         if (r_type != R_PPC64_ADDR64)
-           {
-             (*_bfd_error_handler)
-               (_("%s: unexpected reloc type %u in .opd section"),
-                bfd_archive_filename (ibfd), r_type);
-             need_edit = FALSE;
-             break;
-           }
-
-         if (rel + 1 >= relend)
-           continue;
-         r_type = ELF64_R_TYPE ((rel + 1)->r_info);
-         if (r_type != R_PPC64_TOC)
-           continue;
-
-         if (rel->r_offset != offset)
+         if (rel->r_offset != offset
+             || rel + 1 >= relend
+             || (rel + 1)->r_offset != offset + 8)
            {
              /* If someone messes with .opd alignment then after a
                 "ld -r" we might have padding in the middle of .opd.
@@ -4918,10 +4926,20 @@ ppc64_elf_edit_opd (bfd *obfd, struct bfd_link_info *info)
              break;
            }
 
+         if ((r_type = ELF64_R_TYPE (rel->r_info)) != R_PPC64_ADDR64
+             || (r_type = ELF64_R_TYPE ((rel + 1)->r_info)) != R_PPC64_TOC)
+           {
+             (*_bfd_error_handler)
+               (_("%s: unexpected reloc type %u in .opd section"),
+                bfd_archive_filename (ibfd), r_type);
+             need_edit = FALSE;
+             break;
+           }
+
          r_symndx = ELF64_R_SYM (rel->r_info);
          if (!get_sym_h (&h, &sym, &sym_sec, NULL, &local_syms,
                          r_symndx, ibfd))
-           goto error_free_rel;
+           goto error_ret;
 
          if (sym_sec == NULL || sym_sec->owner == NULL)
            {
@@ -4951,6 +4969,11 @@ ppc64_elf_edit_opd (bfd *obfd, struct bfd_link_info *info)
            need_edit = TRUE;
 
          offset += 24;
+         rel += 2;
+         /* Allow for the possibility of a reloc on the third word.  */
+         if (rel < relend
+             && rel->r_offset == offset - 8)
+           rel += 1;
        }
 
       if (need_edit)
@@ -4970,10 +4993,10 @@ ppc64_elf_edit_opd (bfd *obfd, struct bfd_link_info *info)
                  || !bfd_get_section_contents (ibfd, sec, loc, 0,
                                                sec->_raw_size))
                {
+               error_ret:
                  if (local_syms != NULL
                      && symtab_hdr->contents != (unsigned char *) local_syms)
                    free (local_syms);
-               error_free_rel:
                  if (elf_section_data (sec)->relocs != relstart)
                    free (relstart);
                  return FALSE;
@@ -4991,16 +5014,22 @@ ppc64_elf_edit_opd (bfd *obfd, struct bfd_link_info *info)
          offset = 0;
          for (rel = relstart; rel < relend; rel++)
            {
+             unsigned long r_symndx;
+             asection *sym_sec;
+             struct elf_link_hash_entry *h;
+             Elf_Internal_Sym *sym;
+
+             r_symndx = ELF64_R_SYM (rel->r_info);
+             if (!get_sym_h (&h, &sym, &sym_sec, NULL, &local_syms,
+                             r_symndx, ibfd))  
+               goto error_ret;
+
              if (rel->r_offset == offset)
                {
-                 unsigned long r_symndx;
-                 asection *sym_sec;
-                 struct elf_link_hash_entry *h;
-                 Elf_Internal_Sym *sym;
-
-                 r_symndx = ELF64_R_SYM (rel->r_info);
-                 get_sym_h (&h, &sym, &sym_sec, NULL, &local_syms,
-                            r_symndx, ibfd);
+                 struct ppc_link_hash_entry *fdh = NULL;
+                 if (h != NULL)
+                   fdh = get_fdh ((struct ppc_link_hash_entry *) h,
+                                  ppc_hash_table (info));
 
                  skip = (sym_sec->owner != ibfd
                          || sym_sec->output_section == bfd_abs_section_ptr);
@@ -5010,27 +5039,6 @@ ppc64_elf_edit_opd (bfd *obfd, struct bfd_link_info *info)
                        {
                          /* Arrange for the function descriptor sym
                             to be dropped.  */
-                         struct ppc_link_hash_entry *fdh;
-                         struct ppc_link_hash_entry *fh;
-
-                         fh = (struct ppc_link_hash_entry *) h;
-                         fdh = (struct ppc_link_hash_entry *) fh->oh;
-                         if (fdh == NULL)
-                           {
-                             const char *fd_name;
-                             struct ppc_link_hash_table *htab;
-
-                             fd_name = h->root.root.string + 1;
-                             htab = ppc_hash_table (info);
-                             fdh = (struct ppc_link_hash_entry *)
-                               elf_link_hash_lookup (&htab->elf, fd_name,
-                                                     FALSE, FALSE, FALSE);
-                             fdh->is_func_descriptor = 1;
-                             fdh->oh = &fh->elf;
-                             fh->is_func = 1;
-                             fh->oh = &fdh->elf;
-                           }
-
                          fdh->elf.root.u.def.value = 0;
                          fdh->elf.root.u.def.section = sym_sec;
                        }
@@ -5045,27 +5053,6 @@ ppc64_elf_edit_opd (bfd *obfd, struct bfd_link_info *info)
                             to this location in the opd section.
                             We've checked above that opd relocs are
                             ordered.  */
-                         struct ppc_link_hash_entry *fdh;
-                         struct ppc_link_hash_entry *fh;
-
-                         fh = (struct ppc_link_hash_entry *) h;
-                         fdh = (struct ppc_link_hash_entry *) fh->oh;
-                         if (fdh == NULL)
-                           {
-                             const char *fd_name;
-                             struct ppc_link_hash_table *htab;
-
-                             fd_name = h->root.root.string + 1;
-                             htab = ppc_hash_table (info);
-                             fdh = (struct ppc_link_hash_entry *)
-                               elf_link_hash_lookup (&htab->elf, fd_name,
-                                                     FALSE, FALSE, FALSE);
-                             fdh->is_func_descriptor = 1;
-                             fdh->oh = &fh->elf;
-                             fh->is_func = 1;
-                             fh->oh = &fdh->elf;
-                           }
-
                          fdh->elf.root.u.def.value = wptr - sec->contents;
                        }
                      else
@@ -5087,11 +5074,41 @@ ppc64_elf_edit_opd (bfd *obfd, struct bfd_link_info *info)
                  offset += 24;
                }
 
-             /* We need to adjust any reloc offsets to point to the
-                new opd entries.  While we're at it, we may as well
-                remove redundant relocs.  */
-             if (!skip)
+             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;
+                       }
+                   }
+               }
+             else
+               {
+                 /* We need to adjust any reloc offsets to point to the
+                    new opd entries.  While we're at it, we may as well
+                    remove redundant relocs.  */
                  rel->r_offset += wptr - rptr;
                  if (write_rel != rel)
                    memcpy (write_rel, rel, sizeof (*rel));
@@ -6089,8 +6106,6 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
   struct ppc_branch_hash_entry *br_entry;
   struct bfd_link_info *info;
   struct ppc_link_hash_table *htab;
-  asection *stub_sec;
-  bfd *stub_bfd;
   bfd_byte *loc;
   bfd_byte *p;
   unsigned int indx;
@@ -6103,29 +6118,10 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
   info = in_arg;
 
   htab = ppc_hash_table (info);
-  stub_sec = stub_entry->stub_sec;
 
   /* Make a note of the offset within the stubs for this entry.  */
-  stub_entry->stub_offset = stub_sec->_cooked_size;
-  loc = stub_sec->contents + stub_entry->stub_offset;
-
-  if (htab->emit_stub_syms)
-    {
-      struct elf_link_hash_entry *h;
-      h = elf_link_hash_lookup (&htab->elf, stub_entry->root.string,
-                               TRUE, FALSE, FALSE);
-      if (h == NULL)
-       return FALSE;
-      h->root.type = bfd_link_hash_defined;
-      h->root.u.def.section = stub_entry->stub_sec;
-      h->root.u.def.value = stub_entry->stub_offset;
-      h->elf_link_hash_flags = (ELF_LINK_HASH_REF_REGULAR
-                               | ELF_LINK_HASH_DEF_REGULAR
-                               | ELF_LINK_HASH_REF_REGULAR_NONWEAK
-                               | ELF_LINK_FORCED_LOCAL);
-    }
-
-  stub_bfd = stub_sec->owner;
+  stub_entry->stub_offset = stub_entry->stub_sec->_cooked_size;
+  loc = stub_entry->stub_sec->contents + stub_entry->stub_offset;
 
   htab->stub_count[stub_entry->stub_type - 1] += 1;
   switch (stub_entry->stub_type)
@@ -6139,8 +6135,8 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
 
       /* And this is where we are coming from.  */
       off -= (stub_entry->stub_offset
-             + stub_sec->output_offset
-             + stub_sec->output_section->vma);
+             + stub_entry->stub_sec->output_offset
+             + stub_entry->stub_sec->output_section->vma);
 
       if (stub_entry->stub_type != ppc_stub_long_branch_r2off)
        size = 4;
@@ -6150,16 +6146,16 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
 
          r2off = (htab->stub_group[stub_entry->target_section->id].toc_off
                   - htab->stub_group[stub_entry->id_sec->id].toc_off);
-         bfd_put_32 (stub_bfd, STD_R2_40R1, loc);
+         bfd_put_32 (htab->stub_bfd, STD_R2_40R1, loc);
          loc += 4;
-         bfd_put_32 (stub_bfd, ADDIS_R2_R2 | PPC_HA (r2off), loc);
+         bfd_put_32 (htab->stub_bfd, ADDIS_R2_R2 | PPC_HA (r2off), loc);
          loc += 4;
-         bfd_put_32 (stub_bfd, ADDI_R2_R2 | PPC_LO (r2off), loc);
+         bfd_put_32 (htab->stub_bfd, ADDI_R2_R2 | PPC_LO (r2off), loc);
          loc += 4;
          off -= 12;
          size = 16;
        }
-      bfd_put_32 (stub_bfd, B_DOT | (off & 0x3fffffc), loc);
+      bfd_put_32 (htab->stub_bfd, B_DOT | (off & 0x3fffffc), loc);
 
       BFD_ASSERT (off + (1 << 25) < (bfd_vma) (1 << 26));
       break;
@@ -6220,9 +6216,9 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
       indx = off;
       if (stub_entry->stub_type != ppc_stub_plt_branch_r2off)
        {
-         bfd_put_32 (stub_bfd, ADDIS_R12_R2 | PPC_HA (indx), loc);
+         bfd_put_32 (htab->stub_bfd, ADDIS_R12_R2 | PPC_HA (indx), loc);
          loc += 4;
-         bfd_put_32 (stub_bfd, LD_R11_0R12 | PPC_LO (indx), loc);
+         bfd_put_32 (htab->stub_bfd, LD_R11_0R12 | PPC_LO (indx), loc);
          size = 16;
        }
       else
@@ -6231,21 +6227,21 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
 
          r2off = (htab->stub_group[stub_entry->target_section->id].toc_off
                   - htab->stub_group[stub_entry->id_sec->id].toc_off);
-         bfd_put_32 (stub_bfd, STD_R2_40R1, loc);
+         bfd_put_32 (htab->stub_bfd, STD_R2_40R1, loc);
          loc += 4;
-         bfd_put_32 (stub_bfd, ADDIS_R12_R2 | PPC_HA (indx), loc);
+         bfd_put_32 (htab->stub_bfd, ADDIS_R12_R2 | PPC_HA (indx), loc);
          loc += 4;
-         bfd_put_32 (stub_bfd, LD_R11_0R12 | PPC_LO (indx), loc);
+         bfd_put_32 (htab->stub_bfd, LD_R11_0R12 | PPC_LO (indx), loc);
          loc += 4;
-         bfd_put_32 (stub_bfd, ADDIS_R2_R2 | PPC_HA (r2off), loc);
+         bfd_put_32 (htab->stub_bfd, ADDIS_R2_R2 | PPC_HA (r2off), loc);
          loc += 4;
-         bfd_put_32 (stub_bfd, ADDI_R2_R2 | PPC_LO (r2off), loc);
+         bfd_put_32 (htab->stub_bfd, ADDI_R2_R2 | PPC_LO (r2off), loc);
          size = 28;
        }
       loc += 4;
-      bfd_put_32 (stub_bfd, MTCTR_R11, loc);
+      bfd_put_32 (htab->stub_bfd, MTCTR_R11, loc);
       loc += 4;
-      bfd_put_32 (stub_bfd, BCTR, loc);
+      bfd_put_32 (htab->stub_bfd, BCTR, loc);
       break;
 
     case ppc_stub_plt_call:
@@ -6292,7 +6288,7 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
          return FALSE;
        }
 
-      p = build_plt_stub (stub_bfd, loc, off);
+      p = build_plt_stub (htab->stub_bfd, loc, off);
       size = p - loc;
       break;
 
@@ -6301,7 +6297,31 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
       return FALSE;
     }
 
-  stub_sec->_cooked_size += size;
+  stub_entry->stub_sec->_cooked_size += size;
+
+  if (htab->emit_stub_syms
+      && !(stub_entry->stub_type == ppc_stub_plt_call
+          && stub_entry->h->oh->root.type == bfd_link_hash_defined
+          && stub_entry->h->oh->root.u.def.section == stub_entry->stub_sec
+          && stub_entry->h->oh->root.u.def.value == stub_entry->stub_offset))
+    {
+      struct elf_link_hash_entry *h;
+      h = elf_link_hash_lookup (&htab->elf, stub_entry->root.string,
+                               TRUE, FALSE, FALSE);
+      if (h == NULL)
+       return FALSE;
+      if (h->root.type == bfd_link_hash_new)
+       {
+         h->root.type = bfd_link_hash_defined;
+         h->root.u.def.section = stub_entry->stub_sec;
+         h->root.u.def.value = stub_entry->stub_offset;
+         h->elf_link_hash_flags = (ELF_LINK_HASH_REF_REGULAR
+                                   | ELF_LINK_HASH_DEF_REGULAR
+                                   | ELF_LINK_HASH_REF_REGULAR_NONWEAK
+                                   | ELF_LINK_FORCED_LOCAL);
+       }
+    }
+
   return TRUE;
 }
 
@@ -6587,7 +6607,8 @@ ppc64_elf_next_input_section (struct bfd_link_info *info, asection *isec)
 
   /* If a code section has a function that uses the TOC then we need
      to use the right TOC (obviously).  Also, make sure that .opd gets
-     the correct TOC value.  */
+     the correct TOC value for R_PPC64_TOC relocs that don't have or
+     can't find their function symbol (shouldn't ever happen now).  */
   if (isec->has_gp_reloc || (isec->flags & SEC_CODE) == 0)
     {
       if (elf_gp (isec->owner) != 0)
@@ -7087,6 +7108,23 @@ ppc64_elf_build_stubs (bfd_boolean emit_stub_syms,
          return FALSE;
        }
 
+      if (htab->emit_stub_syms)
+       {
+         struct elf_link_hash_entry *h;
+         h = elf_link_hash_lookup (&htab->elf, "__glink", TRUE, FALSE, FALSE);
+         if (h == NULL)
+           return FALSE;
+         if (h->root.type == bfd_link_hash_new)
+           {
+             h->root.type = bfd_link_hash_defined;
+             h->root.u.def.section = htab->glink;
+             h->root.u.def.value = 0;
+             h->elf_link_hash_flags = (ELF_LINK_HASH_REF_REGULAR
+                                       | ELF_LINK_HASH_DEF_REGULAR
+                                       | ELF_LINK_HASH_REF_REGULAR_NONWEAK
+                                       | ELF_LINK_FORCED_LOCAL);
+           }
+       }
       p = htab->glink->contents;
       bfd_put_32 (htab->glink->owner, MFCTR_R12, p);
       p += 4;
@@ -7282,13 +7320,23 @@ ppc64_elf_relocate_section (bfd *output_bfd,
       bfd_vma relocation;
       bfd_boolean unresolved_reloc;
       bfd_boolean warned;
-      long insn, mask;
+      unsigned long insn, mask;
       struct ppc_stub_hash_entry *stub_entry;
       bfd_vma max_br_offset;
       bfd_vma from;
 
       r_type = ELF64_R_TYPE (rel->r_info);
       r_symndx = ELF64_R_SYM (rel->r_info);
+
+      /* For old style R_PPC64_TOC relocs with a zero symbol, use the
+        symbol of the previous ADDR64 reloc.  The symbol gives us the
+        proper TOC base to use.  */
+      if (rel->r_info == ELF64_R_INFO (0, R_PPC64_TOC)
+         && rel != relocs
+         && ELF64_R_TYPE (rel[-1].r_info) == R_PPC64_ADDR64
+         && is_opd)
+       r_symndx = ELF64_R_SYM (rel[-1].r_info);
+
       sym = NULL;
       sec = NULL;
       h = NULL;
@@ -7314,44 +7362,11 @@ ppc64_elf_relocate_section (bfd *output_bfd,
        }
       else
        {
-         /* It's a global symbol.  */
-         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;
+         RELOC_FOR_GLOBAL_SYMBOL (h, sym_hashes, r_symndx,
+                                  symtab_hdr, relocation, sec,
+                                  unresolved_reloc, info,
+                                  warned);
          sym_name = h->root.root.string;
-         relocation = 0;
-         if (h->root.type == bfd_link_hash_defined
-             || h->root.type == bfd_link_hash_defweak)
-           {
-             sec = h->root.u.def.section;
-             if (sec->output_section == NULL)
-               /* Set a flag that will be cleared later if we find a
-                  relocation value for this symbol.  output_section
-                  is typically NULL for symbols satisfied by a shared
-                  library.  */
-               unresolved_reloc = TRUE;
-             else
-               relocation = (h->root.u.def.value
-                             + sec->output_section->vma
-                             + sec->output_offset);
-           }
-         else if (h->root.type == bfd_link_hash_undefweak)
-           ;
-         else if (!info->executable
-                  && !info->no_undefined
-                  && ELF_ST_VISIBILITY (h->other) == STV_DEFAULT)
-           ;
-         else
-           {
-             if (! ((*info->callbacks->undefined_symbol)
-                    (info, h->root.root.string, input_bfd, input_section,
-                     rel->r_offset, (!info->shared
-                                     || info->no_undefined
-                                     || ELF_ST_VISIBILITY (h->other)))))
-               return FALSE;
-             warned = TRUE;
-           }
        }
 
       /* TLS optimizations.  Replace instruction sequences and relocs
@@ -7437,7 +7452,6 @@ ppc64_elf_relocate_section (bfd *output_bfd,
          if (tls_mask != 0
              && (tls_mask & TLS_TPREL) == 0)
            {
-             bfd_vma insn;
            toctprel:
              insn = bfd_get_32 (output_bfd, contents + rel->r_offset - 2);
              insn &= 31 << 21;
@@ -7463,7 +7477,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
          if (tls_mask != 0
              && (tls_mask & TLS_TPREL) == 0)
            {
-             bfd_vma insn, rtra;
+             bfd_vma rtra;
              insn = bfd_get_32 (output_bfd, contents + rel->r_offset);
              if ((insn & ((0x3f << 26) | (31 << 11)))
                  == ((31 << 26) | (13 << 11)))
@@ -7751,6 +7765,13 @@ ppc64_elf_relocate_section (bfd *output_bfd,
                      if ((insn & 1) == 0)
                        can_plt_call = 1;
                    }
+                 else if (h != NULL
+                          && strcmp (h->root.root.string,
+                                     ".__libc_start_main") == 0)
+                   {
+                     /* Allow crt1 branch to go via a toc adjusting stub.  */
+                     can_plt_call = 1;
+                   }
                  else
                    {
                      if (strcmp (input_section->output_section->name,
This page took 0.036181 seconds and 4 git commands to generate.