daily update
[deliverable/binutils-gdb.git] / bfd / elf64-ppc.c
index b49b6137034366dca4086718df401c77aa970ff4..d230c1bdb343538b69451926cb39eca7a290382a 100644 (file)
@@ -3206,9 +3206,9 @@ struct ppc_link_hash_entry
   unsigned int is_func:1;
   unsigned int is_func_descriptor:1;
 
-  /* Whether global opd sym has been adjusted or not.
-     After ppc64_elf_edit_opd has run, this flag should be set for all
-     globals defined in any opd section.  */
+  /* Whether global opd/toc sym has been adjusted or not.
+     After ppc64_elf_edit_opd/ppc64_elf_edit_toc has run, this flag
+     should be set for all globals defined in any opd/toc section.  */
   unsigned int adjust_done:1;
 
   /* Set if we twiddled this symbol to weak at some stage.  */
@@ -3766,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;
@@ -3810,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)
@@ -4064,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;
@@ -4155,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;
 }
@@ -4551,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)
@@ -4584,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;
@@ -4701,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);
@@ -5080,13 +5103,13 @@ sfpr_define (struct bfd_link_info *info, const struct sfpr_def_parms *parm)
       sym[len + 1] = 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)
+         && !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->elf_link_hash_flags |= ELF_LINK_HASH_DEF_REGULAR;
+         h->def_regular = 1;
          _bfd_elf_link_hash_hide_symbol (info, h, TRUE);
          writing = TRUE;
          if (htab->sfpr->contents == NULL)
@@ -5311,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
@@ -5362,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;
@@ -5390,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;
@@ -5406,10 +5428,10 @@ 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;
@@ -5479,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.  */
@@ -5493,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
@@ -5502,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;
     }
 
@@ -5524,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)
@@ -5544,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;
        }
     }
@@ -5582,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
@@ -5812,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;
@@ -5905,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;
 
@@ -6404,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;
@@ -6622,6 +6645,445 @@ ppc64_elf_tls_optimize (bfd *obfd ATTRIBUTE_UNUSED, struct bfd_link_info *info)
   return TRUE;
 }
 
