* elf.c (bfd_section_from_r_symndx): Test for SHN_UNDEF.
authorAlan Modra <amodra@gmail.com>
Thu, 31 Jul 2003 14:34:13 +0000 (14:34 +0000)
committerAlan Modra <amodra@gmail.com>
Thu, 31 Jul 2003 14:34:13 +0000 (14:34 +0000)
* elf64-ppc.c (get_fdh): New function, split out from
ppc64_elf_edit_opd.
(ppc64_elf_check_relocs): Use get_fdh.
(func_desc_adjust): Likewise.  Tidy.
(ppc64_elf_edit_opd): Tighten reloc checks.  Free local_syms on error
exit.  Use get_fdh.  Account for superfluous dynamic relocs.
(ppc64_elf_relocate_section): Warning fix.

bfd/ChangeLog
bfd/elf.c
bfd/elf64-ppc.c

index aef89d9e213a64e33eb34bdc8ffd64808b596cdb..5a7116f8d9ed81e15f49dfaec48fe9adec89c783 100644 (file)
@@ -1,3 +1,14 @@
+2003-07-30  Alan Modra  <amodra@bigpond.net.au>
+
+       * elf.c (bfd_section_from_r_symndx): Test for SHN_UNDEF.
+       * elf64-ppc.c (get_fdh): New function, split out from
+       ppc64_elf_edit_opd.
+       (ppc64_elf_check_relocs): Use get_fdh.
+       (func_desc_adjust): Likewise.  Tidy.
+       (ppc64_elf_edit_opd): Tighten reloc checks.  Free local_syms on error
+       exit.  Use get_fdh.  Account for superfluous dynamic relocs.
+       (ppc64_elf_relocate_section): Warning fix.
+
 2003-07-30  Jason Eckhardt  <jle@rice.edu>
 
        * coff-i860.c: Convert to ISO C90.  Remove superflous prototypes.
index b03e7edb5e0c836e30d48f5d44377a5e1e104d04..f97d507dbb97f3ed74073db2cc403459db12dc4f 100644 (file)
--- a/bfd/elf.c
+++ b/bfd/elf.c
@@ -1995,7 +1995,8 @@ bfd_section_from_r_symndx (bfd *abfd,
     }
   cache->indx[ent] = r_symndx;
   cache->sec[ent] = sec;
-  if (isym.st_shndx < SHN_LORESERVE || isym.st_shndx > SHN_HIRESERVE)
+  if ((isym.st_shndx != SHN_UNDEF && isym.st_shndx < SHN_LORESERVE)
+      || isym.st_shndx > SHN_HIRESERVE)
     {
       asection *s;
       s = bfd_section_from_elf_index (abfd, isym.st_shndx);
index 07ba432c4ee996bc59ea4673ff509a55acc5db15..50cb5d878a9df02aba3c6b1c1766ebc9ce5147b5 100644 (file)
@@ -3509,6 +3509,31 @@ update_plt_info (bfd *abfd, struct ppc_link_hash_entry *eh, bfd_vma addend)
   return TRUE;
 }
 
+/* Find the function descriptor hash entry from the given function code
+   hash entry FH.  Link the entries via their OH fields.  */
+static struct ppc_link_hash_entry *
+get_fdh (struct ppc_link_hash_entry *fh, struct ppc_link_hash_table *htab)
+{
+  struct ppc_link_hash_entry *fdh = (struct ppc_link_hash_entry *) fh->oh;
+
+  if (fdh == NULL)
+    {
+      const char *fd_name = fh->elf.root.root.string + 1;
+
+      fdh = (struct ppc_link_hash_entry *)
+       elf_link_hash_lookup (&htab->elf, fd_name, FALSE, FALSE, FALSE);
+      if (fdh != NULL)
+       {
+         fdh->is_func_descriptor = 1;
+         fdh->oh = &fh->elf;
+         fh->is_func = 1;
+         fh->oh = &fdh->elf;
+       }
+    }
+
+  return fdh;
+}
+
 /* Look through the relocs for a section during the first phase, and
    calculate needed space in the global offset table, procedure
    linkage table, and dynamic reloc sections.  */
