* config.bfd: Mark arm-*-oabi and thumb-*-oabi as obsolete.
[deliverable/binutils-gdb.git] / bfd / elf64-ppc.c
index 0738c45794fa1a4e615dd2d4597e400a99627f1b..c21d0272d86002fd58c4eea56d277de85ce31fc7 100644 (file)
@@ -174,9 +174,17 @@ static bfd_vma opd_entry_value
 #define LIS_R0_0       0x3c000000      /* lis   %r0,0          */
 #define ORI_R0_R0_0    0x60000000      /* ori   %r0,%r0,0      */
 
-/* Instructions to save and restore floating point regs.  */
+/* Instructions used by the save and restore reg functions.  */
+#define STD_R0_0R1     0xf8010000      /* std   %r0,0(%r1)     */
+#define STD_R0_0R12    0xf80c0000      /* std   %r0,0(%r12)    */
+#define LD_R0_0R1      0xe8010000      /* ld    %r0,0(%r1)     */
+#define LD_R0_0R12     0xe80c0000      /* ld    %r0,0(%r12)    */
 #define STFD_FR0_0R1   0xd8010000      /* stfd  %fr0,0(%r1)    */
 #define LFD_FR0_0R1    0xc8010000      /* lfd   %fr0,0(%r1)    */
+#define LI_R12_0       0x39800000      /* li    %r12,0         */
+#define STVX_VR0_R12_R0        0x7c0c01ce      /* stvx  %v0,%r12,%r0   */
+#define LVX_VR0_R12_R0 0x7c0c00ce      /* lvx   %v0,%r12,%r0   */
+#define MTLR_R0                0x7c0803a6      /* mtlr  %r0            */
 #define BLR            0x4e800020      /* blr                  */
 
 /* Since .opd is an array of descriptors and each entry will end up
@@ -2145,7 +2153,8 @@ ppc64_elf_branch_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol,
     return bfd_elf_generic_reloc (abfd, reloc_entry, symbol, data,
                                  input_section, output_bfd, error_message);
 
-  if (strcmp (symbol->section->name, ".opd") == 0)
+  if (strcmp (symbol->section->name, ".opd") == 0
+      && (symbol->section->owner->flags & DYNAMIC) == 0)
     {
       bfd_vma dest = opd_entry_value (symbol->section,
                                      symbol->value + reloc_entry->addend,
@@ -2391,6 +2400,17 @@ ppc64_elf_mkobject (bfd *abfd)
   return TRUE;
 }
 
+/* Return 1 if target is one of ours.  */
+
+static bfd_boolean
+is_ppc64_elf_target (const struct bfd_target *targ)
+{
+  extern const bfd_target bfd_elf64_powerpc_vec;
+  extern const bfd_target bfd_elf64_powerpcle_vec;
+
+  return targ == &bfd_elf64_powerpc_vec || targ == &bfd_elf64_powerpcle_vec;
+}
+
 /* Fix bad default arch selected for a 64 bit input bfd when the
    default is 32 bit.  */
 
@@ -2541,7 +2561,7 @@ get_opd_info (asection * sec)
 static asection *synthetic_opd;
 static bfd_boolean synthetic_relocatable;
 
-/* Helper routine for ppc64_elf_get_synthetic_symtab.  */
+/* qsort comparison function for ppc64_elf_get_synthetic_symtab.  */
 
 static int
 compare_symbols (const void *ap, const void *bp)
@@ -2549,16 +2569,19 @@ compare_symbols (const void *ap, const void *bp)
   const asymbol *a = * (const asymbol **) ap;
   const asymbol *b = * (const asymbol **) bp;
 
-  if ((a->flags & BSF_SECTION_SYM) == 0 && (b->flags & BSF_SECTION_SYM))
+  /* Section symbols first.  */
+  if ((a->flags & BSF_SECTION_SYM) && !(b->flags & BSF_SECTION_SYM))
     return -1;
-  if ((a->flags & BSF_SECTION_SYM) && (b->flags & BSF_SECTION_SYM) == 0)
+  if (!(a->flags & BSF_SECTION_SYM) && (b->flags & BSF_SECTION_SYM))
     return 1;
 
+  /* then .opd symbols.  */
   if (a->section == synthetic_opd && b->section != synthetic_opd)
     return -1;
   if (a->section != synthetic_opd && b->section == synthetic_opd)
     return 1;
 
+  /* then other code symbols.  */
   if ((a->section->flags & (SEC_CODE | SEC_ALLOC | SEC_THREAD_LOCAL))
       == (SEC_CODE | SEC_ALLOC)
       && (b->section->flags & (SEC_CODE | SEC_ALLOC | SEC_THREAD_LOCAL))
@@ -2589,38 +2612,63 @@ compare_symbols (const void *ap, const void *bp)
   return 0;
 }
 
-/* Helper routine for ppc64_elf_get_synthetic_symtab.  */
+/* Search SYMS for a symbol of the given VALUE.  */
 
-static int
-compare_relocs (const void *ap, const void *bp)
+static asymbol *
+sym_exists_at (asymbol **syms, long lo, long hi, int id, bfd_vma value)
 {
-  const arelent *a = * (const arelent **) ap;
-  const arelent *b = * (const arelent **) bp;
-
-  if (a->address < b->address)
-    return -1;
+  long mid;
 
-  if (a->address > b->address)
-    return 1;
-
-  return 0;
+  if (id == -1)
+    {
+      while (lo < hi)
+       {
+         mid = (lo + hi) >> 1;
+         if (syms[mid]->value + syms[mid]->section->vma < value)
+           lo = mid + 1;
+         else if (syms[mid]->value + syms[mid]->section->vma > value)
+           hi = mid;
+         else
+           return syms[mid];
+       }
+    }
+  else
+    {
+      while (lo < hi)
+       {
+         mid = (lo + hi) >> 1;
+         if (syms[mid]->section->id < id)
+           lo = mid + 1;
+         else if (syms[mid]->section->id > id)
+           hi = mid;
+         else if (syms[mid]->value < value)
+           lo = mid + 1;
+         else if (syms[mid]->value > value)
+           hi = mid;
+         else
+           return syms[mid];
+       }
+    }
+  return NULL;
 }
 
-/* Create synthetic symbols.  */
+/* Create synthetic symbols, effectively restoring "dot-symbol" function
+   entry syms.  */
 
 static long
