]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
Apply from mainline.
authorAlan Modra <amodra@gmail.com>
Tue, 10 May 2005 00:42:00 +0000 (00:42 +0000)
committerAlan Modra <amodra@gmail.com>
Tue, 10 May 2005 00:42:00 +0000 (00:42 +0000)
2005-05-09  Alan Modra  <amodra@bigpond.net.au>
* elf64-ppc.c (struct ppc64_elf_obj_tdata): Add has_dotsym.
(ppc64_elf_add_symbol_hook): Set has_dotsym.
(ppc64_elf_check_directives): Only process syms when has_dotsym.
(func_desc_adjust): Hide fake function descriptors when function
code entry is defined.
(adjust_opd_syms): Adjust for deleted_section becoming union field.

2005-04-05  Alan Modra  <amodra@bigpond.net.au>
* elf64-ppc.c (dec_dynrel_count): New function split out from
ppc64_elf_edit_toc, with additional code from ppc64_elf_edit_opd.
(ppc64_elf_edit_toc, ppc64_elf_edit_opd): Use it.
(ppc64_elf_tls_optimize): Likewise.

2005-04-01  Alan Modra  <amodra@bigpond.net.au>
* elf64-ppc.c (ppc64_elf_edit_toc): Account for dynamic relocs
that we no longer need.

bfd/ChangeLog
bfd/elf64-ppc.c

index afa80b2e9446b402299f87f544f13b90c786355c..15dc99ee98f18e58e2eb5768bc798803cdadff2e 100644 (file)
@@ -1,3 +1,24 @@
+2005-05-10  Alan Modra  <amodra@bigpond.net.au>
+
+       Apply from mainline.
+       2005-05-09  Alan Modra  <amodra@bigpond.net.au>
+       * elf64-ppc.c (struct ppc64_elf_obj_tdata): Add has_dotsym.
+       (ppc64_elf_add_symbol_hook): Set has_dotsym.
+       (ppc64_elf_check_directives): Only process syms when has_dotsym.
+       (func_desc_adjust): Hide fake function descriptors when function
+       code entry is defined.
+       (adjust_opd_syms): Adjust for deleted_section becoming union field.
+
+       2005-04-05  Alan Modra  <amodra@bigpond.net.au>
+       * elf64-ppc.c (dec_dynrel_count): New function split out from
+       ppc64_elf_edit_toc, with additional code from ppc64_elf_edit_opd.
+       (ppc64_elf_edit_toc, ppc64_elf_edit_opd): Use it.
+       (ppc64_elf_tls_optimize): Likewise.
+
+       2005-04-01  Alan Modra  <amodra@bigpond.net.au>
+       * elf64-ppc.c (ppc64_elf_edit_toc): Account for dynamic relocs
+       that we no longer need.
+
 2005-05-02  Daniel Jacobowitz  <dan@codesourcery.com>
 
        * Makefile.am: Clear RELEASE.
index 9377564b1e265c1c40ff70cf100ff2e5a1857040..69afd3a65f73ec4cda8154662818fa537affdeee 100644 (file)
@@ -2370,9 +2370,14 @@ struct ppc64_elf_obj_tdata
   asection *got;
   asection *relgot;
 
-  /* Used during garbage collection.  We attach global symbols defined
-     on removed .opd entries to this section so that the sym is removed.  */
-  asection *deleted_section;
+  union {
+    /* Used during garbage collection.  We attach global symbols defined
+       on removed .opd entries to this section so that the sym is removed.  */
+    asection *deleted_section;
+
+    /* Used when adding symbols.  */
+    bfd_boolean has_dotsym;
+  } u;
 
   /* TLS local dynamic got entry handling.  Suppose for multiple GOT
      sections means we potentially need one of these for each input bfd.  */