+/* Called via elf_link_hash_traverse from ppc64_elf_edit_toc to adjust
+   the values of any global symbols in a toc section that has been
+   edited.  Globals in toc sections should be a rarity, so this function
+   sets a flag if any are found in toc sections other than the one just
+   edited, so that futher hash table traversals can be avoided.  */
+
+struct adjust_toc_info
+{
+  asection *toc;
+  unsigned long *skip;
+  bfd_boolean global_toc_syms;
+};
+
+static bfd_boolean
+adjust_toc_syms (struct elf_link_hash_entry *h, void *inf)
+{
+  struct ppc_link_hash_entry *eh;
+  struct adjust_toc_info *toc_inf = (struct adjust_toc_info *) inf;
+
+  if (h->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 (h->root.type != bfd_link_hash_defined
+      && h->root.type != bfd_link_hash_defweak)
+    return TRUE;
+
+  eh = (struct ppc_link_hash_entry *) h;
+  if (eh->adjust_done)
+    return TRUE;
+
+  if (eh->elf.root.u.def.section == toc_inf->toc)
+    {
+      unsigned long skip = toc_inf->skip[eh->elf.root.u.def.value >> 3];
+      if (skip != (unsigned long) -1)
+       eh->elf.root.u.def.value -= skip;
+      else
+       {
+         (*_bfd_error_handler)
+           (_("%s defined in removed toc entry"), eh->elf.root.root.string);
+         eh->elf.root.u.def.section = &bfd_abs_section;
+         eh->elf.root.u.def.value = 0;
+       }
+      eh->adjust_done = 1;
+    }
+  else if (strcmp (eh->elf.root.u.def.section->name, ".toc") == 0)
+    toc_inf->global_toc_syms = TRUE;
+
+  return TRUE;
+}
+
+/* Examine all relocs referencing .toc sections in order to remove
+   unused .toc entries.  */
+
+bfd_boolean
+ppc64_elf_edit_toc (bfd *obfd ATTRIBUTE_UNUSED, struct bfd_link_info *info)
+{
+  bfd *ibfd;
+  struct adjust_toc_info toc_inf;
+
+  toc_inf.global_toc_syms = TRUE;
+  for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next)
+    {
+      asection *toc, *sec;
+      Elf_Internal_Shdr *symtab_hdr;
+      Elf_Internal_Sym *local_syms;
+      struct elf_link_hash_entry **sym_hashes;
+      Elf_Internal_Rela *relstart, *rel, *wrel;
+      unsigned long *skip, *drop;
+      unsigned char *used;
+      unsigned char *keep, last, some_unused;
+
+      toc = bfd_get_section_by_name (ibfd, ".toc");
+      if (toc == NULL
+         || toc->sec_info_type == ELF_INFO_TYPE_JUST_SYMS
+         || elf_discarded_section (toc))
+       continue;
+
+      local_syms = NULL;
+      symtab_hdr = &elf_tdata (ibfd)->symtab_hdr;
+      sym_hashes = elf_sym_hashes (ibfd);
+
+      /* Look at sections dropped from the final link.  */
+      skip = NULL;
+      relstart = NULL;
+      for (sec = ibfd->sections; sec != NULL; sec = sec->next)
+       {
+         if (sec->reloc_count == 0
+             || !elf_discarded_section (sec)
+             || get_opd_info (sec)
+             || (sec->flags & SEC_ALLOC) == 0
+             || (sec->flags & SEC_DEBUGGING) != 0)
+           continue;
+
+         relstart = _bfd_elf_link_read_relocs (ibfd, sec, NULL, NULL, FALSE);
+         if (relstart == NULL)
+           goto error_ret;
+
+         /* Run through the relocs to see which toc entries might be
+            unused.  */
+         for (rel = relstart; rel < relstart + sec->reloc_count; ++rel)
+           {
+             enum elf_ppc64_reloc_type r_type;
+             unsigned long r_symndx;
+             asection *sym_sec;
+             struct elf_link_hash_entry *h;
+             Elf_Internal_Sym *sym;
+             bfd_vma val;
+
+             r_type = ELF64_R_TYPE (rel->r_info);
+             switch (r_type)
+               {
+               default:
+                 continue;
+
+               case R_PPC64_TOC16:
+               case R_PPC64_TOC16_LO:
+               case R_PPC64_TOC16_HI:
+               case R_PPC64_TOC16_HA:
+               case R_PPC64_TOC16_DS:
+               case R_PPC64_TOC16_LO_DS:
+                 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_ret;
+
+             if (sym_sec != toc)
+               continue;
+
+             if (h != NULL)
+               val = h->root.u.def.value;
+             else
+               val = sym->st_value;
+             val += rel->r_addend;
+
+             if (val >= toc->size)
+               continue;
+
+             /* Anything in the toc ought to be aligned to 8 bytes.
+                If not, don't mark as unused.  */
+             if (val & 7)
+               continue;
+
+             if (skip == NULL)
+               {
+                 skip = bfd_zmalloc (sizeof (*skip) * (toc->size + 7) / 8);
+                 if (skip == NULL)
+                   goto error_ret;
+               }
+
+             skip[val >> 3] = 1;
+           }
+
+         if (elf_section_data (sec)->relocs != relstart)
+           free (relstart);
+       }
+
+      if (skip == NULL)
+       continue;
+
+      used = bfd_zmalloc (sizeof (*used) * (toc->size + 7) / 8);
+      if (used == NULL)
+       {
+       error_ret:
+         if (local_syms != NULL
+             && symtab_hdr->contents != (unsigned char *) local_syms)
+           free (local_syms);
+         if (sec != NULL
+             && relstart != NULL
+             && elf_section_data (sec)->relocs != relstart)
+           free (relstart);
+         if (skip != NULL)
+           free (skip);
+         return FALSE;
+       }
+
+      /* Now check all kept sections that might reference the toc.  */
+      for (sec = ibfd->sections;
+          sec != NULL;
+          /* Check the toc itself last.  */
+          sec = (sec == toc ? NULL
+                 : sec->next == toc && sec->next->next ? sec->next->next
+                 : sec->next == NULL ? toc
+                 : sec->next))
+       {
+         int repeat;
+
+         if (sec->reloc_count == 0
+             || elf_discarded_section (sec)
+             || get_opd_info (sec)
+             || (sec->flags & SEC_ALLOC) == 0
+             || (sec->flags & SEC_DEBUGGING) != 0)
+           continue;
+
+         relstart = _bfd_elf_link_read_relocs (ibfd, sec, NULL, NULL, TRUE);
+         if (relstart == NULL)
+           goto error_ret;
+
+         /* Mark toc entries referenced as used.  */
+         repeat = 0;
+         do
+           for (rel = relstart; rel < relstart + sec->reloc_count; ++rel)
+             {
+               enum elf_ppc64_reloc_type r_type;
+               unsigned long r_symndx;
+               asection *sym_sec;
+               struct elf_link_hash_entry *h;
+               Elf_Internal_Sym *sym;
+               bfd_vma val;
+
+               r_type = ELF64_R_TYPE (rel->r_info);
+               switch (r_type)
+                 {
+                 case R_PPC64_TOC16:
+                 case R_PPC64_TOC16_LO:
+                 case R_PPC64_TOC16_HI:
+                 case R_PPC64_TOC16_HA:
+                 case R_PPC64_TOC16_DS:
+                 case R_PPC64_TOC16_LO_DS:
+                   /* In case we're taking addresses of toc entries.  */
+                 case R_PPC64_ADDR64:
+                   break;
+
+                 default:
+                   continue;
+                 }
+
+               r_symndx = ELF64_R_SYM (rel->r_info);
+               if (!get_sym_h (&h, &sym, &sym_sec, NULL, &local_syms,
+                               r_symndx, ibfd))
+                 {
+                   free (used);
+                   goto error_ret;
+                 }
+
+               if (sym_sec != toc)
+                 continue;
+
+               if (h != NULL)
+                 val = h->root.u.def.value;
+               else
+                 val = sym->st_value;
+               val += rel->r_addend;
+
+               if (val >= toc->size)
+                 continue;
+
+               /* For the toc section, we only mark as used if
+                  this entry itself isn't unused.  */
+               if (sec == toc
+                   && !used[val >> 3]
+                   && (used[rel->r_offset >> 3]
+                       || !skip[rel->r_offset >> 3]))
+                 /* Do all the relocs again, to catch reference
+                    chains.  */
+                 repeat = 1;
+
+               used[val >> 3] = 1;
+             }
+         while (repeat);
+       }
+
+      /* Merge the used and skip arrays.  Assume that TOC
+        doublewords not appearing as either used or unused belong
+        to to an entry more than one doubleword in size.  */
+      for (drop = skip, keep = used, last = 0, some_unused = 0;
+          drop < skip + (toc->size + 7) / 8;
+          ++drop, ++keep)
+       {
+         if (*keep)
+           {
+             *drop = 0;
+             last = 0;
+           }
+         else if (*drop)
+           {
+             some_unused = 1;
+             last = 1;
+           }
+         else
+           *drop = last;
+       }
+
+      free (used);
+
+      if (some_unused)
+       {
+         bfd_byte *contents, *src;
+         unsigned long off;
+
+         /* Shuffle the toc contents, and at the same time convert the
+            skip array from booleans into offsets.  */
+         if (!bfd_malloc_and_get_section (ibfd, toc, &contents))
+           goto error_ret;
+
+         elf_section_data (toc)->this_hdr.contents = contents;
+
+         for (src = contents, off = 0, drop = skip;
+              src < contents + toc->size;
+              src += 8, ++drop)
+           {
+             if (*drop)
+               {
+                 *drop = (unsigned long) -1;
+                 off += 8;
+               }
+             else if (off != 0)
+               {
+                 *drop = off;
+                 memcpy (src - off, src, 8);
+               }
+           }
+         toc->rawsize = toc->size;
+         toc->size = src - contents - off;
+
+         /* Read toc relocs.  */
+         relstart = _bfd_elf_link_read_relocs (ibfd, toc, NULL, NULL, TRUE);
+         if (relstart == NULL)
+           goto error_ret;
+
+         /* Remove unused toc relocs, and adjust those we keep.  */
+         wrel = relstart;
+         for (rel = relstart; rel < relstart + toc->reloc_count; ++rel)
+           if (skip[rel->r_offset >> 3] != (unsigned long) -1)
+             {
+               wrel->r_offset = rel->r_offset - skip[rel->r_offset >> 3];
+               wrel->r_info = rel->r_info;
+               wrel->r_addend = rel->r_addend;
+               ++wrel;
+             }
+         toc->reloc_count = wrel - relstart;
+
+         /* Adjust addends for relocs against the toc section sym.  */
+         for (sec = ibfd->sections; sec != NULL; sec = sec->next)
+           {
+             if (sec->reloc_count == 0
+                 || elf_discarded_section (sec))
+               continue;
+
+             relstart = _bfd_elf_link_read_relocs (ibfd, sec, NULL, NULL,
+                                                   TRUE);
+             if (relstart == NULL)
+               goto error_ret;
+
+             for (rel = relstart; rel < relstart + sec->reloc_count; ++rel)
+               {
+                 enum elf_ppc64_reloc_type r_type;
+                 unsigned long r_symndx;
+                 asection *sym_sec;
+                 struct elf_link_hash_entry *h;
+                 Elf_Internal_Sym *sym;
+
+                 r_type = ELF64_R_TYPE (rel->r_info);
+                 switch (r_type)
+                   {
+                   default:
+                     continue;
+
+                   case R_PPC64_TOC16:
+                   case R_PPC64_TOC16_LO:
+                   case R_PPC64_TOC16_HI:
+                   case R_PPC64_TOC16_HA:
+                   case R_PPC64_TOC16_DS:
+                   case R_PPC64_TOC16_LO_DS:
+                   case R_PPC64_ADDR64:
+                     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_ret;
+
+                 if (sym_sec != toc || h != NULL || sym->st_value != 0)
+                   continue;
+
+                 rel->r_addend -= skip[rel->r_addend >> 3];
+               }
+           }
+
+         /* We shouldn't have local or global symbols defined in the TOC,
+            but handle them anyway.  */
+         if (local_syms != NULL)
+           {
+             Elf_Internal_Sym *sym;
+
+             for (sym = local_syms;
+                  sym < local_syms + symtab_hdr->sh_info;
+                  ++sym)
+               if (sym->st_shndx != SHN_UNDEF
+                   && (sym->st_shndx < SHN_LORESERVE
+                       || sym->st_shndx > SHN_HIRESERVE)
+                   && sym->st_value != 0
+                   && bfd_section_from_elf_index (ibfd, sym->st_shndx) == toc)
+                 {
+                   if (skip[sym->st_value >> 3] != (unsigned long) -1)
+                     sym->st_value -= skip[sym->st_value >> 3];
+                   else
+                     {
+                       (*_bfd_error_handler)
+                         (_("%s defined in removed toc entry"),
+                          bfd_elf_local_sym_name (ibfd, sym));
+                       sym->st_value = 0;
+                       sym->st_shndx = SHN_ABS;
+                     }
+                   symtab_hdr->contents = (unsigned char *) local_syms;
+                 }
+           }
+
+         /* Finally, adjust any global syms defined in the toc.  */
+         if (toc_inf.global_toc_syms)
+           {
+             toc_inf.toc = toc;
+             toc_inf.skip = skip;
+             toc_inf.global_toc_syms = FALSE;
+             elf_link_hash_traverse (elf_hash_table (info), adjust_toc_syms,
+                                     &toc_inf);
+           }
+       }
+
+      if (local_syms != NULL
+         && symtab_hdr->contents != (unsigned char *) local_syms)
+       {
+         if (!info->keep_memory)
+           free (local_syms);
+         else
+           symtab_hdr->contents = (unsigned char *) local_syms;
+       }
+      free (skip);
+    }
+
+  return TRUE;
+}
+
 /* Allocate space in .plt, .got and associated reloc sections for
    dynamic relocs.  */
 
@@ -6683,13 +7145,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;
@@ -6727,14 +7189,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;
@@ -6801,14 +7263,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;
@@ -7537,10 +7999,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;
        }
     }
 
@@ -8403,10 +8866,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;
@@ -9322,8 +9786,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
              {
@@ -9642,9 +10105,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;
@@ -9897,7 +10360,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'"),
@@ -9939,7 +10402,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;
            }
@@ -10035,7 +10499,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;
This page took 0.038339 seconds and 4 git commands to generate.