-ppc64_elf_get_synthetic_symtab (bfd *abfd, asymbol **relsyms, asymbol **ret)
+ppc64_elf_get_synthetic_symtab (bfd *abfd,
+                               long static_count, asymbol **static_syms,
+                               long dyn_count, asymbol **dyn_syms,
+                               asymbol **ret)
 {
   asymbol *s;
-  bfd_boolean (*slurp_relocs) (bfd *, asection *, asymbol **, bfd_boolean);
-  arelent **relocs, **r;
-  long count, i;
-  size_t size;
+  long i;
+  long count;
   char *names;
-  asymbol **syms = NULL;
-  long symcount = 0, opdsymcount, relcount;
-  asection *relopd, *opd;
+  long symcount, codesecsym, codesecsymend, secsymend, opdsymend;
+  asection *opd;
   bfd_boolean relocatable = (abfd->flags & (EXEC_P | DYNAMIC)) == 0;
+  asymbol **syms;
 
   *ret = NULL;
 
@@ -2628,297 +2676,257 @@ ppc64_elf_get_synthetic_symtab (bfd *abfd, asymbol **relsyms, asymbol **ret)
   if (opd == NULL)
     return 0;
 
-  if ((bfd_get_file_flags (abfd) & HAS_SYMS))
-    {
-      long storage;
-      storage = bfd_get_symtab_upper_bound (abfd);
-      if (storage < 0)
-       return 0;
-
-      if (storage)
-       {
-         syms = bfd_malloc (storage);
-         if (syms == NULL)
-           return 0;
-       }
-
-      symcount = bfd_canonicalize_symtab (abfd, syms);
-      if (symcount < 0)
-       {
-         free (syms);
-         return 0;
-       }
-
-      if (symcount == 0)
-       {
-         free (syms);
-         syms = NULL;
-       }
-    }
-
+  symcount = static_count;
+  if (!relocatable)
+    symcount += dyn_count;
   if (symcount == 0)
-    {
-      long storage;
-
-      storage = bfd_get_dynamic_symtab_upper_bound (abfd);
-      if (storage < 0)
-       return 0;
+    return 0;
 
-      if (storage)
-       {
-         syms = bfd_malloc (storage);
-         if (syms == NULL)
-           return 0;
-       }
+  syms = bfd_malloc ((symcount + 1) * sizeof (*syms));
+  if (syms == NULL)
+    return 0;
 
-      symcount = bfd_canonicalize_dynamic_symtab (abfd, syms);
-      if (symcount < 0)
-       {
-         free (syms);
-         return 0;
-       }
+  if (!relocatable && static_count != 0 && dyn_count != 0)
+    {
+      /* Use both symbol tables.  */
+      memcpy (syms, static_syms, static_count * sizeof (*syms));
+      memcpy (syms + static_count, dyn_syms, (dyn_count + 1) * sizeof (*syms));
     }
+  else if (!relocatable && static_count == 0)
+    memcpy (syms, dyn_syms, (symcount + 1) * sizeof (*syms));
+  else
+    memcpy (syms, static_syms, (symcount + 1) * sizeof (*syms));
 
   synthetic_opd = opd;
   synthetic_relocatable = relocatable;
-  qsort (syms, symcount, sizeof (asymbol *), compare_symbols);
+  qsort (syms, symcount, sizeof (*syms), compare_symbols);
 
-  opdsymcount = symcount;
-  for (i = 0; i < symcount; ++i)
+  if (!relocatable && symcount > 1)
     {
-      if (syms[i]->flags & BSF_SECTION_SYM)
-       {
-         if (opdsymcount == symcount)
-           opdsymcount = i;
-         symcount = i;
-         break;
-       }
+      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.  */ 
+      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)
+         syms[j++] = syms[i];
+      symcount = j;
+    }
 
-      if (syms[i]->section == opd)
-       continue;
+  i = 0;
+  if (syms[i]->section == opd)
+    ++i;
+  codesecsym = i;
 
-      if (opdsymcount == symcount)
-       opdsymcount = i;
+  for (; i < symcount; ++i)
+    if (((syms[i]->section->flags & (SEC_CODE | SEC_ALLOC | SEC_THREAD_LOCAL))
+        != (SEC_CODE | SEC_ALLOC))
+       || (syms[i]->flags & BSF_SECTION_SYM) == 0)
+      break;
+  codesecsymend = i;
 
-      if ((syms[i]->section->flags & (SEC_CODE | SEC_ALLOC | SEC_THREAD_LOCAL))
-         != (SEC_CODE | SEC_ALLOC))
-       {
-         symcount = i;
-         break;
-       }
-    }
+  for (; i < symcount; ++i)
+    if ((syms[i]->flags & BSF_SECTION_SYM) == 0)
+      break;
+  secsymend = i;
 
-  if (opdsymcount == 0)
-    {
-      free (syms);
-      return 0;
-    }
+  for (; i < symcount; ++i)
+    if (syms[i]->section != opd)
+      break;
+  opdsymend = i;
 
-  slurp_relocs = get_elf_backend_data (abfd)->s->slurp_reloc_table;
-  if (! relocatable)
-    {
-      relopd = bfd_get_section_by_name (abfd, ".rela.opd");
-      if (relopd == NULL)
-       {
-         relopd = bfd_get_section_by_name (abfd, ".rela.dyn");
-         if (relopd == NULL)
-           {
-             free (syms);
-             return 0;
-           }
-       }
-      relcount = relopd->size / 24;
+  for (; i < symcount; ++i)
+    if ((syms[i]->section->flags & (SEC_CODE | SEC_ALLOC | SEC_THREAD_LOCAL))
+       != (SEC_CODE | SEC_ALLOC))
+      break;
+  symcount = i;
 
-      if (! relcount
-         || ! (*slurp_relocs) (abfd, relopd, relsyms, TRUE))
-       {
-         free (syms);
-         return 0;
-       }
-    }
-  else
+  count = 0;
+  if (opdsymend == secsymend)
+    goto done;
+
+  if (relocatable)
     {
-      relopd = opd;
+      bfd_boolean (*slurp_relocs) (bfd *, asection *, asymbol **, bfd_boolean);
+      arelent *r;
+      size_t size;
+      long relcount;
+
+      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, relopd, relsyms, FALSE))
+         || ! (*slurp_relocs) (abfd, opd, static_syms, FALSE))
+       goto done;
+
+      size = 0;
+      for (i = secsymend, r = opd->relocation; i < opdsymend; ++i)
        {
-         free (syms);
-         return 0;
-       }
-    }
+         asymbol *sym;
 
-  relocs = bfd_malloc (relcount * sizeof (arelent **));
-  if (relocs == NULL)
-    {
-      free (syms);
-      return 0;
-    }
+         while (r < opd->relocation + relcount
+                && r->address < syms[i]->value + opd->vma)
+           ++r;
 
-  for (i = 0; i < relcount; ++i)
-    relocs[i] = &relopd->relocation[i];
+         if (r == opd->relocation + relcount)
+           break;
 
-  qsort (relocs, relcount, sizeof (*relocs), compare_relocs);
+         if (r->address != syms[i]->value + opd->vma)
+           continue;
 
-  size = 0;
-  count = 0;
-  for (i = 0, r = relocs; i < opdsymcount; ++i)
-    {
-      long lo, hi, mid;
-      asymbol *sym;
+         if (r->howto->type != R_PPC64_ADDR64)
+           continue;
+
+         sym = *r->sym_ptr_ptr;
+         if (!sym_exists_at (syms, opdsymend, symcount,
+                             sym->section->id, sym->value + r->addend))
+           {
+             ++count;
+             size += sizeof (asymbol);
+             size += strlen (syms[i]->name) + 2;
+           }
+       }
 
-      while (r < relocs + relcount
-            && (*r)->address < syms[i]->value + opd->vma)
-       ++r;
+      s = *ret = bfd_malloc (size);
+      if (s == NULL)
+       {
+         count = 0;
+         goto done;
+       }
 
-      if (r == relocs + relcount)
-       continue;
+      names = (char *) (s + count);
 
-      if ((*r)->address != syms[i]->value + opd->vma)
-       continue;
+      for (i = secsymend, r = opd->relocation; i < opdsymend; ++i)
+       {
+         asymbol *sym;
 
-      if ((*r)->howto->type != (relocatable
-                               ? R_PPC64_ADDR64 : R_PPC64_RELATIVE))
-       continue;
+         while (r < opd->relocation + relcount
+                && r->address < syms[i]->value + opd->vma)
+           ++r;
 
-      lo = opdsymcount;
-      hi = symcount;
-      sym = *((*r)->sym_ptr_ptr);
-      if (relocatable)
-       while (lo < hi)
-         {
-           mid = (lo + hi) >> 1;
-           if (syms[mid]->section->id < sym->section->id)
-             lo = mid + 1;
-           else if (syms[mid]->section->id > sym->section->id)
-             hi = mid;
-           else if (syms[mid]->value < sym->value + (*r)->addend)
-             lo = mid + 1;
-           else if (syms[mid]->value > sym->value + (*r)->addend)
-             hi = mid;
-           else
-             break;
-         }
-      else
-       while (lo < hi)
-         {
-           mid = (lo + hi) >> 1;
-           if (syms[mid]->value + syms[mid]->section->vma < (*r)->addend)
-             lo = mid + 1;
-           else if (syms[mid]->value + syms[mid]->section->vma > (*r)->addend)
-             hi = mid;
-           else
-             break;
-         }
+         if (r == opd->relocation + relcount)
+           break;
 
-      if (lo >= hi)
-       {
-         ++count;
-         size += sizeof (asymbol);
-         size += strlen (syms[i]->name) + 1;
-       }
-    }
+         if (r->address != syms[i]->value + opd->vma)
+           continue;
 
-  s = *ret = bfd_malloc (size);
-  if (s == NULL)
-    {
-      free (syms);
-      free (relocs);
-      return 0;
-    }
+         if (r->howto->type != R_PPC64_ADDR64)
+           continue;
 