@@ -2709,7 +2714,7 @@ ppc64_elf_get_synthetic_symtab (bfd *abfd,
       long j;
       /* Trim duplicate syms, since we may have merged the normal and
         dynamic symbols.  Actually, we only care about syms that have
-        different values, so trim any with the same value.  */ 
+        different values, so trim any with the same value.  */
       for (i = 1, j = 1; i < symcount; ++i)
        if (syms[i - 1]->value + syms[i - 1]->section->vma
            != syms[i]->value + syms[i]->section->vma)
@@ -3998,10 +4003,10 @@ make_fdh (struct bfd_link_info *info,
    function type.  */
 
 static bfd_boolean
-ppc64_elf_add_symbol_hook (bfd *ibfd ATTRIBUTE_UNUSED,
+ppc64_elf_add_symbol_hook (bfd *ibfd,
                           struct bfd_link_info *info ATTRIBUTE_UNUSED,
                           Elf_Internal_Sym *isym,
-                          const char **name ATTRIBUTE_UNUSED,
+                          const char **name,
                           flagword *flags ATTRIBUTE_UNUSED,
                           asection **sec,
                           bfd_vma *value ATTRIBUTE_UNUSED)
@@ -4009,6 +4014,13 @@ ppc64_elf_add_symbol_hook (bfd *ibfd ATTRIBUTE_UNUSED,
   if (*sec != NULL
       && strcmp (bfd_get_section_name (ibfd, *sec), ".opd") == 0)
     isym->st_info = ELF_ST_INFO (ELF_ST_BIND (isym->st_info), STT_FUNC);
+
+  if ((*name)[0] == '.'
+      && ELF_ST_BIND (isym->st_info) == STB_GLOBAL
+      && ELF_ST_TYPE (isym->st_info) < STT_SECTION
+      && is_ppc64_elf_target (ibfd->xvec))
+    ppc64_elf_tdata (ibfd)->u.has_dotsym = 1;
+
   return TRUE;
 }
 
@@ -4122,12 +4134,18 @@ add_symbol_adjust (struct elf_link_hash_entry *h, void *inf)
 }
 
 static bfd_boolean
-ppc64_elf_check_directives (bfd *abfd ATTRIBUTE_UNUSED,
-                           struct bfd_link_info *info)
+ppc64_elf_check_directives (bfd *abfd, struct bfd_link_info *info)
 {
   struct ppc_link_hash_table *htab;
   struct add_symbol_adjust_data data;
 
+  if (!is_ppc64_elf_target (abfd->xvec))
+    return TRUE;
+
+  if (!ppc64_elf_tdata (abfd)->u.has_dotsym)
+    return TRUE;
+  ppc64_elf_tdata (abfd)->u.deleted_section = NULL;
+
   htab = ppc_hash_table (info);
   if (!is_ppc64_elf_target (htab->elf.root.creator))
     return TRUE;
@@ -4768,7 +4786,7 @@ opd_entry_value (asection *opd_sec,
 
       if (!bfd_get_section_contents (opd_bfd, opd_sec, &val, offset, 8))
        return (bfd_vma) -1;
-      
+
       if (code_sec != NULL)
        {
          asection *sec, *likely = NULL;
@@ -5446,15 +5464,25 @@ func_desc_adjust (struct elf_link_hash_entry *h, void *inf)
     }
 
   /* Fake function descriptors are made undefweak.  If the function
-     code symbol is strong undefined, make the fake sym the same.  */
+     code symbol is strong undefined, make the fake sym the same.
+     If the function code symbol is defined, then force the fake
+     descriptor local;  We can't support overriding of symbols in a
+     shared library on a fake descriptor.  */
 
   if (fdh != NULL
       && fdh->fake
-      && fdh->elf.root.type == bfd_link_hash_undefweak
-      && fh->elf.root.type == bfd_link_hash_undefined)
+      && fdh->elf.root.type == bfd_link_hash_undefweak)
     {
-      fdh->elf.root.type = bfd_link_hash_undefined;
-      bfd_link_add_undef (&htab->elf.root, &fdh->elf.root);
+      if (fh->elf.root.type == bfd_link_hash_undefined)
+       {
+         fdh->elf.root.type = bfd_link_hash_undefined;
+         bfd_link_add_undef (&htab->elf.root, &fdh->elf.root);
+       }
+      else if (fh->elf.root.type == bfd_link_hash_defined
+              || fh->elf.root.type == bfd_link_hash_defweak)
+       {
+         _bfd_elf_link_hash_hide_symbol (info, &fdh->elf, TRUE);
+       }
     }
 
   if (fdh != NULL
@@ -5931,13 +5959,13 @@ adjust_opd_syms (struct elf_link_hash_entry *h, void *inf ATTRIBUTE_UNUSED)
       if (adjust == -1)
        {
          /* This entry has been deleted.  */
-         asection *dsec = ppc64_elf_tdata (sym_sec->owner)->deleted_section;
+         asection *dsec = ppc64_elf_tdata (sym_sec->owner)->u.deleted_section;
          if (dsec == NULL)
            {
              for (dsec = sym_sec->owner->sections; dsec; dsec = dsec->next)
                if (elf_discarded_section (dsec))
                  {
-                   ppc64_elf_tdata (sym_sec->owner)->deleted_section = dsec;
+                   ppc64_elf_tdata (sym_sec->owner)->u.deleted_section = dsec;
                    break;
                  }
            }
@@ -5951,6 +5979,125 @@ adjust_opd_syms (struct elf_link_hash_entry *h, void *inf ATTRIBUTE_UNUSED)
   return TRUE;
 }
 
+/* Handles decrementing dynamic reloc counts for the reloc specified by
+   R_INFO in section SEC.  If LOCAL_SYMS is NULL, then H and SYM_SEC
+   have already been determined.  */
+
+static bfd_boolean
+dec_dynrel_count (bfd_vma r_info,
+                 asection *sec,
+                 struct bfd_link_info *info,
+                 Elf_Internal_Sym **local_syms,
+                 struct elf_link_hash_entry *h,
+                 asection *sym_sec)
+{
+  enum elf_ppc64_reloc_type r_type;
+  struct ppc_dyn_relocs *p;
+  struct ppc_dyn_relocs **pp;
+
+  /* Can this reloc be dynamic?  This switch, and later tests here
+     should be kept in sync with the code in check_relocs.  */
+  r_type = ELF64_R_TYPE (r_info);
+  switch (r_type)
+    {
+    default:
+      return TRUE;
+
+    case R_PPC64_TPREL16:
+    case R_PPC64_TPREL16_LO:
+    case R_PPC64_TPREL16_HI:
+    case R_PPC64_TPREL16_HA:
+    case R_PPC64_TPREL16_DS:
+    case R_PPC64_TPREL16_LO_DS:
+    case R_PPC64_TPREL16_HIGHER:
+    case R_PPC64_TPREL16_HIGHERA:
+    case R_PPC64_TPREL16_HIGHEST:
+    case R_PPC64_TPREL16_HIGHESTA:
+      if (!info->shared)
+       return TRUE;
+
+    case R_PPC64_TPREL64:
+    case R_PPC64_DTPMOD64:
+    case R_PPC64_DTPREL64:
+    case R_PPC64_ADDR64:
+    case R_PPC64_REL30:
+    case R_PPC64_REL32:
+    case R_PPC64_REL64:
+    case R_PPC64_ADDR14:
+    case R_PPC64_ADDR14_BRNTAKEN:
+    case R_PPC64_ADDR14_BRTAKEN:
+    case R_PPC64_ADDR16:
+    case R_PPC64_ADDR16_DS:
+    case R_PPC64_ADDR16_HA:
+    case R_PPC64_ADDR16_HI:
+    case R_PPC64_ADDR16_HIGHER:
+    case R_PPC64_ADDR16_HIGHERA:
+    case R_PPC64_ADDR16_HIGHEST:
+    case R_PPC64_ADDR16_HIGHESTA:
+    case R_PPC64_ADDR16_LO:
+    case R_PPC64_ADDR16_LO_DS:
+    case R_PPC64_ADDR24:
+    case R_PPC64_ADDR32:
+    case R_PPC64_UADDR16:
+    case R_PPC64_UADDR32:
+    case R_PPC64_UADDR64:
+    case R_PPC64_TOC:
+      break;
+    }
+
+  if (local_syms != NULL)
+    {
+      unsigned long r_symndx;
+      Elf_Internal_Sym *sym;
+      bfd *ibfd = sec->owner;
+
+      r_symndx = ELF64_R_SYM (r_info);
+      if (!get_sym_h (&h, &sym, &sym_sec, NULL, local_syms, r_symndx, ibfd))
+       return FALSE;
+    }
+
+  if ((info->shared
+       && (MUST_BE_DYN_RELOC (r_type)
+          || (h != NULL
+              && (!info->symbolic
+                  || h->root.type == bfd_link_hash_defweak
+                  || !h->def_regular))))
+      || (ELIMINATE_COPY_RELOCS
+         && !info->shared
+         && h != NULL
+         && (h->root.type == bfd_link_hash_defweak
+             || !h->def_regular)))
+    ;
+  else
+    return TRUE;
+
+  if (h != NULL)
+    pp = &((struct ppc_link_hash_entry *) h)->dyn_relocs;
+  else if (sym_sec != NULL)
+    pp = (struct ppc_dyn_relocs **) &elf_section_data (sym_sec)->local_dynrel;
+  else
+    pp = (struct ppc_dyn_relocs **) &elf_section_data (sec)->local_dynrel;
+
+  while ((p = *pp) != NULL)
+    {
+      if (p->sec == sec)
+       {
+         if (!MUST_BE_DYN_RELOC (r_type))
+           p->pc_count -= 1;
+         p->count -= 1;
+         if (p->count == 0)
+           *pp = p->next;
+         return TRUE;
+       }
+      pp = &p->next;
+    }
+
+  (*_bfd_error_handler) (_("dynreloc miscount for %B, section %A"),
+                          sec->owner, sec);
+  bfd_set_error (bfd_error_bad_value);
+  return FALSE;
+}
+
 /* Remove unused Official Procedure Descriptor entries.  Currently we
    only remove those associated with functions in discarded link-once
    sections, or weakly defined functions that have been overridden.  It
@@ -6271,33 +6418,9 @@ ppc64_elf_edit_opd (bfd *obfd, struct bfd_link_info *info,
 
              if (skip)
                {
-                 BFD_ASSERT (MUST_BE_DYN_RELOC (ELF64_R_TYPE (rel->r_info)));
-                 if (info->shared)
-                   {
-                     /* We won't be needing dynamic relocs here.  */
-                     struct ppc_dyn_relocs **pp;
-                     struct ppc_dyn_relocs *p;
-
-                     if (h != NULL)
-                       pp = &((struct ppc_link_hash_entry *) h)->dyn_relocs;
-                     else if (sym_sec != NULL)
-                       pp = ((struct ppc_dyn_relocs **)
-                             &elf_section_data (sym_sec)->local_dynrel);
-                     else
-                       pp = ((struct ppc_dyn_relocs **)
-                             &elf_section_data (sec)->local_dynrel);
-                     while ((p = *pp) != NULL)
-                       {
-                         if (p->sec == sec)
-                           {
-                             p->count -= 1;
-                             if (p->count == 0)
-                               *pp = p->next;
-                             break;
-                           }
-                         pp = &p->next;
-                       }
-                   }
+                 if (!dec_dynrel_count (rel->r_info, sec, info,
+                                        NULL, h, sym_sec))
+                   goto error_ret;
                }
              else
                {
@@ -6668,29 +6791,20 @@ ppc64_elf_tls_optimize (bfd *obfd ATTRIBUTE_UNUSED, struct bfd_link_info *info)
                          ent->got.refcount -= 1;
                      }
                  }
-               else if (h != NULL)
+               else
                  {
-                   struct ppc_link_hash_entry * eh;
-                   struct ppc_dyn_relocs **pp;
-                   struct ppc_dyn_relocs *p;
-
-                   /* Adjust dynamic relocs.  */
-                   eh = (struct ppc_link_hash_entry *) h;
-                   for (pp = &eh->dyn_relocs;
-                        (p = *pp) != NULL;
-                        pp = &p->next)
-                     if (p->sec == sec)
-                       {
-                         /* If we got rid of a DTPMOD/DTPREL reloc
-                            pair then we'll lose one or two dyn
-                            relocs.  */
-                         if (tls_set == (TLS_EXPLICIT | TLS_GD))
-                           p->count -= 1;
-                         p->count -= 1;
-                         if (p->count == 0)
-                           *pp = p->next;
-                         break;
-                       }
+                   /* If we got rid of a DTPMOD/DTPREL reloc pair then
+                      we'll lose one or two dyn relocs.  */
+                   if (!dec_dynrel_count (rel->r_info, sec, info,
+                                          NULL, h, sym_sec))
+                     return FALSE;
+
+                   if (tls_set == (TLS_EXPLICIT | TLS_GD))
+                     {
+                       if (!dec_dynrel_count ((rel + 1)->r_info, sec, info,
+                                              NULL, h, sym_sec))
+                         return FALSE;
+                     }
                  }
 
                *tls_mask |= tls_set;
@@ -7056,6 +7170,10 @@ ppc64_elf_edit_toc (bfd *obfd ATTRIBUTE_UNUSED, struct bfd_link_info *info)
                    wrel->r_addend = rel->r_addend;
                    ++wrel;
                  }
+               else if (!dec_dynrel_count (rel->r_info, toc, info,
+                                           &local_syms, NULL, NULL))
+                 goto error_ret;
+
              toc->reloc_count = wrel - relstart;
              sz = elf_section_data (toc)->rel_hdr.sh_entsize;
              elf_section_data (toc)->rel_hdr.sh_size = toc->reloc_count * sz;