@@ -3837,19 +3862,8 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
              && h != NULL
              && h->root.root.string[0] == '.'
              && h->root.root.string[1] != 0)
-           {
-             struct elf_link_hash_entry *fdh;
+           get_fdh ((struct ppc_link_hash_entry *) h, htab);
 
-             fdh = elf_link_hash_lookup (&htab->elf, h->root.root.string + 1,
-                                         FALSE, FALSE, FALSE);
-             if (fdh != NULL)
-               {
-                 ((struct ppc_link_hash_entry *) fdh)->is_func_descriptor = 1;
-                 ((struct ppc_link_hash_entry *) fdh)->oh = h;
-                 ((struct ppc_link_hash_entry *) h)->is_func = 1;
-                 ((struct ppc_link_hash_entry *) h)->oh = fdh;
-               }
-           }
          if (opd_sym_map != NULL
              && h == NULL
              && rel + 1 < rel_end
@@ -4247,117 +4261,118 @@ func_desc_adjust (struct elf_link_hash_entry *h, void *inf)
   struct bfd_link_info *info;
   struct ppc_link_hash_table *htab;
   struct plt_entry *ent;
+  struct ppc_link_hash_entry *fh;
+  struct ppc_link_hash_entry *fdh;
+  bfd_boolean force_local;
 
-  if (h->root.type == bfd_link_hash_indirect)
+  fh = (struct ppc_link_hash_entry *) h;
+  if (fh->elf.root.type == bfd_link_hash_indirect)
     return TRUE;
 
-  if (h->root.type == bfd_link_hash_warning)
-    h = (struct elf_link_hash_entry *) h->root.u.i.link;
+  if (fh->elf.root.type == bfd_link_hash_warning)
+    fh = (struct ppc_link_hash_entry *) fh->elf.root.u.i.link;
 
   info = inf;
   htab = ppc_hash_table (info);
 
   /* If this is a function code symbol, transfer dynamic linking
      information to the function descriptor symbol.  */
-  if (!((struct ppc_link_hash_entry *) h)->is_func)
+  if (!fh->is_func)
     return TRUE;
 
-  if (h->root.type == bfd_link_hash_undefweak
-      && (h->elf_link_hash_flags & ELF_LINK_HASH_REF_REGULAR))
+  if (fh->elf.root.type == bfd_link_hash_undefweak
+      && (fh->elf.elf_link_hash_flags & ELF_LINK_HASH_REF_REGULAR))
     htab->have_undefweak = TRUE;
 
-  for (ent = h->plt.plist; ent != NULL; ent = ent->next)
+  for (ent = fh->elf.plt.plist; ent != NULL; ent = ent->next)
     if (ent->plt.refcount > 0)
       break;
-  if (ent != NULL
-      && h->root.root.string[0] == '.'
-      && h->root.root.string[1] != '\0')
-    {
-      struct elf_link_hash_entry *fdh = ((struct ppc_link_hash_entry *) h)->oh;
-      bfd_boolean force_local;
+  if (ent == NULL
+      || fh->elf.root.root.string[0] != '.'
+      || fh->elf.root.root.string[1] == '\0')
+    return TRUE;
 
-      /* Find the corresponding function descriptor symbol.  Create it
-        as undefined if necessary.  */
+  /* Find the corresponding function descriptor symbol.  Create it
+     as undefined if necessary.  */
 
-      if (fdh == NULL)
-       fdh = elf_link_hash_lookup (&htab->elf, h->root.root.string + 1,
-                                   FALSE, FALSE, TRUE);
+  fdh = get_fdh (fh, htab);
+  if (fdh != NULL)
+    while (fdh->elf.root.type == bfd_link_hash_indirect
+          || fdh->elf.root.type == bfd_link_hash_warning)
+      fdh = (struct ppc_link_hash_entry *) fdh->elf.root.u.i.link;
 
-      if (fdh == NULL
-         && info->shared
-         && (h->root.type == bfd_link_hash_undefined
-             || h->root.type == bfd_link_hash_undefweak))
+  if (fdh == NULL
+      && info->shared
+      && (fh->elf.root.type == bfd_link_hash_undefined
+         || fh->elf.root.type == bfd_link_hash_undefweak))
+    {
+      bfd *abfd;
+      asymbol *newsym;
+      struct bfd_link_hash_entry *bh;
+
+      abfd = fh->elf.root.u.undef.abfd;
+      newsym = bfd_make_empty_symbol (abfd);
+      newsym->name = fh->elf.root.root.string + 1;
+      newsym->section = bfd_und_section_ptr;
+      newsym->value = 0;
+      newsym->flags = BSF_OBJECT;
+      if (fh->elf.root.type == bfd_link_hash_undefweak)
+       newsym->flags |= BSF_WEAK;
+
+      bh = &fdh->elf.root;
+      if ( !(_bfd_generic_link_add_one_symbol
+            (info, abfd, newsym->name, newsym->flags,
+             newsym->section, newsym->value, NULL, FALSE, FALSE, &bh)))
        {
-         bfd *abfd;
-         asymbol *newsym;
-         struct bfd_link_hash_entry *bh;
-
-         abfd = h->root.u.undef.abfd;
-         newsym = bfd_make_empty_symbol (abfd);
-         newsym->name = h->root.root.string + 1;
-         newsym->section = bfd_und_section_ptr;
-         newsym->value = 0;
-         newsym->flags = BSF_OBJECT;
-         if (h->root.type == bfd_link_hash_undefweak)
-           newsym->flags |= BSF_WEAK;
-
-         bh = &fdh->root;
-         if ( !(_bfd_generic_link_add_one_symbol
-                (info, abfd, newsym->name, newsym->flags,
-                 newsym->section, newsym->value, NULL, FALSE, FALSE, &bh)))
-           {
-             return FALSE;
-           }
-         fdh = (struct elf_link_hash_entry *) bh;
-         fdh->elf_link_hash_flags &= ~ELF_LINK_NON_ELF;
-         fdh->size = 24;
-         fdh->type = STT_OBJECT;
+         return FALSE;
        }
+      fdh = (struct ppc_link_hash_entry *) bh;
+      fdh->elf.elf_link_hash_flags &= ~ELF_LINK_NON_ELF;
+      fdh->elf.size = 24;
+      fdh->elf.type = STT_OBJECT;
+    }
 
-      if (fdh != NULL
-         && (fdh->elf_link_hash_flags & ELF_LINK_FORCED_LOCAL) == 0
-         && (info->shared
-             || (fdh->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC) != 0
-             || (fdh->elf_link_hash_flags & ELF_LINK_HASH_REF_DYNAMIC) != 0
-             || (fdh->root.type == bfd_link_hash_undefweak
-                 && ELF_ST_VISIBILITY (fdh->other) == STV_DEFAULT)))
+  if (fdh != NULL
+      && (fdh->elf.elf_link_hash_flags & ELF_LINK_FORCED_LOCAL) == 0
+      && (info->shared
+         || (fdh->elf.elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC) != 0
+         || (fdh->elf.elf_link_hash_flags & ELF_LINK_HASH_REF_DYNAMIC) != 0
+         || (fdh->elf.root.type == bfd_link_hash_undefweak
+             && ELF_ST_VISIBILITY (fdh->elf.other) == STV_DEFAULT)))
+    {
+      if (fdh->elf.dynindx == -1)
+       if (! bfd_elf64_link_record_dynamic_symbol (info, &fdh->elf))
+         return FALSE;
+      fdh->elf.elf_link_hash_flags
+       |= (fh->elf.elf_link_hash_flags & (ELF_LINK_HASH_REF_REGULAR
+                                     | ELF_LINK_HASH_REF_DYNAMIC
+                                     | ELF_LINK_HASH_REF_REGULAR_NONWEAK
+                                     | ELF_LINK_NON_GOT_REF));
+      if (ELF_ST_VISIBILITY (fh->elf.other) == STV_DEFAULT)
        {
-         if (fdh->dynindx == -1)
-           if (! bfd_elf64_link_record_dynamic_symbol (info, fdh))
-             return FALSE;
-         fdh->elf_link_hash_flags |= (h->elf_link_hash_flags
-                                      & (ELF_LINK_HASH_REF_REGULAR
-                                         | ELF_LINK_HASH_REF_DYNAMIC
-                                         | ELF_LINK_HASH_REF_REGULAR_NONWEAK
-                                         | ELF_LINK_NON_GOT_REF));
-         if (ELF_ST_VISIBILITY (h->other) == STV_DEFAULT)
-           {
-             fdh->plt.plist = h->plt.plist;
-             fdh->elf_link_hash_flags |= ELF_LINK_HASH_NEEDS_PLT;
-           }
-         ((struct ppc_link_hash_entry *) fdh)->is_func_descriptor = 1;
-         ((struct ppc_link_hash_entry *) fdh)->oh = h;
-         ((struct ppc_link_hash_entry *) h)->oh = fdh;
+         fdh->elf.plt.plist = fh->elf.plt.plist;
+         fdh->elf.elf_link_hash_flags |= ELF_LINK_HASH_NEEDS_PLT;
        }
-
-      /* Now that the info is on the function descriptor, clear the
-        function code sym info.  Any function code syms for which we
-        don't have a definition in a regular file, we force local.
-        This prevents a shared library from exporting syms that have
-        been imported from another library.  Function code syms that
-        are really in the library we must leave global to prevent the
-        linker dragging in a definition from a static library.  */
-      force_local = (info->shared
-                    && ((h->elf_link_hash_flags
-                         & ELF_LINK_HASH_DEF_REGULAR) == 0
-                        || fdh == NULL
-                        || (fdh->elf_link_hash_flags
-                            & ELF_LINK_HASH_DEF_REGULAR) == 0
-                        || (fdh->elf_link_hash_flags
-                            & ELF_LINK_FORCED_LOCAL) != 0));
-      _bfd_elf_link_hash_hide_symbol (info, h, force_local);
+      fdh->is_func_descriptor = 1;
+      fdh->oh = &fh->elf;
+      fh->oh = &fdh->elf;
     }
 
+  /* Now that the info is on the function descriptor, clear the
+     function code sym info.  Any function code syms for which we
+     don't have a definition in a regular file, we force local.
+     This prevents a shared library from exporting syms that have
+     been imported from another library.  Function code syms that
+     are really in the library we must leave global to prevent the
+     linker dragging in a definition from a static library.  */
+  force_local
+    = (info->shared
+       && ((fh->elf.elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0
+          || fdh == NULL
+          || (fdh->elf.elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0
+          || (fdh->elf.elf_link_hash_flags & ELF_LINK_FORCED_LOCAL) != 0));
+  _bfd_elf_link_hash_hide_symbol (info, &fh->elf, force_local);
+
   return TRUE;
 }
 
@@ -4874,7 +4889,7 @@ ppc64_elf_edit_opd (bfd *obfd, struct bfd_link_info *info)
       need_edit = FALSE;
       offset = 0;
       relend = relstart + sec->reloc_count;
-      for (rel = relstart; rel < relend; rel++)
+      for (rel = relstart; rel < relend; )
        {
          enum elf_ppc64_reloc_type r_type;
          unsigned long r_symndx;
@@ -4885,26 +4900,9 @@ ppc64_elf_edit_opd (bfd *obfd, struct bfd_link_info *info)
          /* .opd contains a regular array of 24 byte entries.  We're
             only interested in the reloc pointing to a function entry
             point.  */
-         r_type = ELF64_R_TYPE (rel->r_info);
-         if (r_type == R_PPC64_TOC)
-           continue;
-
-         if (r_type != R_PPC64_ADDR64)
-           {
-             (*_bfd_error_handler)
-               (_("%s: unexpected reloc type %u in .opd section"),
-                bfd_archive_filename (ibfd), r_type);
-             need_edit = FALSE;
-             break;
-           }
-
-         if (rel + 1 >= relend)
-           continue;
-         r_type = ELF64_R_TYPE ((rel + 1)->r_info);
-         if (r_type != R_PPC64_TOC)
-           continue;
-
-         if (rel->r_offset != offset)
+         if (rel->r_offset != offset
+             || rel + 1 >= relend
+             || (rel + 1)->r_offset != offset + 8)
            {
              /* If someone messes with .opd alignment then after a
                 "ld -r" we might have padding in the middle of .opd.
@@ -4918,10 +4916,20 @@ ppc64_elf_edit_opd (bfd *obfd, struct bfd_link_info *info)
              break;
            }
 
+         if ((r_type = ELF64_R_TYPE (rel->r_info)) != R_PPC64_ADDR64
+             || (r_type = ELF64_R_TYPE ((rel + 1)->r_info)) != R_PPC64_TOC)
+           {
+             (*_bfd_error_handler)
+               (_("%s: unexpected reloc type %u in .opd section"),
+                bfd_archive_filename (ibfd), r_type);
+             need_edit = FALSE;
+             break;
+           }
+
          r_symndx = ELF64_R_SYM (rel->r_info);
          if (!get_sym_h (&h, &sym, &sym_sec, NULL, &local_syms,
                          r_symndx, ibfd))
-           goto error_free_rel;
+           goto error_ret;
 
          if (sym_sec == NULL || sym_sec->owner == NULL)
            {
@@ -4951,6 +4959,11 @@ ppc64_elf_edit_opd (bfd *obfd, struct bfd_link_info *info)
            need_edit = TRUE;
 
          offset += 24;
+         rel += 2;
+         /* Allow for the possibility of a reloc on the third word.  */
+         if (rel < relend
+             && rel->r_offset == offset - 8)
+           rel += 1;
        }
 
       if (need_edit)
@@ -4970,10 +4983,10 @@ ppc64_elf_edit_opd (bfd *obfd, struct bfd_link_info *info)
                  || !bfd_get_section_contents (ibfd, sec, loc, 0,
                                                sec->_raw_size))
                {
+               error_ret:
                  if (local_syms != NULL
                      && symtab_hdr->contents != (unsigned char *) local_syms)
                    free (local_syms);
-               error_free_rel:
                  if (elf_section_data (sec)->relocs != relstart)
                    free (relstart);
                  return FALSE;
@@ -4991,16 +5004,22 @@ ppc64_elf_edit_opd (bfd *obfd, struct bfd_link_info *info)
          offset = 0;
          for (rel = relstart; rel < relend; rel++)
            {
+             unsigned long r_symndx;
+             asection *sym_sec;
+             struct elf_link_hash_entry *h;
+             Elf_Internal_Sym *sym;
+
+             r_symndx = ELF64_R_SYM (rel->r_info);
+             if (!get_sym_h (&h, &sym, &sym_sec, NULL, &local_syms,
+                             r_symndx, ibfd))  
+               goto error_ret;
+
              if (rel->r_offset == offset)
                {
-                 unsigned long r_symndx;
-                 asection *sym_sec;
-                 struct elf_link_hash_entry *h;
-                 Elf_Internal_Sym *sym;
-
-                 r_symndx = ELF64_R_SYM (rel->r_info);
-                 get_sym_h (&h, &sym, &sym_sec, NULL, &local_syms,
-                            r_symndx, ibfd);
+                 struct ppc_link_hash_entry *fdh = NULL;
+                 if (h != NULL)
+                   fdh = get_fdh ((struct ppc_link_hash_entry *) h,
+                                  ppc_hash_table (info));
 
                  skip = (sym_sec->owner != ibfd
                          || sym_sec->output_section == bfd_abs_section_ptr);
@@ -5010,27 +5029,6 @@ ppc64_elf_edit_opd (bfd *obfd, struct bfd_link_info *info)
                        {
                          /* Arrange for the function descriptor sym
                             to be dropped.  */
-                         struct ppc_link_hash_entry *fdh;
-                         struct ppc_link_hash_entry *fh;
-
-                         fh = (struct ppc_link_hash_entry *) h;
-                         fdh = (struct ppc_link_hash_entry *) fh->oh;
-                         if (fdh == NULL)
-                           {
-                             const char *fd_name;
-                             struct ppc_link_hash_table *htab;
-
-                             fd_name = h->root.root.string + 1;
-                             htab = ppc_hash_table (info);
-                             fdh = (struct ppc_link_hash_entry *)
-                               elf_link_hash_lookup (&htab->elf, fd_name,
-                                                     FALSE, FALSE, FALSE);
-                             fdh->is_func_descriptor = 1;
-                             fdh->oh = &fh->elf;
-                             fh->is_func = 1;
-                             fh->oh = &fdh->elf;
-                           }
-
                          fdh->elf.root.u.def.value = 0;
                          fdh->elf.root.u.def.section = sym_sec;
                        }
@@ -5045,27 +5043,6 @@ ppc64_elf_edit_opd (bfd *obfd, struct bfd_link_info *info)
                             to this location in the opd section.
                             We've checked above that opd relocs are
                             ordered.  */
-                         struct ppc_link_hash_entry *fdh;
-                         struct ppc_link_hash_entry *fh;
-
-                         fh = (struct ppc_link_hash_entry *) h;
-                         fdh = (struct ppc_link_hash_entry *) fh->oh;
-                         if (fdh == NULL)
-                           {
-                             const char *fd_name;
-                             struct ppc_link_hash_table *htab;
-
-                             fd_name = h->root.root.string + 1;
-                             htab = ppc_hash_table (info);
-                             fdh = (struct ppc_link_hash_entry *)
-                               elf_link_hash_lookup (&htab->elf, fd_name,
-                                                     FALSE, FALSE, FALSE);
-                             fdh->is_func_descriptor = 1;
-                             fdh->oh = &fh->elf;
-                             fh->is_func = 1;
-                             fh->oh = &fdh->elf;
-                           }
-
                          fdh->elf.root.u.def.value = wptr - sec->contents;
                        }
                      else
@@ -5087,11 +5064,41 @@ ppc64_elf_edit_opd (bfd *obfd, struct bfd_link_info *info)
                  offset += 24;
                }
 
-             /* We need to adjust any reloc offsets to point to the
-                new opd entries.  While we're at it, we may as well
-                remove redundant relocs.  */
-             if (!skip)
+             if (skip)
+               {
+                 BFD_ASSERT (MUST_BE_DYN_RELOC (ELF64_R_TYPE (rel->r_info)));
+                 if (info->shared)
+                   {
+                     /* We won't be needing dynamic relocs here.  */
+                     struct ppc_dyn_relocs **pp;
+                     struct ppc_dyn_relocs *p;
+
+                     if (h != NULL)
+                       pp = &((struct ppc_link_hash_entry *) h)->dyn_relocs;
+                     else if (sym_sec != NULL)
+                       pp = ((struct ppc_dyn_relocs **)
+                             &elf_section_data (sym_sec)->local_dynrel);
+                     else
+                       pp = ((struct ppc_dyn_relocs **)
+                             &elf_section_data (sec)->local_dynrel);
+                     while ((p = *pp) != NULL)
+                       {
+                         if (p->sec == sec)
+                           {
+                             p->count -= 1;
+                             if (p->count == 0)
+                               *pp = p->next;  
+                             break;
+                           }
+                         pp = &p->next;
+                       }
+                   }
+               }
+             else
                {
+                 /* We need to adjust any reloc offsets to point to the
+                    new opd entries.  While we're at it, we may as well
+                    remove redundant relocs.  */
                  rel->r_offset += wptr - rptr;
                  if (write_rel != rel)
                    memcpy (write_rel, rel, sizeof (*rel));
@@ -7282,7 +7289,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
       bfd_vma relocation;
       bfd_boolean unresolved_reloc;
       bfd_boolean warned;
-      long insn, mask;
+      unsigned long insn, mask;
       struct ppc_stub_hash_entry *stub_entry;
       bfd_vma max_br_offset;
       bfd_vma from;
@@ -7437,7 +7444,6 @@ ppc64_elf_relocate_section (bfd *output_bfd,
          if (tls_mask != 0
              && (tls_mask & TLS_TPREL) == 0)
            {
-             bfd_vma insn;
            toctprel:
              insn = bfd_get_32 (output_bfd, contents + rel->r_offset - 2);
              insn &= 31 << 21;
@@ -7463,7 +7469,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
          if (tls_mask != 0
              && (tls_mask & TLS_TPREL) == 0)
            {
-             bfd_vma insn, rtra;
+             bfd_vma rtra;
              insn = bfd_get_32 (output_bfd, contents + rel->r_offset);
              if ((insn & ((0x3f << 26) | (31 << 11)))
                  == ((31 << 26) | (13 << 11)))