-  names = (char *) (s + count);
+         sym = *r->sym_ptr_ptr;
+         if (!sym_exists_at (syms, opdsymend, symcount,
+                             sym->section->id, sym->value + r->addend))
+           {
+             size_t len;
 
-  for (i = 0, r = relocs; i < opdsymcount; ++i)
+             *s = *syms[i];
+             s->section = sym->section;
+             s->value = sym->value + r->addend;
+             s->name = names;
+             *names++ = '.';
+             len = strlen (syms[i]->name);
+             memcpy (names, syms[i]->name, len + 1);
+             names += len + 1;
+             s++;
+           }
+       }
+    }
+  else
     {
-      long lo, hi, mid;
-      asymbol *sym;
+      bfd_byte *contents;
+      size_t size;
 
-      while (r < relocs + relcount
-            && (*r)->address < syms[i]->value + opd->vma)
-       ++r;
+      if (!bfd_malloc_and_get_section (abfd, opd, &contents))
+       {
+         if (contents)
+           {
+           free_contents_and_exit:
+             free (contents);
+           }
+         goto done;
+       }
 
-      if (r == relocs + relcount)
-       continue;
+      size = 0;
+      for (i = secsymend; i < opdsymend; ++i)
+       {
+         bfd_vma ent;
 
-      if ((*r)->address != syms[i]->value + opd->vma)
-       continue;
+         ent = bfd_get_64 (abfd, contents + syms[i]->value);
+         if (!sym_exists_at (syms, opdsymend, symcount, -1, ent))
+           {
+             ++count;
+             size += sizeof (asymbol);
+             size += strlen (syms[i]->name) + 2;
+           }
+       }
 
-      if ((*r)->howto->type != (relocatable
-                               ? R_PPC64_ADDR64 : R_PPC64_RELATIVE))
-       continue;
+      s = *ret = bfd_malloc (size);
+      if (s == NULL)
+       {
+         count = 0;
+         goto free_contents_and_exit;
+       }
 
-      lo = opdsymcount;
-      hi = symcount;
-      sym = *((*r)->sym_ptr_ptr);
-      if (relocatable)
-       while (lo < hi)
-         {
-           mid = (lo + hi) >> 1;
-           if (syms[mid]->section->id < sym->section->id)
-             lo = mid + 1;
-           else if (syms[mid]->section->id > sym->section->id)
-             hi = mid;
-           else if (syms[mid]->value < sym->value + (*r)->addend)
-             lo = mid + 1;
-           else if (syms[mid]->value > sym->value + (*r)->addend)
-             hi = mid;
-           else
-             break;
-         }
-      else
-       while (lo < hi)
-         {
-           mid = (lo + hi) >> 1;
-           if (syms[mid]->value + syms[mid]->section->vma < (*r)->addend)
-             lo = mid + 1;
-           else if (syms[mid]->value + syms[mid]->section->vma > (*r)->addend)
-             hi = mid;
-           else
-             break;
-         }
+      names = (char *) (s + count);
 
-      if (lo >= hi)
+      for (i = secsymend; i < opdsymend; ++i)
        {
-         size_t len;
+         bfd_vma ent;
 
-         *s = *syms[i];
-         
-         if (! relocatable)
+         ent = bfd_get_64 (abfd, contents + syms[i]->value);
+         if (!sym_exists_at (syms, opdsymend, symcount, -1, ent))
            {
-             asection *sec;
+             long lo, hi;
+             size_t len;
+             asection *sec = abfd->sections;
+
+             *s = *syms[i];
+             lo = codesecsym;
+             hi = codesecsymend;
+             while (lo < hi)
+               {
+                 long mid = (lo + hi) >> 1;
+                 if (syms[mid]->section->vma < ent)
+                   lo = mid + 1;
+                 else if (syms[mid]->section->vma > ent)
+                   hi = mid;
+                 else
+                   {
+                     sec = syms[mid]->section;
+                     break;
+                   }
+               }
 
-             s->section = &bfd_abs_section;
-             for (sec = abfd->sections; sec; sec = sec->next)
-               if ((sec->flags & (SEC_ALLOC | SEC_CODE))
-                   == (SEC_ALLOC | SEC_CODE)
-                   && (*r)->addend >= sec->vma
-                   && (*r)->addend < sec->vma + sec->size)
-                 {
-                   s->section = sec;
+             if (lo >= hi && lo > codesecsym)
+               sec = syms[lo - 1]->section;
+
+             for (; sec != NULL; sec = sec->next)
+               {
+                 if (sec->vma > ent)
                    break;
-                 }
-             s->value = (*r)->addend - sec->vma;
-           }
-         else
-           {
-             s->section = sym->section;
-             s->value = sym->value + (*r)->addend;
+                 if ((sec->flags & SEC_ALLOC) == 0
+                     || (sec->flags & SEC_LOAD) == 0)
+                   break;
+                 if ((sec->flags & SEC_CODE) != 0)
+                   s->section = sec;
+               }
+             s->value = ent - s->section->vma;
+             s->name = names;
+             *names++ = '.';
+             len = strlen (syms[i]->name);
+             memcpy (names, syms[i]->name, len + 1);
+             names += len + 1;
+             s++;
            }
-         s->name = names;
-         len = strlen (syms[i]->name);
-         memcpy (names, syms[i]->name, len + 1);
-         names += len + 1;
-         s++;
        }
+      free (contents);
     }
 
+ done:
   free (syms);
-  free (relocs);
   return count;
 }
-
 \f
 /* The following functions are specific to the ELF linker, while
    functions above are used generally.  Those named ppc64_elf_* are
@@ -3284,6 +3292,9 @@ struct ppc_link_hash_table
   /* Statistics.  */
   unsigned long stub_count[ppc_stub_plt_call];
 
+  /* Number of stubs against global syms.  */
+  unsigned long stub_globals;
+
   /* Set if we should emit symbols for stubs.  */
   unsigned int emit_stub_syms:1;
 
@@ -3527,6 +3538,8 @@ ppc_stub_name (const asection *input_section,
                   (int) rel->r_addend & 0xffffffff);
        }
     }
+  if (stub_name[len - 2] == '+' && stub_name[len - 1] == '0')
+    stub_name[len - 2] = 0;
   return stub_name;
 }
 
@@ -3665,7 +3678,7 @@ create_linkage_sections (bfd *dynobj, struct bfd_link_info *info)
       || ! bfd_set_section_alignment (dynobj, htab->brlt, 3))
     return FALSE;
 
-  if (info->shared)
+  if (info->shared || info->emitrelocations)
     {
       flags = (SEC_ALLOC | SEC_LOAD | SEC_READONLY
               | SEC_HAS_CONTENTS | SEC_IN_MEMORY | SEC_LINKER_CREATED);
@@ -3753,7 +3766,6 @@ ppc64_elf_copy_indirect_symbol
    struct elf_link_hash_entry *ind)
 {
   struct ppc_link_hash_entry *edir, *eind;
-  flagword mask;
 
   edir = (struct ppc_link_hash_entry *) dir;
   eind = (struct ppc_link_hash_entry *) ind;
@@ -3797,18 +3809,18 @@ ppc64_elf_copy_indirect_symbol
   edir->is_func_descriptor |= eind->is_func_descriptor;
   edir->tls_mask |= eind->tls_mask;
 
-  mask = (ELF_LINK_HASH_REF_DYNAMIC | ELF_LINK_HASH_REF_REGULAR
-         | ELF_LINK_HASH_REF_REGULAR_NONWEAK | ELF_LINK_NON_GOT_REF
-         | ELF_LINK_HASH_NEEDS_PLT);
   /* If called to transfer flags for a weakdef during processing
-     of elf_adjust_dynamic_symbol, don't copy ELF_LINK_NON_GOT_REF.
+     of elf_adjust_dynamic_symbol, don't copy NON_GOT_REF.
      We clear it ourselves for ELIMINATE_COPY_RELOCS.  */
-  if (ELIMINATE_COPY_RELOCS
-      && eind->elf.root.type != bfd_link_hash_indirect
-      && (edir->elf.elf_link_hash_flags & ELF_LINK_HASH_DYNAMIC_ADJUSTED) != 0)
-    mask &= ~ELF_LINK_NON_GOT_REF;
+  if (!(ELIMINATE_COPY_RELOCS
+       && eind->elf.root.type != bfd_link_hash_indirect
+       && edir->elf.dynamic_adjusted))
+    edir->elf.non_got_ref |= eind->elf.non_got_ref;
 
-  edir->elf.elf_link_hash_flags |= eind->elf.elf_link_hash_flags & mask;
+  edir->elf.ref_dynamic |= eind->elf.ref_dynamic;
+  edir->elf.ref_regular |= eind->elf.ref_regular;
+  edir->elf.ref_regular_nonweak |= eind->elf.ref_regular_nonweak;
+  edir->elf.needs_plt |= eind->elf.needs_plt;
 
   /* If we were called to copy over info for a weak sym, that's all.  */
   if (eind->elf.root.type != bfd_link_hash_indirect)
@@ -4030,12 +4042,9 @@ ppc64_elf_check_directives (bfd *abfd ATTRIBUTE_UNUSED,
                            struct bfd_link_info *info)
 {
   struct ppc_link_hash_table *htab;
-  extern const bfd_target bfd_elf64_powerpc_vec;
-  extern const bfd_target bfd_elf64_powerpcle_vec;
 
   htab = ppc_hash_table (info);
-  if (htab->elf.root.creator != &bfd_elf64_powerpc_vec
-      && htab->elf.root.creator != &bfd_elf64_powerpcle_vec)
+  if (!is_ppc64_elf_target (htab->elf.root.creator))
     return TRUE;
 
   elf_link_hash_traverse (&htab->elf, add_symbol_adjust, info);
@@ -4054,22 +4063,22 @@ ppc64_elf_check_directives (bfd *abfd ATTRIBUTE_UNUSED,
          if (h->type != bfd_link_hash_undefined
              && h->type != bfd_link_hash_common)
            {
-             *pun = h->und_next;
-             h->und_next = NULL;
+             *pun = h->u.undef.next;
+             h->u.undef.next = NULL;
              if (h == htab->elf.root.undefs_tail)
                {
                  if (pun == &htab->elf.root.undefs)
                    htab->elf.root.undefs_tail = NULL;
                  else
-                   /* pun points at an und_next field.  Go back to
+                   /* pun points at an u.undef.next field.  Go back to
                       the start of the link_hash_entry.  */
                    htab->elf.root.undefs_tail = (struct bfd_link_hash_entry *)
-                     ((char *) pun - ((char *) &h->und_next - (char *) h));
+                     ((char *) pun - ((char *) &h->u.undef.next - (char *) h));
                  break;
                }
            }
          else
-           pun = &h->und_next;
+           pun = &h->u.undef.next;
        }
 
       htab->twiddled_syms = 0;
@@ -4145,7 +4154,7 @@ update_plt_info (bfd *abfd, struct ppc_link_hash_entry *eh, bfd_vma addend)
       eh->elf.plt.plist = ent;
     }
   ent->plt.refcount += 1;
-  eh->elf.elf_link_hash_flags |= ELF_LINK_HASH_NEEDS_PLT;
+  eh->elf.needs_plt = 1;
   eh->is_func = 1;
   return TRUE;
 }
@@ -4541,7 +4550,7 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
        case R_PPC64_TOC:
          if (h != NULL && !info->shared)
            /* We may need a copy reloc.  */
-           h->elf_link_hash_flags |= ELF_LINK_NON_GOT_REF;
+           h->non_got_ref = 1;
 
          /* Don't propagate .opd relocs.  */
          if (NO_OPD_RELOCS && opd_sym_map != NULL)
@@ -4574,14 +4583,12 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
                   || (h != NULL
                       && (! info->symbolic
                           || h->root.type == bfd_link_hash_defweak
-                          || (h->elf_link_hash_flags
-                              & ELF_LINK_HASH_DEF_REGULAR) == 0))))
+                          || !h->def_regular))))
              || (ELIMINATE_COPY_RELOCS
                  && !info->shared
                  && h != NULL
                  && (h->root.type == bfd_link_hash_defweak
-                     || (h->elf_link_hash_flags
-                         & ELF_LINK_HASH_DEF_REGULAR) == 0)))
+                     || !h->def_regular)))
            {
              struct ppc_dyn_relocs *p;
              struct ppc_dyn_relocs **head;
@@ -4691,6 +4698,32 @@ opd_entry_value (asection *opd_sec,
   bfd *opd_bfd = opd_sec->owner;
   Elf_Internal_Rela *lo, *hi, *look;
 
+  /* No relocs implies we are linking a --just-symbols object.  */
+  if (opd_sec->reloc_count == 0)
+    {
+      bfd_vma val;
+
+      if (!bfd_get_section_contents (opd_bfd, opd_sec, &val, offset, 8))
+       return (bfd_vma) -1;
+      
+      if (code_sec != NULL)
+       {
+         asection *sec, *likely = NULL;
+         for (sec = opd_bfd->sections; sec != NULL; sec = sec->next)
+           if (sec->vma <= val
+               && (sec->flags & SEC_LOAD) != 0
+               && (sec->flags & SEC_ALLOC) != 0)
+             likely = sec;
+         if (likely != NULL)
+           {
+             *code_sec = likely;
+             if (code_off != NULL)
+               *code_off = val - likely->vma;
+           }
+       }
+      return val;
+    }
+
   /* Go find the opd reloc at the sym address.  */
   lo = _bfd_elf_link_read_relocs (opd_bfd, opd_sec, NULL, NULL, TRUE);
   BFD_ASSERT (lo != NULL);
@@ -5037,9 +5070,235 @@ ppc64_elf_gc_sweep_hook (bfd *abfd, struct bfd_link_info *info,
   return TRUE;
 }
 
+/* The maximum size of .sfpr.  */
+#define SFPR_MAX (218*4)
+
+struct sfpr_def_parms
+{
+  const char name[12];
+  unsigned char lo, hi;
+  bfd_byte * (*write_ent) (bfd *, bfd_byte *, int);
+  bfd_byte * (*write_tail) (bfd *, bfd_byte *, int);
+};
+
+/* Auto-generate _save*, _rest* functions in .sfpr.  */
+
+static unsigned int
+sfpr_define (struct bfd_link_info *info, const struct sfpr_def_parms *parm)
+{
+  struct ppc_link_hash_table *htab = ppc_hash_table (info);
+  unsigned int i;
+  size_t len = strlen (parm->name);
+  bfd_boolean writing = FALSE;
+  char sym[16];
+
+  memcpy (sym, parm->name, len);
+  sym[len + 2] = 0;
+
+  for (i = parm->lo; i <= parm->hi; i++)
+    {
+      struct elf_link_hash_entry *h;
+
+      sym[len + 0] = i / 10 + '0';
+      sym[len + 1] = i % 10 + '0';
+      h = elf_link_hash_lookup (&htab->elf, sym, FALSE, FALSE, TRUE);
+      if (h != NULL
+         && !h->def_regular)
+       {
+         h->root.type = bfd_link_hash_defined;
+         h->root.u.def.section = htab->sfpr;
+         h->root.u.def.value = htab->sfpr->size;
+         h->type = STT_FUNC;
+         h->def_regular = 1;
+         _bfd_elf_link_hash_hide_symbol (info, h, TRUE);
+         writing = TRUE;
+         if (htab->sfpr->contents == NULL)
+           {
+             htab->sfpr->contents = bfd_alloc (htab->elf.dynobj, SFPR_MAX);
+             if (htab->sfpr->contents == NULL)
+               return FALSE;
+           }
+       }
+      if (writing)
+       {
+         bfd_byte *p = htab->sfpr->contents + htab->sfpr->size;
+         if (i != parm->hi)
+           p = (*parm->write_ent) (htab->elf.dynobj, p, i);
+         else
+           p = (*parm->write_tail) (htab->elf.dynobj, p, i);
+         htab->sfpr->size = p - htab->sfpr->contents;
+       }
+    }
+
+  return TRUE;
+}
+
+static bfd_byte *
+savegpr0 (bfd *abfd, bfd_byte *p, int r)
+{
+  bfd_put_32 (abfd, STD_R0_0R1 + (r << 21) + (1 << 16) - (32 - r) * 8, p);
+  return p + 4;
+}
+
+static bfd_byte *
+savegpr0_tail (bfd *abfd, bfd_byte *p, int r)
+{
+  p = savegpr0 (abfd, p, r);
+  bfd_put_32 (abfd, STD_R0_0R1 + 16, p);
+  p = p + 4;
+  bfd_put_32 (abfd, BLR, p);
+  return p + 4;
+}
+
+static bfd_byte *
+restgpr0 (bfd *abfd, bfd_byte *p, int r)
+{
+  bfd_put_32 (abfd, LD_R0_0R1 + (r << 21) + (1 << 16) - (32 - r) * 8, p);
+  return p + 4;
+}
+
+static bfd_byte *
+restgpr0_tail (bfd *abfd, bfd_byte *p, int r)
+{
+  bfd_put_32 (abfd, LD_R0_0R1 + 16, p);
+  p = p + 4;
+  p = restgpr0 (abfd, p, r);
+  bfd_put_32 (abfd, MTLR_R0, p);
+  p = p + 4;
+  if (r == 29)
+    {
+      p = restgpr0 (abfd, p, 30);
+      p = restgpr0 (abfd, p, 31);
+    }
+  bfd_put_32 (abfd, BLR, p);
+  return p + 4;
+}
+
+static bfd_byte *
+savegpr1 (bfd *abfd, bfd_byte *p, int r)
+{
+  bfd_put_32 (abfd, STD_R0_0R12 + (r << 21) + (1 << 16) - (32 - r) * 8, p);
+  return p + 4;
+}
+
+static bfd_byte *
+savegpr1_tail (bfd *abfd, bfd_byte *p, int r)
+{
+  p = savegpr1 (abfd, p, r);
+  bfd_put_32 (abfd, BLR, p);
+  return p + 4;
+}
+
+static bfd_byte *
+restgpr1 (bfd *abfd, bfd_byte *p, int r)
+{
+  bfd_put_32 (abfd, LD_R0_0R12 + (r << 21) + (1 << 16) - (32 - r) * 8, p);
+  return p + 4;
+}
+
+static bfd_byte *
+restgpr1_tail (bfd *abfd, bfd_byte *p, int r)
+{
+  p = restgpr1 (abfd, p, r);
+  bfd_put_32 (abfd, BLR, p);
+  return p + 4;
+}
+
+static bfd_byte *
+savefpr (bfd *abfd, bfd_byte *p, int r)
+{
+  bfd_put_32 (abfd, STFD_FR0_0R1 + (r << 21) + (1 << 16) - (32 - r) * 8, p);
+  return p + 4;
+}
+
+static bfd_byte *
+savefpr0_tail (bfd *abfd, bfd_byte *p, int r)
+{
+  p = savefpr (abfd, p, r);
+  bfd_put_32 (abfd, STD_R0_0R1 + 16, p);
+  p = p + 4;
+  bfd_put_32 (abfd, BLR, p);
+  return p + 4;
+}
+
+static bfd_byte *
+restfpr (bfd *abfd, bfd_byte *p, int r)
+{
+  bfd_put_32 (abfd, LFD_FR0_0R1 + (r << 21) + (1 << 16) - (32 - r) * 8, p);
+  return p + 4;
+}
+
+static bfd_byte *
+restfpr0_tail (bfd *abfd, bfd_byte *p, int r)
+{
+  bfd_put_32 (abfd, LD_R0_0R1 + 16, p);
+  p = p + 4;
+  p = restfpr (abfd, p, r);
+  bfd_put_32 (abfd, MTLR_R0, p);
+  p = p + 4;
+  if (r == 29)
+    {
+      p = restfpr (abfd, p, 30);
+      p = restfpr (abfd, p, 31);
+    }
+  bfd_put_32 (abfd, BLR, p);
+  return p + 4;
+}
+
+static bfd_byte *
+savefpr1_tail (bfd *abfd, bfd_byte *p, int r)
+{
+  p = savefpr (abfd, p, r);
+  bfd_put_32 (abfd, BLR, p);
+  return p + 4;
+}
+
+static bfd_byte *
+restfpr1_tail (bfd *abfd, bfd_byte *p, int r)
+{
+  p = restfpr (abfd, p, r);
+  bfd_put_32 (abfd, BLR, p);
+  return p + 4;
+}
+
+static bfd_byte *
+savevr (bfd *abfd, bfd_byte *p, int r)
+{
+  bfd_put_32 (abfd, LI_R12_0 + (1 << 16) - (32 - r) * 16, p);
+  p = p + 4;
+  bfd_put_32 (abfd, STVX_VR0_R12_R0 + (r << 21), p);
+  return p + 4;
+}
+
+static bfd_byte *
+savevr_tail (bfd *abfd, bfd_byte *p, int r)
+{
+  p = savevr (abfd, p, r);
+  bfd_put_32 (abfd, BLR, p);
+  return p + 4;
+}
+
+static bfd_byte *
+restvr (bfd *abfd, bfd_byte *p, int r)
+{
+  bfd_put_32 (abfd, LI_R12_0 + (1 << 16) - (32 - r) * 16, p);
+  p = p + 4;
+  bfd_put_32 (abfd, LVX_VR0_R12_R0 + (r << 21), p);
+  return p + 4;
+}
+
+static bfd_byte *
+restvr_tail (bfd *abfd, bfd_byte *p, int r)
+{
+  p = restvr (abfd, p, r);
+  bfd_put_32 (abfd, BLR, p);
+  return p + 4;
+}
+
 /* Called via elf_link_hash_traverse to transfer dynamic linking
    information on function code symbol entries to their corresponding
    function descriptor symbol entries.  */
+
 static bfd_boolean
 func_desc_adjust (struct elf_link_hash_entry *h, void *inf)
 {
@@ -5075,7 +5334,7 @@ func_desc_adjust (struct elf_link_hash_entry *h, void *inf)
                          &fh->elf.root.u.def.value) != (bfd_vma) -1)
     {
       fh->elf.root.type = fh->oh->elf.root.type;
-      fh->elf.elf_link_hash_flags |= ELF_LINK_FORCED_LOCAL;
+      fh->elf.forced_local = 1;
     }
 
   /* If this is a function code symbol, transfer dynamic linking
@@ -5126,27 +5385,26 @@ func_desc_adjust (struct elf_link_hash_entry *h, void *inf)
          return FALSE;
        }
       fdh = (struct ppc_link_hash_entry *) bh;
-      fdh->elf.elf_link_hash_flags &= ~ELF_LINK_NON_ELF;
+      fdh->elf.non_elf = 0;
       fdh->elf.size = 24;
       fdh->elf.type = STT_OBJECT;
     }
 
   if (fdh != NULL
-      && (fdh->elf.elf_link_hash_flags & ELF_LINK_FORCED_LOCAL) == 0
+      && !fdh->elf.forced_local
       && (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.def_dynamic
+         || fdh->elf.ref_dynamic
          || (fdh->elf.root.type == bfd_link_hash_undefweak
              && ELF_ST_VISIBILITY (fdh->elf.other) == STV_DEFAULT)))
     {
       if (fdh->elf.dynindx == -1)
        if (! bfd_elf_link_record_dynamic_symbol (info, &fdh->elf))
          return FALSE;
-      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));
+      fdh->elf.ref_regular |= fh->elf.ref_regular;
+      fdh->elf.ref_dynamic |= fh->elf.ref_dynamic;
+      fdh->elf.ref_regular_nonweak |= fh->elf.ref_regular_nonweak;
+      fdh->elf.non_got_ref |= fh->elf.non_got_ref;
       if (ELF_ST_VISIBILITY (fh->elf.other) == STV_DEFAULT)
        {
          struct plt_entry **ep = &fdh->elf.plt.plist;
@@ -5154,7 +5412,7 @@ func_desc_adjust (struct elf_link_hash_entry *h, void *inf)
            ep = &(*ep)->next;
          *ep = fh->elf.plt.plist;
          fh->elf.plt.plist = NULL;
-         fdh->elf.elf_link_hash_flags |= ELF_LINK_HASH_NEEDS_PLT;
+         fdh->elf.needs_plt = 1;
        }
       fdh->is_func_descriptor = 1;
       fdh->oh = fh;
@@ -5170,120 +5428,57 @@ func_desc_adjust (struct elf_link_hash_entry *h, void *inf)
      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
+       && (!fh->elf.def_regular
           || 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));
+          || !fdh->elf.def_regular
+          || fdh->elf.forced_local));
   _bfd_elf_link_hash_hide_symbol (info, &fh->elf, force_local);
 
   return TRUE;
 }
 
-#define MIN_SAVE_FPR 14
-#define MAX_SAVE_FPR 31
-
 /* Called near the start of bfd_elf_size_dynamic_sections.  We use
    this hook to a) provide some gcc support functions, and b) transfer
    dynamic linking information gathered so far on function code symbol
    entries, to their corresponding function descriptor symbol entries.  */
+
 static bfd_boolean
 ppc64_elf_func_desc_adjust (bfd *obfd ATTRIBUTE_UNUSED,
                            struct bfd_link_info *info)
 {
   struct ppc_link_hash_table *htab;
-  unsigned int lowest_savef = MAX_SAVE_FPR + 2;
-  unsigned int lowest_restf = MAX_SAVE_FPR + 2;
   unsigned int i;
-  struct elf_link_hash_entry *h;
-  bfd_byte *p;
-  char sym[10];
+  const struct sfpr_def_parms funcs[] =
+    {
+      { "_savegpr0_", 14, 31, savegpr0, savegpr0_tail },
+      { "_restgpr0_", 14, 29, restgpr0, restgpr0_tail },
+      { "_restgpr0_", 30, 31, restgpr0, restgpr0_tail },
+      { "_savegpr1_", 14, 31, savegpr1, savegpr1_tail },
+      { "_restgpr1_", 14, 31, restgpr1, restgpr1_tail },
+      { "_savefpr_", 14, 31, savefpr, savefpr0_tail },
+      { "_restfpr_", 14, 29, restfpr, restfpr0_tail },
+      { "_restfpr_", 30, 31, restfpr, restfpr0_tail },
+      { "._savef", 14, 31, savefpr, savefpr1_tail },
+      { "._restf", 14, 31, restfpr, restfpr1_tail },
+      { "_savevr_", 20, 31, savevr, savevr_tail },
+      { "_restvr_", 20, 31, restvr, restvr_tail }
+    };
 
   htab = ppc_hash_table (info);
-
   if (htab->sfpr == NULL)
     /* We don't have any relocs.  */
     return TRUE;
 
-  /* First provide any missing ._savef* and ._restf* functions.  */
-  memcpy (sym, "._savef14", 10);
-  for (i = MIN_SAVE_FPR; i <= MAX_SAVE_FPR; i++)
-    {
-      sym[7] = i / 10 + '0';
-      sym[8] = i % 10 + '0';
-      h = elf_link_hash_lookup (&htab->elf, sym, FALSE, FALSE, TRUE);
-      if (h != NULL
-         && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0)
-       {
-         if (lowest_savef > i)
-           lowest_savef = i;
-         h->root.type = bfd_link_hash_defined;
-         h->root.u.def.section = htab->sfpr;
-         h->root.u.def.value = (i - lowest_savef) * 4;
-         h->type = STT_FUNC;
-         h->elf_link_hash_flags |= ELF_LINK_HASH_DEF_REGULAR;
-         _bfd_elf_link_hash_hide_symbol (info, h, TRUE);
-       }
-    }
-
-  memcpy (sym, "._restf14", 10);
-  for (i = MIN_SAVE_FPR; i <= MAX_SAVE_FPR; i++)
-    {
-      sym[7] = i / 10 + '0';
-      sym[8] = i % 10 + '0';
-      h = elf_link_hash_lookup (&htab->elf, sym, FALSE, FALSE, TRUE);
-      if (h != NULL
-         && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0)
-       {
-         if (lowest_restf > i)
-           lowest_restf = i;
-         h->root.type = bfd_link_hash_defined;
-         h->root.u.def.section = htab->sfpr;
-         h->root.u.def.value = ((MAX_SAVE_FPR + 2 - lowest_savef) * 4
-                                + (i - lowest_restf) * 4);
-         h->type = STT_FUNC;
-         h->elf_link_hash_flags |= ELF_LINK_HASH_DEF_REGULAR;
-         _bfd_elf_link_hash_hide_symbol (info, h, TRUE);
-       }
-    }
+  /* Provide any missing _save* and _rest* functions.  */
+  htab->sfpr->size = 0;
+  for (i = 0; i < sizeof (funcs) / sizeof (funcs[0]); i++)
+    if (!sfpr_define (info, &funcs[i]))
+      return FALSE;
 
   elf_link_hash_traverse (&htab->elf, func_desc_adjust, info);
 
-  htab->sfpr->size = ((MAX_SAVE_FPR + 2 - lowest_savef) * 4
-                     + (MAX_SAVE_FPR + 2 - lowest_restf) * 4);
-
   if (htab->sfpr->size == 0)
-    {
-      _bfd_strip_section_from_output (info, htab->sfpr);
-      return TRUE;
-    }
-
-  p = bfd_alloc (htab->elf.dynobj, htab->sfpr->size);
-  if (p == NULL)
-    return FALSE;
-  htab->sfpr->contents = p;
-
-  for (i = lowest_savef; i <= MAX_SAVE_FPR; i++)
-    {
-      unsigned int fpr = i << 21;
-      unsigned int stackoff = (1 << 16) - (MAX_SAVE_FPR + 1 - i) * 8;
-      bfd_put_32 (htab->elf.dynobj, STFD_FR0_0R1 + fpr + stackoff, p);
-      p += 4;
-    }
-  if (lowest_savef <= MAX_SAVE_FPR)
-    {
-      bfd_put_32 (htab->elf.dynobj, BLR, p);
-      p += 4;
-    }
-
-  for (i = lowest_restf; i <= MAX_SAVE_FPR; i++)
-    {
-      unsigned int fpr = i << 21;
-      unsigned int stackoff = (1 << 16) - (MAX_SAVE_FPR + 1 - i) * 8;
-      bfd_put_32 (htab->elf.dynobj, LFD_FR0_0R1 + fpr + stackoff, p);
-      p += 4;
-    }
-  if (lowest_restf <= MAX_SAVE_FPR)
-    bfd_put_32 (htab->elf.dynobj, BLR, p);
+    _bfd_strip_section_from_output (info, htab->sfpr);
 
   return TRUE;
 }
@@ -5306,7 +5501,7 @@ ppc64_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
 
   /* Deal with function syms.  */
   if (h->type == STT_FUNC
-      || (h->elf_link_hash_flags & ELF_LINK_HASH_NEEDS_PLT) != 0)
+      || h->needs_plt)
     {
       /* Clear procedure linkage table information for any symbol that
         won't need a .plt entry.  */
@@ -5320,7 +5515,7 @@ ppc64_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
              && h->root.type == bfd_link_hash_undefweak))
        {
          h->plt.plist = NULL;
-         h->elf_link_hash_flags &= ~ELF_LINK_HASH_NEEDS_PLT;
+         h->needs_plt = 0;
        }
     }
   else
@@ -5329,16 +5524,14 @@ ppc64_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
   /* If this is a weak symbol, and there is a real definition, the
      processor independent code will have arranged for us to see the
      real definition first, and we can just use the same value.  */
-  if (h->weakdef != NULL)
+  if (h->u.weakdef != NULL)
     {
-      BFD_ASSERT (h->weakdef->root.type == bfd_link_hash_defined
-                 || h->weakdef->root.type == bfd_link_hash_defweak);
-      h->root.u.def.section = h->weakdef->root.u.def.section;
-      h->root.u.def.value = h->weakdef->root.u.def.value;
+      BFD_ASSERT (h->u.weakdef->root.type == bfd_link_hash_defined
+                 || h->u.weakdef->root.type == bfd_link_hash_defweak);
+      h->root.u.def.section = h->u.weakdef->root.u.def.section;
+      h->root.u.def.value = h->u.weakdef->root.u.def.value;
       if (ELIMINATE_COPY_RELOCS)
-       h->elf_link_hash_flags
-         = ((h->elf_link_hash_flags & ~ELF_LINK_NON_GOT_REF)
-            | (h->weakdef->elf_link_hash_flags & ELF_LINK_NON_GOT_REF));
+       h->non_got_ref = h->u.weakdef->non_got_ref;
       return TRUE;
     }
 
@@ -5351,7 +5544,7 @@ ppc64_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
 
   /* If there are no references to this symbol that do not use the
      GOT, we don't need to generate a copy reloc.  */
-  if ((h->elf_link_hash_flags & ELF_LINK_NON_GOT_REF) == 0)
+  if (!h->non_got_ref)
     return TRUE;
 
   if (ELIMINATE_COPY_RELOCS)
@@ -5371,7 +5564,7 @@ ppc64_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
         we'll be keeping the dynamic relocs and avoiding the copy reloc.  */
       if (p == NULL)
        {
-         h->elf_link_hash_flags &= ~ELF_LINK_NON_GOT_REF;
+         h->non_got_ref = 0;
          return TRUE;
        }
     }
@@ -5409,7 +5602,7 @@ ppc64_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
   if ((h->root.u.def.section->flags & SEC_ALLOC) != 0)
     {
       htab->relbss->size += sizeof (Elf64_External_Rela);
-      h->elf_link_hash_flags |= ELF_LINK_HASH_NEEDS_COPY;
+      h->needs_copy = 1;
     }
 
   /* We need to figure out the alignment required for this symbol.  I
@@ -5639,7 +5832,7 @@ get_tls_mask (char **tls_maskp, unsigned long *toc_symndx,
   if ((h == NULL
        || ((h->root.type == bfd_link_hash_defined
            || h->root.type == bfd_link_hash_defweak)
-          && !(h->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC)))
+          && !h->def_dynamic))
       && (next_r == -1 || next_r == -2))
     return 1 - next_r;
   return 1;
@@ -5732,13 +5925,16 @@ ppc64_elf_edit_opd (bfd *obfd, struct bfd_link_info *info,
       opd_adjust = get_opd_info (sec);
       if (opd_adjust == NULL)
        {
-         /* Must be a ld -r link.  ie. check_relocs hasn't been
-            called.  */
+         /* check_relocs hasn't been called.  Must be a ld -r link
+            or --just-symbols object.   */
          opd_adjust = bfd_zalloc (obfd, amt);
          ppc64_elf_section_data (sec)->opd.adjust = opd_adjust;
        }
       memset (opd_adjust, 0, amt);
 
+      if (sec->sec_info_type == ELF_INFO_TYPE_JUST_SYMS)
+       continue;
+
       if (sec->output_section == bfd_abs_section_ptr)
        continue;
 
@@ -6092,7 +6288,7 @@ ppc64_elf_edit_opd (bfd *obfd, struct bfd_link_info *info,
          p = bfd_malloc (need_pad->size + 8);
          if (p == NULL)
            return FALSE;
-                      
+
          if (! bfd_get_section_contents (need_pad->owner, need_pad,
                                          p, 0, need_pad->size))
            return FALSE;
@@ -6231,7 +6427,7 @@ ppc64_elf_tls_optimize (bfd *obfd ATTRIBUTE_UNUSED, struct bfd_link_info *info)
                ok_tprel = FALSE;
                is_local = FALSE;
                if (h == NULL
-                   || !(h->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC))
+                   || !h->def_dynamic)
                  {
                    is_local = TRUE;
                    value += sym_sec->output_offset;
@@ -6510,13 +6706,13 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
       if (!doneone)
        {
          h->plt.plist = NULL;
-         h->elf_link_hash_flags &= ~ELF_LINK_HASH_NEEDS_PLT;
+         h->needs_plt = 0;
        }
     }
   else
     {
       h->plt.plist = NULL;
-      h->elf_link_hash_flags &= ~ELF_LINK_HASH_NEEDS_PLT;
+      h->needs_plt = 0;
     }
 
   eh = (struct ppc_link_hash_entry *) h;
@@ -6554,14 +6750,14 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
           Undefined weak syms won't yet be marked as dynamic,
           nor will all TLS symbols.  */
        if (h->dynindx == -1
-           && (h->elf_link_hash_flags & ELF_LINK_FORCED_LOCAL) == 0)
+           && !h->forced_local)
          {
            if (! bfd_elf_link_record_dynamic_symbol (info, h))
              return FALSE;
          }
 
        if ((gent->tls_type & TLS_LD) != 0
-           && !(h->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC))
+           && !h->def_dynamic)
          {
            gent->got.offset = ppc64_tlsld_got (gent->owner)->offset;
            continue;
@@ -6628,14 +6824,14 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
         symbols which turn out to need copy relocs or are not
         dynamic.  */
 
-      if ((h->elf_link_hash_flags & ELF_LINK_NON_GOT_REF) == 0
-         && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC) != 0
-         && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0)
+      if (!h->non_got_ref
+         && h->def_dynamic
+         && !h->def_regular)
        {
          /* Make sure this symbol is output as a dynamic symbol.
             Undefined weak syms won't yet be marked as dynamic.  */
          if (h->dynindx == -1
-             && (h->elf_link_hash_flags & ELF_LINK_FORCED_LOCAL) == 0)
+             && !h->forced_local)
            {
              if (! bfd_elf_link_record_dynamic_symbol (info, h))
                return FALSE;
@@ -6732,7 +6928,7 @@ ppc64_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
       Elf_Internal_Shdr *symtab_hdr;
       asection *srel;
 
-      if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour)
+      if (!is_ppc64_elf_target (ibfd->xvec))
        continue;
 
       if (ppc64_tlsld_got (ibfd)->refcount > 0)
@@ -6902,6 +7098,9 @@ ppc64_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
 
   for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next)
     {
+      if (!is_ppc64_elf_target (ibfd->xvec))
+       continue;
+
       s = ppc64_elf_tdata (ibfd)->got;
       if (s != NULL && s != htab->got)
        {
@@ -7083,7 +7282,7 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
   bfd_byte *p;
   unsigned int indx;
   struct plt_entry *ent;
-  bfd_vma off;
+  bfd_vma dest, off;
   int size;
 
   /* Massage our args to the form they really have.  */
@@ -7102,9 +7301,9 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
     case ppc_stub_long_branch:
     case ppc_stub_long_branch_r2off:
       /* Branches are relative.  This is where we are going to.  */
-      off = (stub_entry->target_value
-            + stub_entry->target_section->output_offset
-            + stub_entry->target_section->output_section->vma);
+      off = dest = (stub_entry->target_value
+                   + stub_entry->target_section->output_offset
+                   + stub_entry->target_section->output_section->vma);
 
       /* And this is where we are coming from.  */
       off -= (stub_entry->stub_offset
@@ -7131,6 +7330,67 @@ 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 (info->emitrelocations)
+       {
+         Elf_Internal_Rela *relocs, *r;
+         struct bfd_elf_section_data *elfsec_data;
+
+         elfsec_data = elf_section_data (stub_entry->stub_sec);
+         relocs = elfsec_data->relocs;
+         if (relocs == NULL)
+           {
+             bfd_size_type relsize;
+             relsize = stub_entry->stub_sec->reloc_count * sizeof (*relocs);
+             relocs = bfd_alloc (htab->stub_bfd, relsize);
+             if (relocs == NULL)
+               return FALSE;
+             elfsec_data->relocs = relocs;
+             elfsec_data->rel_hdr.sh_size = relsize;
+             elfsec_data->rel_hdr.sh_entsize = 24;
+             stub_entry->stub_sec->reloc_count = 0;
+           }
+         r = relocs + stub_entry->stub_sec->reloc_count;
+         stub_entry->stub_sec->reloc_count += 1;
+         r->r_offset = loc - stub_entry->stub_sec->contents;
+         r->r_info = ELF64_R_INFO (0, R_PPC64_REL24);
+         r->r_addend = dest;
+         if (stub_entry->h != NULL)
+           {
+             struct elf_link_hash_entry **hashes;
+             unsigned long symndx;
+             struct ppc_link_hash_entry *h;
+
+             hashes = elf_sym_hashes (htab->stub_bfd);
+             if (hashes == NULL)
+               {
+                 bfd_size_type hsize;
+
+                 hsize = (htab->stub_globals + 1) * sizeof (*hashes);
+                 hashes = bfd_zalloc (htab->stub_bfd, hsize);
+                 if (hashes == NULL)
+                   return FALSE;
+                 elf_sym_hashes (htab->stub_bfd) = hashes;
+                 htab->stub_globals = 1;
+               }
+             symndx = htab->stub_globals++;
+             h = stub_entry->h;
+             hashes[symndx] = &h->elf;
+             r->r_info = ELF64_R_INFO (symndx, R_PPC64_REL24);
+             if (h->oh != NULL && h->oh->is_func)
+               h = h->oh;
+             if (h->elf.root.u.def.section != stub_entry->target_section)
+               /* H is an opd symbol.  The addend must be zero.  */
+               r->r_addend = 0;
+             else
+               {
+                 off = (h->elf.root.u.def.value
+                        + h->elf.root.u.def.section->output_offset
+                        + h->elf.root.u.def.section->output_section->vma);
+                 r->r_addend -= off;
+               }
+           }
+       }
       break;
 
     case ppc_stub_plt_branch:
@@ -7153,7 +7413,7 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
       bfd_put_64 (htab->brlt->owner, off,
                  htab->brlt->contents + br_entry->offset);
 
-      if (info->shared)
+      if (htab->relbrlt != NULL)
        {
          /* Create a reloc for the branch lookup table entry.  */
          Elf_Internal_Rela rela;
@@ -7273,16 +7533,26 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
 
   stub_entry->stub_sec->size += size;
 
-  if (htab->emit_stub_syms
-      && !(stub_entry->stub_type == ppc_stub_plt_call
-          && stub_entry->h->oh != NULL
-          && stub_entry->h->oh->elf.root.type == bfd_link_hash_defined
-          && stub_entry->h->oh->elf.root.u.def.section == stub_entry->stub_sec
-          && stub_entry->h->oh->elf.root.u.def.value == 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);
+      size_t len1, len2;
+      char *name;
+      const char *const stub_str[] = { "long_branch",
+                                      "long_branch_r2off",
+                                      "plt_branch",
+                                      "plt_branch_r2off",
+                                      "plt_call" };
+
+      len1 = strlen (stub_str[stub_entry->stub_type - 1]);
+      len2 = strlen (stub_entry->root.string);
+      name = bfd_malloc (len1 + len2 + 2);
+      if (name == NULL)
+       return FALSE;
+      memcpy (name, stub_entry->root.string, 9);
+      memcpy (name + 9, stub_str[stub_entry->stub_type - 1], len1);
+      memcpy (name + len1 + 9, stub_entry->root.string + 8, len2 - 8 + 1);
+      h = elf_link_hash_lookup (&htab->elf, name, TRUE, FALSE, FALSE);
       if (h == NULL)
        return FALSE;
       if (h->root.type == bfd_link_hash_new)
@@ -7290,10 +7560,11 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
          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);
+         h->ref_regular = 1;
+         h->def_regular = 1;
+         h->ref_regular_nonweak = 1;
+         h->forced_local = 1;
+         h->non_elf = 0;
        }
     }
 
@@ -7385,7 +7656,7 @@ ppc_size_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
              br_entry->offset = htab->brlt->size;
              htab->brlt->size += 8;
 
-             if (info->shared)
+             if (htab->relbrlt != NULL)
                htab->relbrlt->size += sizeof (Elf64_External_Rela);
            }
 
@@ -7394,6 +7665,11 @@ ppc_size_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
          if (stub_entry->stub_type != ppc_stub_plt_branch)
            size = 28;
        }
+
+      if (info->emitrelocations
+         && (stub_entry->stub_type == ppc_stub_long_branch
+             || stub_entry->stub_type == ppc_stub_long_branch_r2off))
+       stub_entry->stub_sec->reloc_count += 1;
     }
 
   stub_entry->stub_sec->size += size;
@@ -7980,6 +8256,10 @@ ppc64_elf_size_stubs (bfd *output_bfd,
                  stub_entry->target_section = code_sec;
                  stub_entry->h = hash;
                  stub_entry->addend = irela->r_addend;
+
+                 if (stub_entry->h != NULL)
+                   htab->stub_globals += 1;
+
                  stub_changed = TRUE;
                }
 
@@ -8007,10 +8287,13 @@ ppc64_elf_size_stubs (bfd *output_bfd,
           stub_sec != NULL;
           stub_sec = stub_sec->next)
        if ((stub_sec->flags & SEC_LINKER_CREATED) == 0)
-         stub_sec->size = 0;
+         {
+           stub_sec->size = 0;
+           stub_sec->reloc_count = 0;
+         }
 
       htab->brlt->size = 0;
-      if (info->shared)
+      if (htab->relbrlt != NULL)
        htab->relbrlt->size = 0;
 
       bfd_hash_traverse (&htab->stub_hash_table, ppc_size_one_stub, info);
@@ -8144,10 +8427,11 @@ ppc64_elf_build_stubs (bfd_boolean emit_stub_syms,
              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);
+             h->ref_regular = 1;
+             h->def_regular = 1;
+             h->ref_regular_nonweak = 1;
+             h->forced_local = 1;
+             h->non_elf = 0;
            }
        }
       p = htab->glink->contents;
@@ -8215,7 +8499,7 @@ ppc64_elf_build_stubs (bfd_boolean emit_stub_syms,
       if (htab->brlt->contents == NULL)
        return FALSE;
     }
-  if (info->shared && htab->relbrlt->size != 0)
+  if (htab->relbrlt != NULL && htab->relbrlt->size != 0)
     {
       htab->relbrlt->contents = bfd_zalloc (htab->relbrlt->owner,
                                            htab->relbrlt->size);
@@ -8252,13 +8536,14 @@ ppc64_elf_build_stubs (bfd_boolean emit_stub_syms,
       if (*stats == NULL)
        return FALSE;
 
-      sprintf (*stats, _("linker stubs in %u groups\n"
+      sprintf (*stats, _("linker stubs in %u group%s\n"
                         "  branch       %lu\n"
                         "  toc adjust   %lu\n"
                         "  long branch  %lu\n"
                         "  long toc adj %lu\n"
                         "  plt call     %lu"),
               stub_sec_count,
+              stub_sec_count == 1 ? "" : "s",
               htab->stub_count[ppc_stub_long_branch - 1],
               htab->stub_count[ppc_stub_long_branch_r2off - 1],
               htab->stub_count[ppc_stub_plt_branch - 1],
@@ -8357,6 +8642,11 @@ ppc64_elf_relocate_section (bfd *output_bfd,
     ppc_howto_init ();
 
   htab = ppc_hash_table (info);
+
+  /* Don't relocate stub sections.  */
+  if (input_section->owner == htab->stub_bfd)
+    return TRUE;
+
   local_got_ents = elf_local_got_ents (input_bfd);
   TOCstart = elf_gp (output_bfd);
   symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
@@ -9057,8 +9347,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
 
            if (tls_type == (TLS_TLS | TLS_LD)
                && (h == NULL
-                   || (h->elf.elf_link_hash_flags
-                       & ELF_LINK_HASH_DEF_DYNAMIC) == 0))
+                   || !h->elf.def_dynamic))
              offp = &ppc64_tlsld_got (input_bfd)->offset;
            else
              {
@@ -9377,9 +9666,9 @@ ppc64_elf_relocate_section (bfd *output_bfd,
                  && !info->shared
                  && h != NULL
                  && h->elf.dynindx != -1
-                 && !(h->elf.elf_link_hash_flags & ELF_LINK_NON_GOT_REF)
-                 && (h->elf.elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC)
-                 && !(h->elf.elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR)))
+                 && !h->elf.non_got_ref
+                 && h->elf.def_dynamic
+                 && !h->elf.def_regular))
            {
              Elf_Internal_Rela outrel;
              bfd_boolean skip, relocate;
@@ -9632,7 +9921,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
         not process them.  */
       if (unresolved_reloc
          && !((input_section->flags & SEC_DEBUGGING) != 0
-              && (h->elf.elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC)))
+              && h->elf.def_dynamic))
        {
          (*_bfd_error_handler)
            (_("%B(%A+0x%lx): unresolvable %s relocation against symbol `%s'"),
@@ -9674,7 +9963,8 @@ ppc64_elf_relocate_section (bfd *output_bfd,
                }
 
              if (!((*info->callbacks->reloc_overflow)
-                   (info, sym_name, ppc64_elf_howto_table[r_type]->name,
+                   (info, (h ? &h->elf.root : NULL), sym_name,
+                    ppc64_elf_howto_table[r_type]->name,
                     rel->r_addend, input_bfd, input_section, rel->r_offset)))
                return FALSE;
            }
@@ -9770,7 +10060,7 @@ ppc64_elf_finish_dynamic_symbol (bfd *output_bfd,
        bfd_elf64_swap_reloca_out (output_bfd, &rela, loc);
       }
 
-  if ((h->elf_link_hash_flags & ELF_LINK_HASH_NEEDS_COPY) != 0)
+  if (h->needs_copy)
     {
       Elf_Internal_Rela rela;
       bfd_byte *loc;
@@ -9941,10 +10231,15 @@ ppc64_elf_finish_dynamic_sections (bfd *output_bfd,
     }
 
   /* We need to handle writing out multiple GOT sections ourselves,
-     since we didn't add them to DYNOBJ.  */
+     since we didn't add them to DYNOBJ.  We know dynobj is the first
+     bfd.  */
   while ((dynobj = dynobj->link_next) != NULL)
     {
       asection *s;
+
+      if (!is_ppc64_elf_target (dynobj->xvec))
+       continue;
+
       s = ppc64_elf_tdata (dynobj)->got;
       if (s != NULL
          && s->size != 0
This page took 0.048502 seconds and 4 git commands to generate.