* coff-h8300.c: Fix formatting.
[deliverable/binutils-gdb.git] / bfd / elflink.h
index 3cd9e0c49aa6a1b7e82687af472acda1fe5b450f..c116ed5d44aa9de8beac05223cdf4760ff83bb3c 100644 (file)
@@ -149,18 +149,13 @@ elf_link_is_defined_archive_symbol (abfd, symdef)
      carsym * symdef;
 {
   Elf_Internal_Shdr * hdr;
-  Elf_Internal_Shdr * shndx_hdr;
-  Elf_External_Sym *  esym;
-  Elf_External_Sym *  esymend;
-  Elf_External_Sym *  buf = NULL;
-  Elf_External_Sym_Shndx * shndx_buf = NULL;
-  Elf_External_Sym_Shndx * shndx;
   bfd_size_type symcount;
   bfd_size_type extsymcount;
   bfd_size_type extsymoff;
-  boolean result = false;
-  file_ptr pos;
-  bfd_size_type amt;
+  Elf_Internal_Sym *isymbuf;
+  Elf_Internal_Sym *isym;
+  Elf_Internal_Sym *isymend;
+  boolean result;
 
   abfd = _bfd_get_elt_at_filepos (abfd, symdef->file_offset);
   if (abfd == (bfd *) NULL)
@@ -178,15 +173,9 @@ elf_link_is_defined_archive_symbol (abfd, symdef)
 
   /* Select the appropriate symbol table.  */
   if ((abfd->flags & DYNAMIC) == 0 || elf_dynsymtab (abfd) == 0)
-    {
-      hdr = &elf_tdata (abfd)->symtab_hdr;
-      shndx_hdr = &elf_tdata (abfd)->symtab_shndx_hdr;
-    }
+    hdr = &elf_tdata (abfd)->symtab_hdr;
   else
-    {
-      hdr = &elf_tdata (abfd)->dynsymtab_hdr;
-      shndx_hdr = NULL;
-    }
+    hdr = &elf_tdata (abfd)->dynsymtab_hdr;
 
   symcount = hdr->sh_size / sizeof (Elf_External_Sym);
 
@@ -203,58 +192,34 @@ elf_link_is_defined_archive_symbol (abfd, symdef)
       extsymoff = hdr->sh_info;
     }
 
-  amt = extsymcount * sizeof (Elf_External_Sym);
-  buf = (Elf_External_Sym *) bfd_malloc (amt);
-  if (buf == NULL && extsymcount != 0)
+  if (extsymcount == 0)
     return false;
 
-  /* Read in the symbol table.
-     FIXME:  This ought to be cached somewhere.  */
-  pos = hdr->sh_offset + extsymoff * sizeof (Elf_External_Sym);
-  if (bfd_seek (abfd, pos, SEEK_SET) != 0
-      || bfd_bread ((PTR) buf, amt, abfd) != amt)
-    goto error_exit;
-
-  if (shndx_hdr != NULL && shndx_hdr->sh_size != 0)
-    {
-      amt = extsymcount * sizeof (Elf_External_Sym_Shndx);
-      shndx_buf = (Elf_External_Sym_Shndx *) bfd_malloc (amt);
-      if (shndx_buf == NULL && extsymcount != 0)
-       goto error_exit;
-
-      pos = shndx_hdr->sh_offset + extsymoff * sizeof (Elf_External_Sym_Shndx);
-      if (bfd_seek (abfd, pos, SEEK_SET) != 0
-         || bfd_bread ((PTR) shndx_buf, amt, abfd) != amt)
-       goto error_exit;
-    }
+  /* Read in the symbol table.  */
+  isymbuf = bfd_elf_get_elf_syms (abfd, hdr, extsymcount, extsymoff,
+                                 NULL, NULL, NULL);
+  if (isymbuf == NULL)
+    return false;
 
   /* Scan the symbol table looking for SYMDEF.  */
-  esymend = buf + extsymcount;
-  for (esym = buf, shndx = shndx_buf;
-       esym < esymend;
-       esym++, shndx = (shndx != NULL ? shndx + 1 : NULL))
+  result = false;
+  for (isym = isymbuf, isymend = isymbuf + extsymcount; isym < isymend; isym++)
     {
-      Elf_Internal_Sym sym;
-      const char * name;
-
-      elf_swap_symbol_in (abfd, (const PTR) esym, (const PTR) shndx, &sym);
+      const char *name;
 
-      name = bfd_elf_string_from_elf_section (abfd, hdr->sh_link, sym.st_name);
+      name = bfd_elf_string_from_elf_section (abfd, hdr->sh_link,
+                                             isym->st_name);
       if (name == (const char *) NULL)
        break;
 
       if (strcmp (name, symdef->name) == 0)
        {
-         result = is_global_data_symbol_definition (abfd, sym);
+         result = is_global_data_symbol_definition (abfd, isym);
          break;
        }
     }
 
- error_exit:
-  if (shndx_buf != NULL)
-    free (shndx_buf);
-  if (buf != NULL)
-    free (buf);
+  free (isymbuf);
 
   return result;
 }
@@ -353,26 +318,40 @@ elf_link_add_archive_symbols (abfd, info)
          if (h == NULL)
            {
              char *p, *copy;
+             size_t len, first;
 
              /* If this is a default version (the name contains @@),
-                look up the symbol again without the version.  The
-                effect is that references to the symbol without the
-                version will be matched by the default symbol in the
-                archive.  */
+                look up the symbol again with only one `@' as well
+                as without the version.  The effect is that references
+                to the symbol with and without the version will be
+                matched by the default symbol in the archive.  */
 
              p = strchr (symdef->name, ELF_VER_CHR);
              if (p == NULL || p[1] != ELF_VER_CHR)
                continue;
 
-             copy = bfd_alloc (abfd, (bfd_size_type) (p - symdef->name + 1));
+             /* First check with only one `@'.  */
+             len = strlen (symdef->name);
+             copy = bfd_alloc (abfd, (bfd_size_type) len);
              if (copy == NULL)
                goto error_return;
-             memcpy (copy, symdef->name, (size_t) (p - symdef->name));
-             copy[p - symdef->name] = '\0';
+             first = p - symdef->name + 1;
+             memcpy (copy, symdef->name, first);
+             memcpy (copy + first, symdef->name + first + 1, len - first);
 
              h = elf_link_hash_lookup (elf_hash_table (info), copy,
                                        false, false, false);
 
+             if (h == NULL)
+               {
+                 /* We also need to check references to the symbol
+                    without the version.  */
+
+                 copy[first - 1] = '\0';
+                 h = elf_link_hash_lookup (elf_hash_table (info),
+                                           copy, false, false, false);
+               }
+
              bfd_release (abfd, copy);
            }
 
@@ -920,19 +899,19 @@ elf_merge_symbol (abfd, info, name, sym, psec, pvalue, sym_hash,
 
 /* This function is called to create an indirect symbol from the
    default for the symbol with the default version if needed. The
-   symbol is described by H, NAME, SYM, SEC, VALUE, and OVERRIDE.  We
+   symbol is described by H, NAME, SYM, PSEC, VALUE, and OVERRIDE.  We
    set DYNSYM if the new indirect symbol is dynamic. DT_NEEDED
    indicates if it comes from a DT_NEEDED entry of a shared object.  */
 
 static boolean
-elf_add_default_symbol (abfd, info, h, name, sym, sec, value,
+elf_add_default_symbol (abfd, info, h, name, sym, psec, value,
                        dynsym, override, dt_needed)
      bfd *abfd;
      struct bfd_link_info *info;
      struct elf_link_hash_entry *h;
      const char *name;
      Elf_Internal_Sym *sym;
-     asection **sec;
+     asection **psec;
      bfd_vma *value;
      boolean *dynsym;
      boolean override;
@@ -942,10 +921,13 @@ elf_add_default_symbol (abfd, info, h, name, sym, sec, value,
   boolean size_change_ok;
   char *shortname;
   struct elf_link_hash_entry *hi;
+  struct bfd_link_hash_entry *bh;
   struct elf_backend_data *bed;
   boolean collect;
   boolean dynamic;
   char *p;
+  size_t len, shortlen;
+  asection *sec;
 
   /* If this symbol has a version, and it is the default version, we
      create an indirect symbol from the default name to the fully
@@ -958,7 +940,7 @@ elf_add_default_symbol (abfd, info, h, name, sym, sec, value,
   if (override)
     {
       /* We are overridden by an old defition. We need to check if we
-        need to crreate the indirect symbol from the default name.  */
+        need to create the indirect symbol from the default name.  */
       hi = elf_link_hash_lookup (elf_hash_table (info), name, true,
                                 false, false);
       BFD_ASSERT (hi != NULL);
@@ -977,12 +959,12 @@ elf_add_default_symbol (abfd, info, h, name, sym, sec, value,
   collect = bed->collect;
   dynamic = (abfd->flags & DYNAMIC) != 0;
 
-  shortname = bfd_hash_allocate (&info->hash->table,
-                                (size_t) (p - name + 1));
+  shortlen = p - name;
+  shortname = bfd_hash_allocate (&info->hash->table, shortlen + 1);
   if (shortname == NULL)
     return false;
-  strncpy (shortname, name, (size_t) (p - name));
-  shortname [p - name] = '\0';
+  memcpy (shortname, name, shortlen);
+  shortname[shortlen] = '\0';
 
   /* We are going to create a new symbol.  Merge it with any existing
      symbol with this name.  For the purposes of the merge, act as
@@ -990,18 +972,20 @@ elf_add_default_symbol (abfd, info, h, name, sym, sec, value,
      actually going to define an indirect symbol.  */
   type_change_ok = false;
   size_change_ok = false;
-  if (! elf_merge_symbol (abfd, info, shortname, sym, sec, value,
+  sec = *psec;
+  if (! elf_merge_symbol (abfd, info, shortname, sym, &sec, value,
                          &hi, &override, &type_change_ok,
                          &size_change_ok, dt_needed))
     return false;
 
   if (! override)
     {
+      bh = &hi->root;
       if (! (_bfd_generic_link_add_one_symbol
             (info, abfd, shortname, BSF_INDIRECT, bfd_ind_section_ptr,
-             (bfd_vma) 0, name, false, collect,
-             (struct bfd_link_hash_entry **) &hi)))
+             (bfd_vma) 0, name, false, collect, &bh)))
        return false;
+      hi = (struct elf_link_hash_entry *) bh;
     }
   else
     {
@@ -1062,7 +1046,7 @@ elf_add_default_symbol (abfd, info, h, name, sym, sec, value,
                      | ELF_LINK_HASH_DEF_REGULAR)) == 0);
 
       ht = (struct elf_link_hash_entry *) hi->root.u.i.link;
-      (*bed->elf_backend_copy_indirect_symbol) (ht, hi);
+      (*bed->elf_backend_copy_indirect_symbol) (bed, ht, hi);
 
       /* See if the new flags lead us to realize that the symbol must
         be dynamic.  */
@@ -1087,16 +1071,18 @@ elf_add_default_symbol (abfd, info, h, name, sym, sec, value,
   /* We also need to define an indirection from the nondefault version
      of the symbol.  */
 
-  shortname = bfd_hash_allocate (&info->hash->table, strlen (name));
+  len = strlen (name);
+  shortname = bfd_hash_allocate (&info->hash->table, len);
   if (shortname == NULL)
     return false;
-  strncpy (shortname, name, (size_t) (p - name));
-  strcpy (shortname + (p - name), p + 1);
+  memcpy (shortname, name, shortlen);
+  memcpy (shortname + shortlen, p + 1, len - shortlen);
 
   /* Once again, merge with any existing symbol.  */
   type_change_ok = false;
   size_change_ok = false;
-  if (! elf_merge_symbol (abfd, info, shortname, sym, sec, value,
+  sec = *psec;
+  if (! elf_merge_symbol (abfd, info, shortname, sym, &sec, value,
                          &hi, &override, &type_change_ok,
                          &size_change_ok, dt_needed))
     return false;
@@ -1104,18 +1090,22 @@ elf_add_default_symbol (abfd, info, h, name, sym, sec, value,
   if (override)
     {
       /* Here SHORTNAME is a versioned name, so we don't expect to see
-        the type of override we do in the case above.  */
-      (*_bfd_error_handler)
-       (_("%s: warning: unexpected redefinition of `%s'"),
-        bfd_archive_filename (abfd), shortname);
+        the type of override we do in the case above unless it is
+        overridden by a versioned definiton.  */
+      if (hi->root.type != bfd_link_hash_defined
+         && hi->root.type != bfd_link_hash_defweak)
+       (*_bfd_error_handler)
+         (_("%s: warning: unexpected redefinition of indirect versioned symbol `%s'"),
+          bfd_archive_filename (abfd), shortname);
     }
   else
     {
+      bh = &hi->root;
       if (! (_bfd_generic_link_add_one_symbol
             (info, abfd, shortname, BSF_INDIRECT,
-             bfd_ind_section_ptr, (bfd_vma) 0, name, false,
-             collect, (struct bfd_link_hash_entry **) &hi)))
+             bfd_ind_section_ptr, (bfd_vma) 0, name, false, collect, &bh)))
        return false;
+      hi = (struct elf_link_hash_entry *) bh;
 
       /* If there is a duplicate definition somewhere, then HI may not
         point to an indirect symbol.  We will have reported an error
@@ -1129,7 +1119,7 @@ elf_add_default_symbol (abfd, info, h, name, sym, sec, value,
                       & (ELF_LINK_HASH_DEF_DYNAMIC
                          | ELF_LINK_HASH_DEF_REGULAR)) == 0);
 
-         (*bed->elf_backend_copy_indirect_symbol) (h, hi);
+         (*bed->elf_backend_copy_indirect_symbol) (bed, h, hi);
 
          /* See if the new flags lead us to realize that the symbol
             must be dynamic.  */
@@ -1170,25 +1160,20 @@ elf_link_add_object_symbols (abfd, info)
                                   asection *, const Elf_Internal_Rela *));
   boolean collect;
   Elf_Internal_Shdr *hdr;
-  Elf_Internal_Shdr *shndx_hdr;
   bfd_size_type symcount;
   bfd_size_type extsymcount;
   bfd_size_type extsymoff;
-  Elf_External_Sym *buf = NULL;
-  Elf_External_Sym_Shndx *shndx_buf = NULL;
-  Elf_External_Sym_Shndx *shndx;
   struct elf_link_hash_entry **sym_hash;
   boolean dynamic;
   Elf_External_Versym *extversym = NULL;
   Elf_External_Versym *ever;
-  Elf_External_Dyn *dynbuf = NULL;
   struct elf_link_hash_entry *weaks;
-  Elf_External_Sym *esym;
-  Elf_External_Sym *esymend;
+  Elf_Internal_Sym *isymbuf = NULL;
+  Elf_Internal_Sym *isym;
+  Elf_Internal_Sym *isymend;
   struct elf_backend_data *bed;
   boolean dt_needed;
   struct elf_link_hash_table * hash_table;
-  file_ptr pos;
   bfd_size_type amt;
 
   hash_table = elf_hash_table (info);
@@ -1287,85 +1272,7 @@ elf_link_add_object_symbols (abfd, info)
        }
     }
 
-  /* If this is a dynamic object, we always link against the .dynsym
-     symbol table, not the .symtab symbol table.  The dynamic linker
-     will only see the .dynsym symbol table, so there is no reason to
-     look at .symtab for a dynamic object.  */
-
-  if (! dynamic || elf_dynsymtab (abfd) == 0)
-    {
-      hdr = &elf_tdata (abfd)->symtab_hdr;
-      shndx_hdr = &elf_tdata (abfd)->symtab_shndx_hdr;
-    }
-  else
-    {
-      hdr = &elf_tdata (abfd)->dynsymtab_hdr;
-      shndx_hdr = NULL;
-    }
-
-  if (dynamic)
-    {
-      /* Read in any version definitions.  */
-
-      if (! _bfd_elf_slurp_version_tables (abfd))
-       goto error_return;
-
-      /* Read in the symbol versions, but don't bother to convert them
-        to internal format.  */
-      if (elf_dynversym (abfd) != 0)
-       {
-         Elf_Internal_Shdr *versymhdr;
-
-         versymhdr = &elf_tdata (abfd)->dynversym_hdr;
-         extversym = (Elf_External_Versym *) bfd_malloc (versymhdr->sh_size);
-         if (extversym == NULL)
-           goto error_return;
-         amt = versymhdr->sh_size;
-         if (bfd_seek (abfd, versymhdr->sh_offset, SEEK_SET) != 0
-             || bfd_bread ((PTR) extversym, amt, abfd) != amt)
-           goto error_return;
-       }
-    }
-
-  symcount = hdr->sh_size / sizeof (Elf_External_Sym);
-
-  /* The sh_info field of the symtab header tells us where the
-     external symbols start.  We don't care about the local symbols at
-     this point.  */
-  if (elf_bad_symtab (abfd))
-    {
-      extsymcount = symcount;
-      extsymoff = 0;
-    }
-  else
-    {
-      extsymcount = symcount - hdr->sh_info;
-      extsymoff = hdr->sh_info;
-    }
-
-  amt = extsymcount * sizeof (Elf_External_Sym);
-  buf = (Elf_External_Sym *) bfd_malloc (amt);
-  if (buf == NULL && extsymcount != 0)
-    goto error_return;
-
-  if (shndx_hdr != NULL && shndx_hdr->sh_size != 0)
-    {
-      amt = extsymcount * sizeof (Elf_External_Sym_Shndx);
-      shndx_buf = (Elf_External_Sym_Shndx *) bfd_malloc (amt);
-      if (shndx_buf == NULL && extsymcount != 0)
-       goto error_return;
-    }
-
-  /* We store a pointer to the hash table entry for each external
-     symbol.  */
-  amt = extsymcount * sizeof (struct elf_link_hash_entry *);
-  sym_hash = (struct elf_link_hash_entry **) bfd_alloc (abfd, amt);
-  if (sym_hash == NULL)
-    goto error_return;
-  elf_sym_hashes (abfd) = sym_hash;
-
   dt_needed = false;
-
   if (! dynamic)
     {
       /* If we are creating a shared library, create all the dynamic
@@ -1391,6 +1298,14 @@ elf_link_add_object_symbols (abfd, info)
       const char *name;
       bfd_size_type oldsize;
       bfd_size_type strindex;
+      struct bfd_link_needed_list *rpath = NULL, *runpath = NULL;
+
+      /* ld --just-symbols and dynamic objects don't mix very well.
+        Test for --just-symbols by looking at info set up by
+        _bfd_elf_link_just_syms.  */
+      if ((s = abfd->sections) != NULL
+         && elf_section_data (s)->sec_info_type == ELF_INFO_TYPE_JUST_SYMS)
+       goto error_return;
 
       /* Find the name to use in a DT_NEEDED entry that refers to this
         object.  If the object has a DT_SONAME entry, we use it.
@@ -1415,12 +1330,11 @@ elf_link_add_object_symbols (abfd, info)
       s = bfd_get_section_by_name (abfd, ".dynamic");
       if (s != NULL)
        {
+         Elf_External_Dyn *dynbuf = NULL;
          Elf_External_Dyn *extdyn;
          Elf_External_Dyn *extdynend;
          int elfsec;
          unsigned long shlink;
-         int rpath;
-         int runpath;
 
          dynbuf = (Elf_External_Dyn *) bfd_malloc (s->_raw_size);
          if (dynbuf == NULL)
@@ -1428,34 +1342,15 @@ elf_link_add_object_symbols (abfd, info)
 
          if (! bfd_get_section_contents (abfd, s, (PTR) dynbuf,
                                          (file_ptr) 0, s->_raw_size))
-           goto error_return;
+           goto error_free_dyn;
 
          elfsec = _bfd_elf_section_from_bfd_section (abfd, s);
          if (elfsec == -1)
-           goto error_return;
+           goto error_free_dyn;
          shlink = elf_elfsections (abfd)[elfsec]->sh_link;
 
-         {
-           /* The shared libraries distributed with hpux11 have a bogus
-              sh_link field for the ".dynamic" section.  This code detects
-              when SHLINK refers to a section that is not a string table
-              and tries to find the string table for the ".dynsym" section
-              instead.  */
-           Elf_Internal_Shdr *shdr = elf_elfsections (abfd)[shlink];
-           if (shdr->sh_type != SHT_STRTAB)
-             {
-               asection *ds = bfd_get_section_by_name (abfd, ".dynsym");
-               int elfdsec = _bfd_elf_section_from_bfd_section (abfd, ds);
-               if (elfdsec == -1)
-                 goto error_return;
-               shlink = elf_elfsections (abfd)[elfdsec]->sh_link;
-             }
-         }
-
          extdyn = dynbuf;
          extdynend = extdyn + s->_raw_size / sizeof (Elf_External_Dyn);
-         rpath = 0;
-         runpath = 0;
          for (; extdyn < extdynend; extdyn++)
            {
              Elf_Internal_Dyn dyn;
@@ -1466,7 +1361,7 @@ elf_link_add_object_symbols (abfd, info)
                  unsigned int tagv = dyn.d_un.d_val;
                  name = bfd_elf_string_from_elf_section (abfd, shlink, tagv);
                  if (name == NULL)
-                   goto error_return;
+                   goto error_free_dyn;
                }
              if (dyn.d_tag == DT_NEEDED)
                {
@@ -1478,11 +1373,12 @@ elf_link_add_object_symbols (abfd, info)
                  n = (struct bfd_link_needed_list *) bfd_alloc (abfd, amt);
                  fnm = bfd_elf_string_from_elf_section (abfd, shlink, tagv);
                  if (n == NULL || fnm == NULL)
-                   goto error_return;
-                 anm = bfd_alloc (abfd, (bfd_size_type) strlen (fnm) + 1);
+                   goto error_free_dyn;
+                 amt = strlen (fnm) + 1;
+                 anm = bfd_alloc (abfd, amt);
                  if (anm == NULL)
-                   goto error_return;
-                 strcpy (anm, fnm);
+                   goto error_free_dyn;
+                 memcpy (anm, fnm, (size_t) amt);
                  n->name = anm;
                  n->by = abfd;
                  n->next = NULL;
@@ -1498,32 +1394,24 @@ elf_link_add_object_symbols (abfd, info)
                  char *fnm, *anm;
                  unsigned int tagv = dyn.d_un.d_val;
 
-                 /* When we see DT_RPATH before DT_RUNPATH, we have
-                    to clear runpath.  Do _NOT_ bfd_release, as that
-                    frees all more recently bfd_alloc'd blocks as
-                    well.  */
-                 if (rpath && hash_table->runpath)
-                   hash_table->runpath = NULL;
-
                  amt = sizeof (struct bfd_link_needed_list);
                  n = (struct bfd_link_needed_list *) bfd_alloc (abfd, amt);
                  fnm = bfd_elf_string_from_elf_section (abfd, shlink, tagv);
                  if (n == NULL || fnm == NULL)
-                   goto error_return;
-                 anm = bfd_alloc (abfd, (bfd_size_type) strlen (fnm) + 1);
+                   goto error_free_dyn;
+                 amt = strlen (fnm) + 1;
+                 anm = bfd_alloc (abfd, amt);
                  if (anm == NULL)
-                   goto error_return;
-                 strcpy (anm, fnm);
+                   goto error_free_dyn;
+                 memcpy (anm, fnm, (size_t) amt);
                  n->name = anm;
                  n->by = abfd;
                  n->next = NULL;
-                 for (pn = & hash_table->runpath;
+                 for (pn = & runpath;
                       *pn != NULL;
                       pn = &(*pn)->next)
                    ;
                  *pn = n;
-                 runpath = 1;
-                 rpath = 0;
                }
              /* Ignore DT_RPATH if we have seen DT_RUNPATH.  */
              if (!runpath && dyn.d_tag == DT_RPATH)
@@ -1536,25 +1424,43 @@ elf_link_add_object_symbols (abfd, info)
                  n = (struct bfd_link_needed_list *) bfd_alloc (abfd, amt);
                  fnm = bfd_elf_string_from_elf_section (abfd, shlink, tagv);
                  if (n == NULL || fnm == NULL)
-                   goto error_return;
-                 anm = bfd_alloc (abfd, (bfd_size_type) strlen (fnm) + 1);
+                   goto error_free_dyn;
+                 amt = strlen (fnm) + 1;
+                 anm = bfd_alloc (abfd, amt);
                  if (anm == NULL)
-                   goto error_return;
-                 strcpy (anm, fnm);
+                   {
+                   error_free_dyn:
+                     free (dynbuf);
+                     goto error_return;
+                   }
+                 memcpy (anm, fnm, (size_t) amt);
                  n->name = anm;
                  n->by = abfd;
                  n->next = NULL;
-                 for (pn = & hash_table->runpath;
+                 for (pn = & rpath;
                       *pn != NULL;
                       pn = &(*pn)->next)
                    ;
                  *pn = n;
-                 rpath = 1;
                }
            }
 
          free (dynbuf);
-         dynbuf = NULL;
+       }
+
+      /* DT_RUNPATH overrides DT_RPATH.  Do _NOT_ bfd_release, as that
+        frees all more recently bfd_alloc'd blocks as well.  */
+      if (runpath)
+       rpath = runpath;
+
+      if (rpath)
+       {
+         struct bfd_link_needed_list **pn;
+         for (pn = & hash_table->runpath;
+              *pn != NULL;
+              pn = &(*pn)->next)
+           ;
+         *pn = rpath;
        }
 
       /* We do not want to include any of the sections in a dynamic
@@ -1604,10 +1510,6 @@ elf_link_add_object_symbols (abfd, info)
                  if (dyn.d_tag == DT_NEEDED
                      && dyn.d_un.d_val == strindex)
                    {
-                     if (buf != NULL)
-                       free (buf);
-                     if (extversym != NULL)
-                       free (extversym);
                      _bfd_elf_strtab_delref (hash_table->dynstr, strindex);
                      return true;
                    }
@@ -1625,31 +1527,79 @@ elf_link_add_object_symbols (abfd, info)
       elf_dt_name (abfd) = name;
     }
 
-  pos = hdr->sh_offset + extsymoff * sizeof (Elf_External_Sym);
-  amt = extsymcount * sizeof (Elf_External_Sym);
-  if (bfd_seek (abfd, pos, SEEK_SET) != 0
-      || bfd_bread ((PTR) buf, amt, abfd) != amt)
-    goto error_return;
+  /* If this is a dynamic object, we always link against the .dynsym
+     symbol table, not the .symtab symbol table.  The dynamic linker
+     will only see the .dynsym symbol table, so there is no reason to
+     look at .symtab for a dynamic object.  */
+
+  if (! dynamic || elf_dynsymtab (abfd) == 0)
+    hdr = &elf_tdata (abfd)->symtab_hdr;
+  else
+    hdr = &elf_tdata (abfd)->dynsymtab_hdr;
+
+  symcount = hdr->sh_size / sizeof (Elf_External_Sym);
+
+  /* The sh_info field of the symtab header tells us where the
+     external symbols start.  We don't care about the local symbols at
+     this point.  */
+  if (elf_bad_symtab (abfd))
+    {
+      extsymcount = symcount;
+      extsymoff = 0;
+    }
+  else
+    {
+      extsymcount = symcount - hdr->sh_info;
+      extsymoff = hdr->sh_info;
+    }
 
-  if (shndx_hdr != NULL && shndx_hdr->sh_size != 0)
+  sym_hash = NULL;
+  if (extsymcount != 0)
     {
-      amt = extsymcount * sizeof (Elf_External_Sym_Shndx);
-      pos = shndx_hdr->sh_offset + extsymoff * sizeof (Elf_External_Sym_Shndx);
-      if (bfd_seek (abfd, pos, SEEK_SET) != 0
-         || bfd_bread ((PTR) shndx_buf, amt, abfd) != amt)
+      isymbuf = bfd_elf_get_elf_syms (abfd, hdr, extsymcount, extsymoff,
+                                     NULL, NULL, NULL);
+      if (isymbuf == NULL)
        goto error_return;
+
+      /* We store a pointer to the hash table entry for each external
+        symbol.  */
+      amt = extsymcount * sizeof (struct elf_link_hash_entry *);
+      sym_hash = (struct elf_link_hash_entry **) bfd_alloc (abfd, amt);
+      if (sym_hash == NULL)
+       goto error_free_sym;
+      elf_sym_hashes (abfd) = sym_hash;
+    }
+
+  if (dynamic)
+    {
+      /* Read in any version definitions.  */
+      if (! _bfd_elf_slurp_version_tables (abfd))
+       goto error_free_sym;
+
+      /* Read in the symbol versions, but don't bother to convert them
+        to internal format.  */
+      if (elf_dynversym (abfd) != 0)
+       {
+         Elf_Internal_Shdr *versymhdr;
+
+         versymhdr = &elf_tdata (abfd)->dynversym_hdr;
+         extversym = (Elf_External_Versym *) bfd_malloc (versymhdr->sh_size);
+         if (extversym == NULL)
+           goto error_free_sym;
+         amt = versymhdr->sh_size;
+         if (bfd_seek (abfd, versymhdr->sh_offset, SEEK_SET) != 0
+             || bfd_bread ((PTR) extversym, amt, abfd) != amt)
+           goto error_free_vers;
+       }
     }
 
   weaks = NULL;
 
   ever = extversym != NULL ? extversym + extsymoff : NULL;
-  esymend = buf + extsymcount;
-  for (esym = buf, shndx = shndx_buf;
-       esym < esymend;
-       esym++, sym_hash++, ever = (ever != NULL ? ever + 1 : NULL),
-        shndx = (shndx != NULL ? shndx + 1 : NULL))
+  for (isym = isymbuf, isymend = isymbuf + extsymcount;
+       isym < isymend;
+       isym++, sym_hash++, ever = (ever != NULL ? ever + 1 : NULL))
     {
-      Elf_Internal_Sym sym;
       int bind;
       bfd_vma value;
       asection *sec;
@@ -1664,14 +1614,12 @@ elf_link_add_object_symbols (abfd, info)
 
       override = false;
 
-      elf_swap_symbol_in (abfd, (const PTR) esym, (const PTR) shndx, &sym);
-
       flags = BSF_NO_FLAGS;
       sec = NULL;
-      value = sym.st_value;
+      value = isym->st_value;
       *sym_hash = NULL;
 
-      bind = ELF_ST_BIND (sym.st_info);
+      bind = ELF_ST_BIND (isym->st_info);
       if (bind == STB_LOCAL)
        {
          /* This should be impossible, since ELF requires that all
@@ -1682,8 +1630,8 @@ elf_link_add_object_symbols (abfd, info)
        }
       else if (bind == STB_GLOBAL)
        {
-         if (sym.st_shndx != SHN_UNDEF
-             && sym.st_shndx != SHN_COMMON)
+         if (isym->st_shndx != SHN_UNDEF
+             && isym->st_shndx != SHN_COMMON)
            flags = BSF_GLOBAL;
        }
       else if (bind == STB_WEAK)
@@ -1693,35 +1641,37 @@ elf_link_add_object_symbols (abfd, info)
          /* Leave it up to the processor backend.  */
        }
 
-      if (sym.st_shndx == SHN_UNDEF)
+      if (isym->st_shndx == SHN_UNDEF)
        sec = bfd_und_section_ptr;
-      else if (sym.st_shndx < SHN_LORESERVE || sym.st_shndx > SHN_HIRESERVE)
+      else if (isym->st_shndx < SHN_LORESERVE || isym->st_shndx > SHN_HIRESERVE)
        {
-         sec = section_from_elf_index (abfd, sym.st_shndx);
+         sec = section_from_elf_index (abfd, isym->st_shndx);
          if (sec == NULL)
            sec = bfd_abs_section_ptr;
          else if ((abfd->flags & (EXEC_P | DYNAMIC)) != 0)
            value -= sec->vma;
        }
-      else if (sym.st_shndx == SHN_ABS)
+      else if (isym->st_shndx == SHN_ABS)
        sec = bfd_abs_section_ptr;
-      else if (sym.st_shndx == SHN_COMMON)
+      else if (isym->st_shndx == SHN_COMMON)
        {
          sec = bfd_com_section_ptr;
          /* What ELF calls the size we call the value.  What ELF
             calls the value we call the alignment.  */
-         value = sym.st_size;
+         value = isym->st_size;
        }
       else
        {
          /* Leave it up to the processor backend.  */
        }
 
-      name = bfd_elf_string_from_elf_section (abfd, hdr->sh_link, sym.st_name);
+      name = bfd_elf_string_from_elf_section (abfd, hdr->sh_link,
+                                             isym->st_name);
       if (name == (const char *) NULL)
-       goto error_return;
+       goto error_free_vers;
 
-      if (sym.st_shndx == SHN_COMMON && ELF_ST_TYPE (sym.st_info) == STT_TLS)
+      if (isym->st_shndx == SHN_COMMON
+         && ELF_ST_TYPE (isym->st_info) == STT_TLS)
        {
          asection *tcomm = bfd_get_section_by_name (abfd, ".tcommon");
 
@@ -1733,15 +1683,15 @@ elf_link_add_object_symbols (abfd, info)
                                                           | SEC_IS_COMMON
                                                           | SEC_LINKER_CREATED
                                                           | SEC_THREAD_LOCAL)))
-               goto error_return;
+               goto error_free_vers;
            }
          sec = tcomm;
        }
       else if (add_symbol_hook)
        {
-         if (! (*add_symbol_hook) (abfd, info, &sym, &name, &flags, &sec,
+         if (! (*add_symbol_hook) (abfd, info, isym, &name, &flags, &sec,
                                    &value))
-           goto error_return;
+           goto error_free_vers;
 
          /* The hook function sets the name to NULL if this symbol
             should be skipped for some reason.  */
@@ -1753,7 +1703,7 @@ elf_link_add_object_symbols (abfd, info)
       if (sec == (asection *) NULL)
        {
          bfd_set_error (bfd_error_bad_value);
-         goto error_return;
+         goto error_free_vers;
        }
 
       if (bfd_is_und_section (sec)
@@ -1784,11 +1734,10 @@ elf_link_add_object_symbols (abfd, info)
                  || (vernum > 1 && ! bfd_is_abs_section (sec)))
                {
                  const char *verstr;
-                 unsigned int namelen;
-                 bfd_size_type newlen;
+                 size_t namelen, verlen, newlen;
                  char *newname, *p;
 
-                 if (sym.st_shndx != SHN_UNDEF)
+                 if (isym->st_shndx != SHN_UNDEF)
                    {
                      if (vernum > elf_tdata (abfd)->dynverdef_hdr.sh_info)
                        {
@@ -1797,7 +1746,7 @@ elf_link_add_object_symbols (abfd, info)
                             bfd_archive_filename (abfd), name, vernum,
                             elf_tdata (abfd)->dynverdef_hdr.sh_info);
                          bfd_set_error (bfd_error_bad_value);
-                         goto error_return;
+                         goto error_free_vers;
                        }
                      else if (vernum > 1)
                        verstr =
@@ -1837,37 +1786,39 @@ elf_link_add_object_symbols (abfd, info)
                            (_("%s: %s: invalid needed version %d"),
                             bfd_archive_filename (abfd), name, vernum);
                          bfd_set_error (bfd_error_bad_value);
-                         goto error_return;
+                         goto error_free_vers;
                        }
                    }
 
                  namelen = strlen (name);
-                 newlen = namelen + strlen (verstr) + 2;
-                 if ((iver.vs_vers & VERSYM_HIDDEN) == 0)
+                 verlen = strlen (verstr);
+                 newlen = namelen + verlen + 2;
+                 if ((iver.vs_vers & VERSYM_HIDDEN) == 0
+                     && isym->st_shndx != SHN_UNDEF)
                    ++newlen;
 
-                 newname = (char *) bfd_alloc (abfd, newlen);
+                 newname = (char *) bfd_alloc (abfd, (bfd_size_type) newlen);
                  if (newname == NULL)
-                   goto error_return;
-                 strcpy (newname, name);
+                   goto error_free_vers;
+                 memcpy (newname, name, namelen);
                  p = newname + namelen;
                  *p++ = ELF_VER_CHR;
                  /* If this is a defined non-hidden version symbol,
                     we add another @ to the name.  This indicates the
                     default version of the symbol.  */
                  if ((iver.vs_vers & VERSYM_HIDDEN) == 0
-                     && sym.st_shndx != SHN_UNDEF)
+                     && isym->st_shndx != SHN_UNDEF)
                    *p++ = ELF_VER_CHR;
-                 strcpy (p, verstr);
+                 memcpy (p, verstr, verlen + 1);
 
                  name = newname;
                }
            }
 
-         if (! elf_merge_symbol (abfd, info, name, &sym, &sec, &value,
+         if (! elf_merge_symbol (abfd, info, name, isym, &sec, &value,
                                  sym_hash, &override, &type_change_ok,
                                  &size_change_ok, dt_needed))
-           goto error_return;
+           goto error_free_vers;
 
          if (override)
            definition = false;
@@ -1895,7 +1846,7 @@ elf_link_add_object_symbols (abfd, info)
       if (! (_bfd_generic_link_add_one_symbol
             (info, abfd, name, flags, sec, value, (const char *) NULL,
              false, collect, (struct bfd_link_hash_entry **) sym_hash)))
-       goto error_return;
+       goto error_free_vers;
 
       h = *sym_hash;
       while (h->root.type == bfd_link_hash_indirect
@@ -1907,7 +1858,7 @@ elf_link_add_object_symbols (abfd, info)
       if (dynamic
          && definition
          && (flags & BSF_WEAK) != 0
-         && ELF_ST_TYPE (sym.st_info) != STT_FUNC
+         && ELF_ST_TYPE (isym->st_info) != STT_FUNC
          && info->hash->creator->flavour == bfd_target_elf_flavour
          && h->weakdef == NULL)
        {
@@ -1929,16 +1880,16 @@ elf_link_add_object_symbols (abfd, info)
        }
 
       /* Set the alignment of a common symbol.  */
-      if (sym.st_shndx == SHN_COMMON
+      if (isym->st_shndx == SHN_COMMON
          && h->root.type == bfd_link_hash_common)
        {
          unsigned int align;
 
-         align = bfd_log2 (sym.st_value);
+         align = bfd_log2 (isym->st_value);
          if (align > old_alignment
              /* Permit an alignment power of zero if an alignment of one
                 is specified and no other alignments have been specified.  */
-             || (sym.st_value == 1 && old_alignment == 0))
+             || (isym->st_value == 1 && old_alignment == 0))
            h->root.u.c.p->alignment_power = align;
        }
 
@@ -1949,16 +1900,16 @@ elf_link_add_object_symbols (abfd, info)
          int new_flag;
 
          /* Remember the symbol size and type.  */
-         if (sym.st_size != 0
+         if (isym->st_size != 0
              && (definition || h->size == 0))
            {
-             if (h->size != 0 && h->size != sym.st_size && ! size_change_ok)
+             if (h->size != 0 && h->size != isym->st_size && ! size_change_ok)
                (*_bfd_error_handler)
                  (_("Warning: size of symbol `%s' changed from %lu to %lu in %s"),
-                  name, (unsigned long) h->size, (unsigned long) sym.st_size,
-                  bfd_archive_filename (abfd));
+                  name, (unsigned long) h->size,
+                  (unsigned long) isym->st_size, bfd_archive_filename (abfd));
 
-             h->size = sym.st_size;
+             h->size = isym->st_size;
            }
 
          /* If this is a common symbol, then we always want H->SIZE
@@ -1969,37 +1920,37 @@ elf_link_add_object_symbols (abfd, info)
          if (h->root.type == bfd_link_hash_common)
            h->size = h->root.u.c.size;
 
-         if (ELF_ST_TYPE (sym.st_info) != STT_NOTYPE
+         if (ELF_ST_TYPE (isym->st_info) != STT_NOTYPE
              && (definition || h->type == STT_NOTYPE))
            {
              if (h->type != STT_NOTYPE
-                 && h->type != ELF_ST_TYPE (sym.st_info)
+                 && h->type != ELF_ST_TYPE (isym->st_info)
                  && ! type_change_ok)
                (*_bfd_error_handler)
                  (_("Warning: type of symbol `%s' changed from %d to %d in %s"),
-                  name, h->type, ELF_ST_TYPE (sym.st_info),
+                  name, h->type, ELF_ST_TYPE (isym->st_info),
                   bfd_archive_filename (abfd));
 
-             h->type = ELF_ST_TYPE (sym.st_info);
+             h->type = ELF_ST_TYPE (isym->st_info);
            }
 
          /* If st_other has a processor-specific meaning, specific code
             might be needed here.  */
-         if (sym.st_other != 0)
+         if (isym->st_other != 0)
            {
              /* Combine visibilities, using the most constraining one.  */
              unsigned char hvis   = ELF_ST_VISIBILITY (h->other);
-             unsigned char symvis = ELF_ST_VISIBILITY (sym.st_other);
+             unsigned char symvis = ELF_ST_VISIBILITY (isym->st_other);
 
              if (symvis && (hvis > symvis || hvis == 0))
-               h->other = sym.st_other;
+               h->other = isym->st_other;
 
              /* If neither has visibility, use the st_other of the
                 definition.  This is an arbitrary choice, since the
                 other bits have no general meaning.  */
              if (!symvis && !hvis
                  && (definition || h->other == 0))
-               h->other = sym.st_other;
+               h->other = isym->st_other;
            }
 
          /* Set a flag in the hash table entry indicating the type of
@@ -2043,21 +1994,21 @@ elf_link_add_object_symbols (abfd, info)
          /* Check to see if we need to add an indirect symbol for
             the default name.  */
          if (definition || h->root.type == bfd_link_hash_common)
-           if (! elf_add_default_symbol (abfd, info, h, name, &sym,
+           if (! elf_add_default_symbol (abfd, info, h, name, isym,
                                          &sec, &value, &dynsym,
                                          override, dt_needed))
-             goto error_return;
+             goto error_free_vers;
 
          if (dynsym && h->dynindx == -1)
            {
              if (! _bfd_elf_link_record_dynamic_symbol (info, h))
-               goto error_return;
+               goto error_free_vers;
              if (h->weakdef != NULL
                  && ! new_weakdef
                  && h->weakdef->dynindx == -1)
                {
                  if (! _bfd_elf_link_record_dynamic_symbol (info, h->weakdef))
-                   goto error_return;
+                   goto error_free_vers;
                }
            }
          else if (dynsym && h->dynindx != -1)
@@ -2080,7 +2031,7 @@ elf_link_add_object_symbols (abfd, info)
              bfd_size_type strindex;
 
              if (! is_elf_hash_table (info))
-               goto error_return;
+               goto error_free_vers;
 
              /* The symbol from a DT_NEEDED object is referenced from
                 the regular object to create a dynamic executable. We
@@ -2091,7 +2042,7 @@ elf_link_add_object_symbols (abfd, info)
              strindex = _bfd_elf_strtab_add (hash_table->dynstr,
                                              elf_dt_soname (abfd), false);
              if (strindex == (bfd_size_type) -1)
-               goto error_return;
+               goto error_free_vers;
 
              if (oldsize == _bfd_elf_strtab_size (hash_table->dynstr))
                {
@@ -2117,11 +2068,21 @@ elf_link_add_object_symbols (abfd, info)
                }
 
              if (! elf_add_dynamic_entry (info, (bfd_vma) DT_NEEDED, strindex))
-               goto error_return;
+               goto error_free_vers;
            }
        }
     }
 
+  if (extversym != NULL)
+    {
+      free (extversym);
+      extversym = NULL;
+    }
+
+  if (isymbuf != NULL)
+    free (isymbuf);
+  isymbuf = NULL;
+
   /* Now set the weakdefs field correctly for all the weak defined
      symbols we found.  The only way to do this is to search all the
      symbols.  Since we only need the information for non functions in
@@ -2189,24 +2150,11 @@ elf_link_add_object_symbols (abfd, info)
                  if (! _bfd_elf_link_record_dynamic_symbol (info, hlook))
                    goto error_return;
                }
-
              break;
            }
        }
     }
 
-  if (buf != NULL)
-    {
-      free (buf);
-      buf = NULL;
-    }
-
-  if (extversym != NULL)
-    {
-      free (extversym);
-      extversym = NULL;
-    }
-
   /* If this object is the same format as the output object, and it is
      not a shared library, then let the backend look through the
      relocs.
@@ -2252,7 +2200,7 @@ elf_link_add_object_symbols (abfd, info)
 
          ok = (*check_relocs) (abfd, info, o, internal_relocs);
 
-         if (! info->keep_memory)
+         if (elf_section_data (o)->relocs != internal_relocs)
            free (internal_relocs);
 
          if (! ok)
@@ -2331,13 +2279,13 @@ elf_link_add_object_symbols (abfd, info)
 
   return true;
 
- error_return:
-  if (buf != NULL)
-    free (buf);
-  if (dynbuf != NULL)
-    free (dynbuf);
+ error_free_vers:
   if (extversym != NULL)
     free (extversym);
+ error_free_sym:
+  if (isymbuf != NULL)
+    free (isymbuf);
+ error_return:
   return false;
 }
 
@@ -2356,6 +2304,7 @@ elf_link_create_dynamic_sections (abfd, info)
   flagword flags;
   register asection *s;
   struct elf_link_hash_entry *h;
+  struct bfd_link_hash_entry *bh;
   struct elf_backend_data *bed;
 
   if (! is_elf_hash_table (info))
@@ -2448,12 +2397,12 @@ elf_link_create_dynamic_sections (abfd, info)
      creating a .dynamic section.  We don't want to define it if there
      is no .dynamic section, since on some ELF platforms the start up
      code examines it to decide how to initialize the process.  */
-  h = NULL;
+  bh = NULL;
   if (! (_bfd_generic_link_add_one_symbol
         (info, abfd, "_DYNAMIC", BSF_GLOBAL, s, (bfd_vma) 0,
-         (const char *) NULL, false, get_elf_backend_data (abfd)->collect,
-         (struct bfd_link_hash_entry **) &h)))
+         (const char *) 0, false, get_elf_backend_data (abfd)->collect, &bh)))
     return false;
+  h = (struct elf_link_hash_entry *) bh;
   h->elf_link_hash_flags |= ELF_LINK_HASH_DEF_REGULAR;
   h->type = STT_OBJECT;
 
@@ -2518,93 +2467,6 @@ elf_add_dynamic_entry (info, tag, val)
 
   return true;
 }
-
-/* Record a new local dynamic symbol.  */
-
-boolean
-elf_link_record_local_dynamic_symbol (info, input_bfd, input_indx)
-     struct bfd_link_info *info;
-     bfd *input_bfd;
-     long input_indx;
-{
-  struct elf_link_local_dynamic_entry *entry;
-  struct elf_link_hash_table *eht;
-  struct elf_strtab_hash *dynstr;
-  Elf_External_Sym esym;
-  Elf_External_Sym_Shndx eshndx;
-  Elf_External_Sym_Shndx *shndx;
-  unsigned long dynstr_index;
-  char *name;
-  file_ptr pos;
-  bfd_size_type amt;
-
-  if (! is_elf_hash_table (info))
-    return false;
-
-  /* See if the entry exists already.  */
-  for (entry = elf_hash_table (info)->dynlocal; entry ; entry = entry->next)
-    if (entry->input_bfd == input_bfd && entry->input_indx == input_indx)
-      return true;
-
-  entry = (struct elf_link_local_dynamic_entry *)
-    bfd_alloc (input_bfd, (bfd_size_type) sizeof (*entry));
-  if (entry == NULL)
-    return false;
-
-  /* Go find the symbol, so that we can find it's name.  */
-  amt = sizeof (Elf_External_Sym);
-  pos = elf_tdata (input_bfd)->symtab_hdr.sh_offset + input_indx * amt;
-  if (bfd_seek (input_bfd, pos, SEEK_SET) != 0
-      || bfd_bread ((PTR) &esym, amt, input_bfd) != amt)
-    return false;
-  shndx = NULL;
-  if (elf_tdata (input_bfd)->symtab_shndx_hdr.sh_size != 0)
-    {
-      amt = sizeof (Elf_External_Sym_Shndx);
-      pos = elf_tdata (input_bfd)->symtab_shndx_hdr.sh_offset;
-      pos += input_indx * amt;
-      shndx = &eshndx;
-      if (bfd_seek (input_bfd, pos, SEEK_SET) != 0
-         || bfd_bread ((PTR) shndx, amt, input_bfd) != amt)
-       return false;
-    }
-  elf_swap_symbol_in (input_bfd, (const PTR) &esym, (const PTR) shndx,
-                     &entry->isym);
-
-  name = (bfd_elf_string_from_elf_section
-         (input_bfd, elf_tdata (input_bfd)->symtab_hdr.sh_link,
-          entry->isym.st_name));
-
-  dynstr = elf_hash_table (info)->dynstr;
-  if (dynstr == NULL)
-    {
-      /* Create a strtab to hold the dynamic symbol names.  */
-      elf_hash_table (info)->dynstr = dynstr = _bfd_elf_strtab_init ();
-      if (dynstr == NULL)
-       return false;
-    }
-
-  dynstr_index = _bfd_elf_strtab_add (dynstr, name, false);
-  if (dynstr_index == (unsigned long) -1)
-    return false;
-  entry->isym.st_name = dynstr_index;
-
-  eht = elf_hash_table (info);
-
-  entry->next = eht->dynlocal;
-  eht->dynlocal = entry;
-  entry->input_bfd = input_bfd;
-  entry->input_indx = input_indx;
-  eht->dynsymcount++;
-
-  /* Whatever binding the symbol had before, it's now local.  */
-  entry->isym.st_info
-    = ELF_ST_INFO (STB_LOCAL, ELF_ST_TYPE (entry->isym.st_info));
-
-  /* The dynindx will be set at the end of size_dynamic_sections.  */
-
-  return true;
-}
 \f
 /* Read and swap the relocs from the section indicated by SHDR.  This
    may be either a REL or a RELA section.  The relocations are
@@ -2922,11 +2784,11 @@ compute_bucket_count (info)
   elf_link_hash_traverse (elf_hash_table (info),
                          elf_collect_hash_codes, &hashcodesp);
 
-/* We have a problem here.  The following code to optimize the table
-   size requires an integer type with more the 32 bits.  If
-   BFD_HOST_U_64_BIT is set we know about such a type.  */
+  /* We have a problem here.  The following code to optimize the table
+     size requires an integer type with more the 32 bits.  If
+     BFD_HOST_U_64_BIT is set we know about such a type.  */
 #ifdef BFD_HOST_U_64_BIT
-  if (info->optimize == true)
+  if (info->optimize)
     {
       unsigned long int nsyms = hashcodesp - hashcodes;
       size_t minsize;
@@ -3095,6 +2957,9 @@ NAME(bfd_elf,size_dynamic_sections) (output_bfd, soname, rpath,
       struct elf_info_failed eif;
       struct elf_link_hash_entry *h;
       asection *dynstr;
+      struct bfd_elf_version_tree *t;
+      struct bfd_elf_version_expr *d;
+      boolean all_defined;
 
       *sinterpptr = bfd_get_section_by_name (dynobj, ".interp");
       BFD_ASSERT (*sinterpptr != NULL || info->shared);
@@ -3175,6 +3040,57 @@ NAME(bfd_elf,size_dynamic_sections) (output_bfd, soname, rpath,
            return false;
        }
 
+      /* Make all global versions with definiton.  */
+      for (t = verdefs; t != NULL; t = t->next)
+       for (d = t->globals; d != NULL; d = d->next)
+         if (!d->symver && strchr (d->pattern, '*') == NULL)
+           {
+             const char *verstr, *name;
+             size_t namelen, verlen, newlen;
+             char *newname, *p;
+             struct elf_link_hash_entry *newh;
+
+             name = d->pattern;
+             namelen = strlen (name);
+             verstr = t->name;
+             verlen = strlen (verstr);
+             newlen = namelen + verlen + 3; 
+
+             newname = (char *) bfd_malloc ((bfd_size_type) newlen);
+             if (newname == NULL)
+               return false;
+             memcpy (newname, name, namelen);
+
+             /* Check the hidden versioned definition.  */
+             p = newname + namelen;
+             *p++ = ELF_VER_CHR;
+             memcpy (p, verstr, verlen + 1);
+             newh = elf_link_hash_lookup (elf_hash_table (info),
+                                          newname, false, false,
+                                          false);
+             if (newh == NULL
+                 || (newh->root.type != bfd_link_hash_defined
+                     && newh->root.type != bfd_link_hash_defweak))
+               {
+                 /* Check the default versioned definition.  */
+                 *p++ = ELF_VER_CHR;
+                 memcpy (p, verstr, verlen + 1);
+                 newh = elf_link_hash_lookup (elf_hash_table (info),
+                                              newname, false, false,
+                                              false);
+               }
+             free (newname);
+
+             /* Mark this version if there is a definition and it is
+                not defined in a shared object.  */
+             if (newh != NULL
+                 && ((newh->elf_link_hash_flags
+                      & ELF_LINK_HASH_DEF_DYNAMIC) == 0)
+                 && (newh->root.type == bfd_link_hash_defined
+                     || newh->root.type == bfd_link_hash_defweak))
+               d->symver = 1;
+           }
+
       /* Attach all the symbols to their version information.  */
       asvinfo.output_bfd = output_bfd;
       asvinfo.info = info;
@@ -3187,6 +3103,28 @@ NAME(bfd_elf,size_dynamic_sections) (output_bfd, soname, rpath,
       if (asvinfo.failed)
        return false;
 
+      if (!info->allow_undefined_version)
+       {
+         /* Check if all global versions have a definiton.  */
+         all_defined = true;
+         for (t = verdefs; t != NULL; t = t->next)
+           for (d = t->globals; d != NULL; d = d->next)
+             if (!d->symver && !d->script
+                 && strchr (d->pattern, '*') == NULL)
+               {
+                 (*_bfd_error_handler)
+                   (_("%s: undefined version: %s"),
+                    d->pattern, t->name);
+                 all_defined = false;
+               }
+
+         if (!all_defined)
+           {
+             bfd_set_error (bfd_error_bad_value);
+             return false;
+           }
+       }
+
       /* Find all symbols which were defined in a dynamic object and make
         the backend pick a reasonable value for them.  */
       elf_link_hash_traverse (elf_hash_table (info),
@@ -3242,7 +3180,7 @@ NAME(bfd_elf,size_dynamic_sections) (output_bfd, soname, rpath,
                    {
                      (*_bfd_error_handler)
                        (_("%s: .preinit_array section is not allowed in DSO"),
-                         bfd_archive_filename (sub));
+                        bfd_archive_filename (sub));
                      break;
                    }
 
@@ -3401,19 +3339,20 @@ NAME(bfd_elf,size_dynamic_sections) (output_bfd, soname, rpath,
              unsigned int cdeps;
              struct bfd_elf_version_deps *n;
              struct elf_link_hash_entry *h;
+             struct bfd_link_hash_entry *bh;
 
              cdeps = 0;
              for (n = t->deps; n != NULL; n = n->next)
                ++cdeps;
 
              /* Add a symbol representing this version.  */
-             h = NULL;
+             bh = NULL;
              if (! (_bfd_generic_link_add_one_symbol
                     (info, dynobj, t->name, BSF_GLOBAL, bfd_abs_section_ptr,
                      (bfd_vma) 0, (const char *) NULL, false,
-                     get_elf_backend_data (dynobj)->collect,
-                     (struct bfd_link_hash_entry **) &h)))
+                     get_elf_backend_data (dynobj)->collect, &bh)))
                return false;
+             h = (struct elf_link_hash_entry *) bh;
              h->elf_link_hash_flags &= ~ ELF_LINK_NON_ELF;
              h->elf_link_hash_flags |= ELF_LINK_HASH_DEF_REGULAR;
              h->type = STT_OBJECT;
@@ -3961,9 +3900,12 @@ elf_fix_symbol_flags (h, eif)
     {
       struct elf_link_hash_entry *weakdef;
 
+      weakdef = h->weakdef;
+      if (h->root.type == bfd_link_hash_indirect)
+       h = (struct elf_link_hash_entry *) h->root.u.i.link;
+
       BFD_ASSERT (h->root.type == bfd_link_hash_defined
                  || h->root.type == bfd_link_hash_defweak);
-      weakdef = h->weakdef;
       BFD_ASSERT (weakdef->root.type == bfd_link_hash_defined
                  || weakdef->root.type == bfd_link_hash_defweak);
       BFD_ASSERT (weakdef->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC);
@@ -3978,7 +3920,7 @@ elf_fix_symbol_flags (h, eif)
          struct elf_backend_data *bed;
 
          bed = get_elf_backend_data (elf_hash_table (eif->info)->dynobj);
-         (*bed->elf_backend_copy_indirect_symbol) (weakdef, h);
+         (*bed->elf_backend_copy_indirect_symbol) (bed, weakdef, h);
        }
     }
 
@@ -4098,7 +4040,7 @@ elf_adjust_dynamic_symbol (h, data)
       && (h->elf_link_hash_flags & ELF_LINK_HASH_NEEDS_PLT) == 0)
     (*_bfd_error_handler)
       (_("warning: type and size of dynamic symbol `%s' are not defined"),
-        h->root.root.string);
+       h->root.root.string);
 
   dynobj = elf_hash_table (eif->info)->dynobj;
   bed = get_elf_backend_data (dynobj);
@@ -4158,7 +4100,7 @@ elf_export_symbol (h, data)
 
       if (!eif->verdefs)
        {
-doit:
+       doit:
          if (! _bfd_elf_link_record_dynamic_symbol (eif->info, h))
            {
              eif->failed = true;
@@ -4325,7 +4267,7 @@ elf_link_assign_sym_version (h, data)
              alc = bfd_malloc ((bfd_size_type) len);
              if (alc == NULL)
                return false;
-             strncpy (alc, h->root.root.string, len - 1);
+             memcpy (alc, h->root.root.string, len - 1);
              alc[len - 1] = '\0';
              if (alc[len - 2] == ELF_VER_CHR)
                alc[len - 2] = '\0';
@@ -4428,45 +4370,58 @@ elf_link_assign_sym_version (h, data)
   if (h->verinfo.vertree == NULL && sinfo->verdefs != NULL)
     {
       struct bfd_elf_version_tree *t;
-      struct bfd_elf_version_tree *deflt;
+      struct bfd_elf_version_tree *local_ver;
       struct bfd_elf_version_expr *d;
 
       /* See if can find what version this symbol is in.  If the
         symbol is supposed to be local, then don't actually register
         it.  */
-      deflt = NULL;
+      local_ver = NULL;
       for (t = sinfo->verdefs; t != NULL; t = t->next)
        {
          if (t->globals != NULL)
            {
+             boolean matched;
+
+             matched = false;
              for (d = t->globals; d != NULL; d = d->next)
                {
                  if ((*d->match) (d, h->root.root.string))
                    {
-                     h->verinfo.vertree = t;
-                     break;
+                     if (d->symver)
+                       matched = true;
+                     else
+                       {
+                         /* There is a version without definition.  Make
+                            the symbol the default definition for this
+                            version.  */
+                         h->verinfo.vertree = t;
+                         local_ver = NULL;
+                         d->script = 1;
+                         break;
+                       }
                    }
                }
 
              if (d != NULL)
                break;
+             else if (matched)
+               /* There is no undefined version for this symbol. Hide the
+                  default one.  */
+               (*bed->elf_backend_hide_symbol) (info, h, true);
            }
 
          if (t->locals != NULL)
            {
              for (d = t->locals; d != NULL; d = d->next)
                {
+                 /* If the match is "*", keep looking for a more
+                    explicit, perhaps even global, match.  */
                  if (d->pattern[0] == '*' && d->pattern[1] == '\0')
-                   deflt = t;
+                   local_ver = t;
                  else if ((*d->match) (d, h->root.root.string))
                    {
-                     h->verinfo.vertree = t;
-                     if (h->dynindx != -1
-                         && info->shared
-                         && ! info->export_dynamic)
-                       {
-                         (*bed->elf_backend_hide_symbol) (info, h, true);
-                       }
+                     local_ver = t;
                      break;
                    }
                }
@@ -4476,9 +4431,9 @@ elf_link_assign_sym_version (h, data)
            }
        }
 
-      if (deflt != NULL && h->verinfo.vertree == NULL)
+      if (local_ver != NULL)
        {
-         h->verinfo.vertree = deflt;
+         h->verinfo.vertree = local_ver;
          if (h->dynindx != -1
              && info->shared
              && ! info->export_dynamic)
@@ -4539,6 +4494,8 @@ struct elf_final_link_info
   size_t symbuf_count;
   /* Number of symbols which fit in symbuf.  */
   size_t symbuf_size;
+  /* And same for symshndxbuf.  */
+  size_t shndxbuf_size;
 };
 
 static boolean elf_link_output_sym
@@ -4695,7 +4652,7 @@ elf_link_adjust_relocs (abfd, rel_hdr, count, rel_hash)
 
          for (j = 0; j < bed->s->int_rels_per_ext_rel; j++)
            irela[j].r_info = ELF_R_INFO ((*rel_hash)->indx,
-                                      ELF_R_TYPE (irela[j].r_info));
+                                         ELF_R_TYPE (irela[j].r_info));
 
          if (bed->s->swap_reloca_out)
            (*bed->s->swap_reloca_out) (abfd, irela, (bfd_byte *) erela);
@@ -4708,12 +4665,15 @@ elf_link_adjust_relocs (abfd, rel_hdr, count, rel_hash)
   free (irela);
 }
 
-struct elf_link_sort_rela {
+struct elf_link_sort_rela
+{
   bfd_vma offset;
   enum elf_reloc_type_class type;
-  union {
-    Elf_Internal_Rel rel;
-    Elf_Internal_Rela rela;
+  union
+  {
+    /* We use these as arrays of size int_rels_per_ext_rel.  */
+    Elf_Internal_Rel rel[1];
+    Elf_Internal_Rela rela[1];
   } u;
 };
 
@@ -4733,13 +4693,13 @@ elf_link_sort_cmp1 (A, B)
     return 1;
   if (relativea > relativeb)
     return -1;
-  if (ELF_R_SYM (a->u.rel.r_info) < ELF_R_SYM (b->u.rel.r_info))
+  if (ELF_R_SYM (a->u.rel->r_info) < ELF_R_SYM (b->u.rel->r_info))
     return -1;
-  if (ELF_R_SYM (a->u.rel.r_info) > ELF_R_SYM (b->u.rel.r_info))
+  if (ELF_R_SYM (a->u.rel->r_info) > ELF_R_SYM (b->u.rel->r_info))
     return 1;
-  if (a->u.rel.r_offset < b->u.rel.r_offset)
+  if (a->u.rel->r_offset < b->u.rel->r_offset)
     return -1;
-  if (a->u.rel.r_offset > b->u.rel.r_offset)
+  if (a->u.rel->r_offset > b->u.rel->r_offset)
     return 1;
   return 0;
 }
@@ -4763,9 +4723,9 @@ elf_link_sort_cmp2 (A, B)
     return -1;
   if (copya > copyb)
     return 1;
-  if (a->u.rel.r_offset < b->u.rel.r_offset)
+  if (a->u.rel->r_offset < b->u.rel->r_offset)
     return -1;
-  if (a->u.rel.r_offset > b->u.rel.r_offset)
+  if (a->u.rel->r_offset > b->u.rel->r_offset)
     return 1;
   return 0;
 }
@@ -4783,6 +4743,7 @@ elf_link_sort_relocs (abfd, info, psec)
   size_t i, j, ret;
   struct elf_link_sort_rela *rela;
   struct elf_backend_data *bed = get_elf_backend_data (abfd);
+  int i2e = bed->s->int_rels_per_ext_rel;
 
   reldyn = bfd_get_section_by_name (abfd, ".rela.dyn");
   if (reldyn == NULL || reldyn->_raw_size == 0)
@@ -4806,7 +4767,23 @@ elf_link_sort_relocs (abfd, info, psec)
   if (size != reldyn->_raw_size)
     return 0;
 
-  rela = (struct elf_link_sort_rela *) bfd_zmalloc (sizeof (*rela) * count);
+  /* We waste some memory here when N = i2e is greater than 1, since
+     we allocate space for N * sizeof (*rela) where sizeof (*rela) +
+     (N - 1) * sizeof (Elf_Internal_Rel/Rela) would do.  Also, we use
+     rela[k] only when k is a multiple of N, and then we index the
+     array within the union, such that rela[k].u.rel[i], i < N, is the
+     (i+1)th internal relocation corresponding to the (k/N)th external
+     relocation.  This is done such that the relocation swap-in and
+     swap-out functions can gen pointers to arrays of internal
+     relocations that form a single external relocation.
+
+     If C permitted arrays of structures with dynamic sizes, we could
+     do better, but trying to avoid wasting space at the end of the
+     chunk from rela[k] to rela[k+N-1] would require us to allocate a
+     separate array of pointers and since most ports have N == 1, this
+     would be more wasteful.  */
+  rela = (struct elf_link_sort_rela *) bfd_zmalloc
+    (sizeof (*rela) * count * i2e);
   if (rela == NULL)
     {
       (*info->callbacks->warning)
@@ -4827,15 +4804,16 @@ elf_link_sort_relocs (abfd, info, psec)
 
            erel = (Elf_External_Rel *) o->contents;
            erelend = (Elf_External_Rel *) (o->contents + o->_raw_size);
-           s = rela + o->output_offset / sizeof (Elf_External_Rel);
-           for (; erel < erelend; erel++, s++)
+           s = rela + (o->output_offset / sizeof (Elf_External_Rel) * i2e);
+           for (; erel < erelend; erel++, s += i2e)
              {
                if (bed->s->swap_reloc_in)
-                 (*bed->s->swap_reloc_in) (abfd, (bfd_byte *) erel, &s->u.rel);
+                 (*bed->s->swap_reloc_in) (abfd, (bfd_byte *) erel,
+                                           s->u.rel);
                else
-                 elf_swap_reloc_in (abfd, erel, &s->u.rel);
+                 elf_swap_reloc_in (abfd, erel, s->u.rel);
 
-               s->type = (*bed->elf_backend_reloc_type_class) (&s->u.rela);
+               s->type = (*bed->elf_backend_reloc_type_class) (s->u.rela);
              }
          }
        else
@@ -4845,30 +4823,34 @@ elf_link_sort_relocs (abfd, info, psec)
 
            erela = (Elf_External_Rela *) o->contents;
            erelaend = (Elf_External_Rela *) (o->contents + o->_raw_size);
-           s = rela + o->output_offset / sizeof (Elf_External_Rela);
-           for (; erela < erelaend; erela++, s++)
+           s = rela + (o->output_offset / sizeof (Elf_External_Rela) * i2e);
+           for (; erela < erelaend; erela++, s += i2e)
              {
                if (bed->s->swap_reloca_in)
                  (*bed->s->swap_reloca_in) (dynobj, (bfd_byte *) erela,
-                                            &s->u.rela);
+                                            s->u.rela);
                else
-                 elf_swap_reloca_in (dynobj, erela, &s->u.rela);
+                 elf_swap_reloca_in (dynobj, erela, s->u.rela);
 
-               s->type = (*bed->elf_backend_reloc_type_class) (&s->u.rela);
+               s->type = (*bed->elf_backend_reloc_type_class) (s->u.rela);
              }
          }
       }
 
-  qsort (rela, (size_t) count, sizeof (*rela), elf_link_sort_cmp1);
-  for (ret = 0; ret < count && rela[ret].type == reloc_class_relative; ret++)
+  qsort (rela, (size_t) count, sizeof (*rela) * i2e, elf_link_sort_cmp1);
+  for (ret = 0; ret < count * i2e && rela[ret].type == reloc_class_relative;
+       ret += i2e)
     ;
-  for (i = ret, j = ret; i < count; i++)
+  for (i = ret, j = ret; i < count * i2e; i += i2e)
     {
-      if (ELF_R_SYM (rela[i].u.rel.r_info) != ELF_R_SYM (rela[j].u.rel.r_info))
+      if (ELF_R_SYM (rela[i].u.rel->r_info)
+         != ELF_R_SYM (rela[j].u.rel->r_info))
        j = i;
-      rela[i].offset = rela[j].u.rel.r_offset;
+      rela[i].offset = rela[j].u.rel->r_offset;
     }
-  qsort (rela + ret, (size_t) count - ret, sizeof (*rela), elf_link_sort_cmp2);
+  ret /= i2e;
+  qsort (rela + ret, (size_t) count - ret,
+        sizeof (*rela) * i2e, elf_link_sort_cmp2);
 
   for (o = dynobj->sections; o != NULL; o = o->next)
     if ((o->flags & (SEC_HAS_CONTENTS|SEC_LINKER_CREATED))
@@ -4882,14 +4864,14 @@ elf_link_sort_relocs (abfd, info, psec)
 
            erel = (Elf_External_Rel *) o->contents;
            erelend = (Elf_External_Rel *) (o->contents + o->_raw_size);
-           s = rela + o->output_offset / sizeof (Elf_External_Rel);
-           for (; erel < erelend; erel++, s++)
+           s = rela + (o->output_offset / sizeof (Elf_External_Rel) * i2e);
+           for (; erel < erelend; erel++, s += i2e)
              {
                if (bed->s->swap_reloc_out)
-                 (*bed->s->swap_reloc_out) (abfd, &s->u.rel,
+                 (*bed->s->swap_reloc_out) (abfd, s->u.rel,
                                             (bfd_byte *) erel);
                else
-                 elf_swap_reloc_out (abfd, &s->u.rel, erel);
+                 elf_swap_reloc_out (abfd, s->u.rel, erel);
              }
          }
        else
@@ -4899,14 +4881,14 @@ elf_link_sort_relocs (abfd, info, psec)
 
            erela = (Elf_External_Rela *) o->contents;
            erelaend = (Elf_External_Rela *) (o->contents + o->_raw_size);
-           s = rela + o->output_offset / sizeof (Elf_External_Rela);
-           for (; erela < erelaend; erela++, s++)
+           s = rela + (o->output_offset / sizeof (Elf_External_Rela) * i2e);
+           for (; erela < erelaend; erela++, s += i2e)
              {
                if (bed->s->swap_reloca_out)
-                 (*bed->s->swap_reloca_out) (dynobj, &s->u.rela,
+                 (*bed->s->swap_reloca_out) (dynobj, s->u.rela,
                                              (bfd_byte *) erela);
                else
-                 elf_swap_reloca_out (dynobj, &s->u.rela, erela);
+                 elf_swap_reloca_out (dynobj, s->u.rela, erela);
              }
          }
       }
@@ -4939,6 +4921,7 @@ elf_bfd_final_link (abfd, info)
   Elf_Internal_Sym elfsym;
   unsigned int i;
   Elf_Internal_Shdr *symtab_hdr;
+  Elf_Internal_Shdr *symtab_shndx_hdr;
   Elf_Internal_Shdr *symstrtab_hdr;
   struct elf_backend_data *bed = get_elf_backend_data (abfd);
   struct elf_outext_info eoinfo;
@@ -4992,6 +4975,7 @@ elf_bfd_final_link (abfd, info)
   finfo.symbuf = NULL;
   finfo.symshndxbuf = NULL;
   finfo.symbuf_count = 0;
+  finfo.shndxbuf_size = 0;
   finfo.first_tls_sec = NULL;
   for (o = abfd->sections; o != (asection *) NULL; o = o->next)
     if ((o->flags & SEC_THREAD_LOCAL) != 0
@@ -5047,7 +5031,7 @@ elf_bfd_final_link (abfd, info)
                  o->reloc_count
                    += (*bed->elf_backend_count_relocs) (sec, relocs);
 
-                 if (!info->keep_memory)
+                 if (elf_section_data (o)->relocs != relocs)
                    free (relocs);
                }
 
@@ -5212,9 +5196,7 @@ elf_bfd_final_link (abfd, info)
   symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
   /* sh_name is set in prep_headers.  */
   symtab_hdr->sh_type = SHT_SYMTAB;
-  symtab_hdr->sh_flags = 0;
-  symtab_hdr->sh_addr = 0;
-  symtab_hdr->sh_size = 0;
+  /* sh_flags, sh_addr and sh_size all start off zero.  */
   symtab_hdr->sh_entsize = sizeof (Elf_External_Sym);
   /* sh_link is set in assign_section_numbers.  */
   /* sh_info is set below.  */
@@ -5241,9 +5223,11 @@ elf_bfd_final_link (abfd, info)
     goto error_return;
   if (elf_numsections (abfd) > SHN_LORESERVE)
     {
-      amt = finfo.symbuf_size;
+      /* Wild guess at number of output symbols.  realloc'd as needed.  */
+      amt = 2 * max_sym_count + elf_numsections (abfd) + 1000;
+      finfo.shndxbuf_size = amt;
       amt *= sizeof (Elf_External_Sym_Shndx);
-      finfo.symshndxbuf = (Elf_External_Sym_Shndx *) bfd_malloc (amt);
+      finfo.symshndxbuf = (Elf_External_Sym_Shndx *) bfd_zmalloc (amt);
       if (finfo.symshndxbuf == NULL)
        goto error_return;
     }
@@ -5303,7 +5287,7 @@ elf_bfd_final_link (abfd, info)
          if (! elf_link_output_sym (&finfo, (const char *) NULL,
                                     &elfsym, o))
            goto error_return;
-         if (i == SHN_LORESERVE)
+         if (i == SHN_LORESERVE - 1)
            i += SHN_HIRESERVE + 1 - SHN_LORESERVE;
        }
     }
@@ -5385,7 +5369,7 @@ elf_bfd_final_link (abfd, info)
              size = 0;
              for (o = sec->link_order_head; o != NULL; o = o->next)
                if (size < o->offset + o->size)
-             size = o->offset + o->size;
+                 size = o->offset + o->size;
            }
          end = sec->vma + size;
        }
@@ -5524,8 +5508,8 @@ elf_bfd_final_link (abfd, info)
              sym = e->isym;
 
              if (e->isym.st_shndx != SHN_UNDEF
-                  && (e->isym.st_shndx < SHN_LORESERVE
-                      || e->isym.st_shndx > SHN_HIRESERVE))
+                 && (e->isym.st_shndx < SHN_LORESERVE
+                     || e->isym.st_shndx > SHN_HIRESERVE))
                {
                  s = bfd_section_from_elf_index (e->input_bfd,
                                                  e->isym.st_shndx);
@@ -5578,6 +5562,24 @@ elf_bfd_final_link (abfd, info)
   /* Now we know the size of the symtab section.  */
   off += symtab_hdr->sh_size;
 
+  symtab_shndx_hdr = &elf_tdata (abfd)->symtab_shndx_hdr;
+  if (symtab_shndx_hdr->sh_name != 0)
+    {
+      symtab_shndx_hdr->sh_type = SHT_SYMTAB_SHNDX;
+      symtab_shndx_hdr->sh_entsize = sizeof (Elf_External_Sym_Shndx);
+      symtab_shndx_hdr->sh_addralign = sizeof (Elf_External_Sym_Shndx);
+      amt = bfd_get_symcount (abfd) * sizeof (Elf_External_Sym_Shndx);
+      symtab_shndx_hdr->sh_size = amt;
+
+      off = _bfd_elf_assign_file_position_for_section (symtab_shndx_hdr,
+                                                      off, true);
+
+      if (bfd_seek (abfd, symtab_shndx_hdr->sh_offset, SEEK_SET) != 0
+         || (bfd_bwrite ((PTR) finfo.symshndxbuf, amt, abfd) != amt))
+       return false;
+    }
+
+
   /* Finish up and write out the symbol string table (.strtab)
      section.  */
   symstrtab_hdr = &elf_tdata (abfd)->strtab_hdr;
@@ -5886,7 +5888,7 @@ elf_bfd_final_link (abfd, info)
   if (finfo.symbuf != NULL)
     free (finfo.symbuf);
   if (finfo.symshndxbuf != NULL)
-    free (finfo.symbuf);
+    free (finfo.symshndxbuf);
   for (o = abfd->sections; o != NULL; o = o->next)
     {
       if ((o->flags & SEC_RELOC) != 0
@@ -5920,7 +5922,7 @@ elf_bfd_final_link (abfd, info)
   if (finfo.symbuf != NULL)
     free (finfo.symbuf);
   if (finfo.symshndxbuf != NULL)
-    free (finfo.symbuf);
+    free (finfo.symshndxbuf);
   for (o = abfd->sections; o != NULL; o = o->next)
     {
       if ((o->flags & SEC_RELOC) != 0
@@ -5979,11 +5981,24 @@ elf_link_output_sym (finfo, name, elfsym, input_sec)
   dest = finfo->symbuf + finfo->symbuf_count;
   destshndx = finfo->symshndxbuf;
   if (destshndx != NULL)
-    destshndx += finfo->symbuf_count;
-  elf_swap_symbol_out (finfo->output_bfd, elfsym, (PTR) dest, (PTR) destshndx);
-  ++finfo->symbuf_count;
+    {
+      if (bfd_get_symcount (finfo->output_bfd) >= finfo->shndxbuf_size)
+       {
+         bfd_size_type amt;
 
-  ++ bfd_get_symcount (finfo->output_bfd);
+         amt = finfo->shndxbuf_size * sizeof (Elf_External_Sym_Shndx);
+         finfo->symshndxbuf = destshndx = bfd_realloc (destshndx, amt * 2);
+         if (destshndx == NULL)
+           return false;
+         memset ((char *) destshndx + amt, 0, amt);
+         finfo->shndxbuf_size *= 2;
+       }
+      destshndx += bfd_get_symcount (finfo->output_bfd);
+    }
+
+  elf_swap_symbol_out (finfo->output_bfd, elfsym, (PTR) dest, (PTR) destshndx);
+  finfo->symbuf_count += 1;
+  bfd_get_symcount (finfo->output_bfd) += 1;
 
   return true;
 }
@@ -6008,20 +6023,6 @@ elf_link_flush_output_syms (finfo)
        return false;
 
       hdr->sh_size += amt;
-
-      if (finfo->symshndxbuf != NULL)
-       {
-         hdr = &elf_tdata (finfo->output_bfd)->symtab_shndx_hdr;
-         pos = hdr->sh_offset + hdr->sh_size;
-         amt = finfo->symbuf_count * sizeof (Elf_External_Sym_Shndx);
-         if (bfd_seek (finfo->output_bfd, pos, SEEK_SET) != 0
-             || (bfd_bwrite ((PTR) finfo->symshndxbuf, amt, finfo->output_bfd)
-                 != amt))
-           return false;
-
-         hdr->sh_size += amt;
-       }
-
       finfo->symbuf_count = 0;
     }
 
@@ -6069,8 +6070,6 @@ elf_link_check_versioned_symbol (info, h)
 {
   bfd *undef_bfd = h->root.u.undef.abfd;
   struct elf_link_loaded_list *loaded;
-  Elf_External_Sym *buf;
-  Elf_External_Versym *extversym;
 
   if ((undef_bfd->flags & DYNAMIC) == 0
       || info->hash->creator->flavour != bfd_target_elf_flavour
@@ -6087,11 +6086,11 @@ elf_link_check_versioned_symbol (info, h)
       bfd_size_type extsymcount;
       bfd_size_type extsymoff;
       Elf_Internal_Shdr *versymhdr;
+      Elf_Internal_Sym *isym;
+      Elf_Internal_Sym *isymend;
+      Elf_Internal_Sym *isymbuf;
       Elf_External_Versym *ever;
-      Elf_External_Sym *esym;
-      Elf_External_Sym *esymend;
-      bfd_size_type count;
-      file_ptr pos;
+      Elf_External_Versym *extversym;
 
       input = loaded->abfd;
 
@@ -6118,17 +6117,11 @@ elf_link_check_versioned_symbol (info, h)
       if (extsymcount == 0)
        continue;
 
-      count = extsymcount * sizeof (Elf_External_Sym);
-      buf = (Elf_External_Sym *) bfd_malloc (count);
-      if (buf == NULL)
+      isymbuf = bfd_elf_get_elf_syms (input, hdr, extsymcount, extsymoff,
+                                     NULL, NULL, NULL);
+      if (isymbuf == NULL)
        return false;
 
-      /* Read in the symbol table.  */
-      pos = hdr->sh_offset + extsymoff * sizeof (Elf_External_Sym);
-      if (bfd_seek (input, pos, SEEK_SET) != 0
-         || bfd_bread ((PTR) buf, count, input) != count)
-       goto error_ret;
-
       /* Read in any version definitions.  */
       versymhdr = &elf_tdata (input)->dynversym_hdr;
       extversym = (Elf_External_Versym *) bfd_malloc (versymhdr->sh_size);
@@ -6141,26 +6134,24 @@ elf_link_check_versioned_symbol (info, h)
        {
          free (extversym);
        error_ret:
-         free (buf);
+         free (isymbuf);
          return false;
        }
 
       ever = extversym + extsymoff;
-      esymend = buf + extsymcount;
-      for (esym = buf; esym < esymend; esym++, ever++)
+      isymend = isymbuf + extsymcount;
+      for (isym = isymbuf; isym < isymend; isym++, ever++)
        {
          const char *name;
-         Elf_Internal_Sym sym;
          Elf_Internal_Versym iver;
 
-         elf_swap_symbol_in (input, esym, NULL, &sym);
-         if (ELF_ST_BIND (sym.st_info) == STB_LOCAL
-             || sym.st_shndx == SHN_UNDEF)
+         if (ELF_ST_BIND (isym->st_info) == STB_LOCAL
+             || isym->st_shndx == SHN_UNDEF)
            continue;
 
          name = bfd_elf_string_from_elf_section (input,
                                                  hdr->sh_link,
-                                                 sym.st_name);
+                                                 isym->st_name);
          if (strcmp (name, h->root.root.string) != 0)
            continue;
 
@@ -6177,13 +6168,13 @@ elf_link_check_versioned_symbol (info, h)
            {
              /* This is the oldest (default) sym.  We can use it.  */
              free (extversym);
-             free (buf);
+             free (isymbuf);
              return true;
            }
        }
 
       free (extversym);
-      free (buf);
+      free (isymbuf);
     }
 
   return false;
@@ -6472,7 +6463,7 @@ elf_link_output_extsym (h, data)
 
   /* If we're stripping it, then it was just a dynamic symbol, and
      there's nothing else to do.  */
-  if (strip)
+  if (strip || (input_sec->flags & SEC_EXCLUDE) != 0)
     return true;
 
   h->indx = bfd_get_symcount (finfo->output_bfd);
@@ -6524,19 +6515,19 @@ elf_link_output_relocs (output_bfd, input_section, input_rel_hdr,
     }
   else
     {
-      (*_bfd_error_handler) (
-        _("%s: relocation size mismatch in %s section %s"),
-        bfd_get_filename (output_bfd),
-        bfd_archive_filename (input_section->owner),
-        input_section->name);
+      (*_bfd_error_handler)
+       (_("%s: relocation size mismatch in %s section %s"),
+        bfd_get_filename (output_bfd),
+        bfd_archive_filename (input_section->owner),
+        input_section->name);
       bfd_set_error (bfd_error_wrong_object_format);
       return false;
     }
 
   bed = get_elf_backend_data (output_bfd);
   irela = internal_relocs;
-  irelaend = irela + NUM_SHDR_ENTRIES (input_rel_hdr)
-                    * bed->s->int_rels_per_ext_rel;
+  irelaend = irela + (NUM_SHDR_ENTRIES (input_rel_hdr)
+                     * bed->s->int_rels_per_ext_rel);
 
   if (input_rel_hdr->sh_entsize == sizeof (Elf_External_Rel))
     {
@@ -6608,15 +6599,11 @@ elf_link_input_bfd (finfo, input_bfd)
                                       Elf_Internal_Sym *, asection **));
   bfd *output_bfd;
   Elf_Internal_Shdr *symtab_hdr;
-  Elf_Internal_Shdr *shndx_hdr;
   size_t locsymcount;
   size_t extsymoff;
-  Elf_External_Sym *external_syms;
-  Elf_External_Sym *esym;
-  Elf_External_Sym *esymend;
-  Elf_External_Sym_Shndx *shndx_buf;
-  Elf_External_Sym_Shndx *shndx;
+  Elf_Internal_Sym *isymbuf;
   Elf_Internal_Sym *isym;
+  Elf_Internal_Sym *isymend;
   long *pindex;
   asection **ppsection;
   asection *o;
@@ -6651,45 +6638,29 @@ elf_link_input_bfd (finfo, input_bfd)
     }
 
   /* Read the local symbols.  */
-  if (symtab_hdr->contents != NULL)
-    external_syms = (Elf_External_Sym *) symtab_hdr->contents;
-  else if (locsymcount == 0)
-    external_syms = NULL;
-  else
-    {
-      bfd_size_type amt = locsymcount * sizeof (Elf_External_Sym);
-      external_syms = finfo->external_syms;
-      if (bfd_seek (input_bfd, symtab_hdr->sh_offset, SEEK_SET) != 0
-         || bfd_bread (external_syms, amt, input_bfd) != amt)
-       return false;
-    }
-
-  shndx_hdr = &elf_tdata (input_bfd)->symtab_shndx_hdr;
-  shndx_buf = NULL;
-  if (shndx_hdr->sh_size != 0 && locsymcount != 0)
-    {
-      bfd_size_type amt = locsymcount * sizeof (Elf_External_Sym_Shndx);
-      shndx_buf = finfo->locsym_shndx;
-      if (bfd_seek (input_bfd, shndx_hdr->sh_offset, SEEK_SET) != 0
-         || bfd_bread (shndx_buf, amt, input_bfd) != amt)
+  isymbuf = (Elf_Internal_Sym *) symtab_hdr->contents;
+  if (isymbuf == NULL && locsymcount != 0)
+    {
+      isymbuf = bfd_elf_get_elf_syms (input_bfd, symtab_hdr, locsymcount, 0,
+                                     finfo->internal_syms,
+                                     finfo->external_syms,
+                                     finfo->locsym_shndx);
+      if (isymbuf == NULL)
        return false;
     }
 
-  /* Swap in the local symbols and write out the ones which we know
-     are going into the output file.  */
-  for (esym = external_syms, esymend = esym + locsymcount,
-        isym = finfo->internal_syms, pindex = finfo->indices,
-        ppsection = finfo->sections, shndx = shndx_buf;
-       esym < esymend;
-       esym++, isym++, pindex++, ppsection++,
-        shndx = (shndx != NULL ? shndx + 1 : NULL))
+  /* Find local symbol sections and adjust values of symbols in
+     SEC_MERGE sections.  Write out those local symbols we know are
+     going into the output file.  */
+  isymend = isymbuf + locsymcount;
+  for (isym = isymbuf, pindex = finfo->indices, ppsection = finfo->sections;
+       isym < isymend;
+       isym++, pindex++, ppsection++)
     {
       asection *isec;
       const char *name;
       Elf_Internal_Sym osym;
 
-      elf_swap_symbol_in (input_bfd, (const PTR) esym, (const PTR) shndx,
-                         isym);
       *pindex = -1;
 
       if (elf_bad_symtab (input_bfd))
@@ -6728,7 +6699,7 @@ elf_link_input_bfd (finfo, input_bfd)
       *ppsection = isec;
 
       /* Don't output the first, undefined, symbol.  */
-      if (esym == external_syms)
+      if (ppsection == finfo->sections)
        continue;
 
       if (ELF_ST_TYPE (isym->st_info) == STT_SECTION)
@@ -6902,20 +6873,12 @@ elf_link_input_bfd (finfo, input_bfd)
                           || h->root.type == bfd_link_hash_defweak)
                          && elf_discarded_section (h->root.u.def.section))
                        {
-#if BFD_VERSION_DATE < 20031005
                          if ((o->flags & SEC_DEBUGGING) != 0)
                            {
-#if BFD_VERSION_DATE > 20021005
-                             (*finfo->info->callbacks->warning)
-                               (finfo->info,
-                                _("warning: relocation against removed section; zeroing"),
-                                NULL, input_bfd, o, rel->r_offset);
-#endif
                              BFD_ASSERT (r_symndx != 0);
                              memset (rel, 0, sizeof (*rel));
                            }
                          else
-#endif
                            {
                              if (! ((*finfo->info->callbacks->undefined_symbol)
                                     (finfo->info, h->root.root.string,
@@ -6931,23 +6894,15 @@ elf_link_input_bfd (finfo, input_bfd)
 
                      if (sec != NULL && elf_discarded_section (sec))
                        {
-#if BFD_VERSION_DATE < 20031005
                          if ((o->flags & SEC_DEBUGGING) != 0
                              || (sec->flags & SEC_LINK_ONCE) != 0)
                            {
-#if BFD_VERSION_DATE > 20021005
-                             (*finfo->info->callbacks->warning)
-                               (finfo->info,
-                                _("warning: relocation against removed section"),
-                                NULL, input_bfd, o, rel->r_offset);
-#endif
                              BFD_ASSERT (r_symndx != 0);
                              rel->r_info
                                = ELF_R_INFO (0, ELF_R_TYPE (rel->r_info));
                              rel->r_addend = 0;
                            }
                          else
-#endif
                            {
                              boolean ok;
                              const char *msg
@@ -6998,7 +6953,7 @@ elf_link_input_bfd (finfo, input_bfd)
          if (! (*relocate_section) (output_bfd, finfo->info,
                                     input_bfd, o, contents,
                                     internal_relocs,
-                                    finfo->internal_syms,
+                                    isymbuf,
                                     finfo->sections))
            return false;
 
@@ -7007,7 +6962,7 @@ elf_link_input_bfd (finfo, input_bfd)
              Elf_Internal_Rela *irela;
              Elf_Internal_Rela *irelaend;
              struct elf_link_hash_entry **rel_hash;
-             Elf_Internal_Shdr *input_rel_hdr;
+             Elf_Internal_Shdr *input_rel_hdr, *input_rel_hdr2;
              unsigned int next_erel;
              boolean (*reloc_emitter) PARAMS ((bfd *, asection *,
                                                Elf_Internal_Shdr *,
@@ -7030,6 +6985,7 @@ elf_link_input_bfd (finfo, input_bfd)
                {
                  unsigned long r_symndx;
                  asection *sec;
+                 Elf_Internal_Sym sym;
 
                  if (next_erel == bed->s->int_rels_per_ext_rel)
                    {
@@ -7082,9 +7038,9 @@ elf_link_input_bfd (finfo, input_bfd)
                  /* This is a reloc against a local symbol.  */
 
                  *rel_hash = NULL;
-                 isym = finfo->internal_syms + r_symndx;
+                 sym = isymbuf[r_symndx];
                  sec = finfo->sections[r_symndx];
-                 if (ELF_ST_TYPE (isym->st_info) == STT_SECTION)
+                 if (ELF_ST_TYPE (sym.st_info) == STT_SECTION)
                    {
                      /* I suppose the backend ought to fill in the
                         section of any STT_SECTION symbol against a
@@ -7131,34 +7087,34 @@ elf_link_input_bfd (finfo, input_bfd)
                             must output it now.  */
                          shlink = symtab_hdr->sh_link;
                          name = (bfd_elf_string_from_elf_section
-                                 (input_bfd, shlink, isym->st_name));
+                                 (input_bfd, shlink, sym.st_name));
                          if (name == NULL)
                            return false;
 
                          osec = sec->output_section;
-                         isym->st_shndx =
+                         sym.st_shndx =
                            _bfd_elf_section_from_bfd_section (output_bfd,
                                                               osec);
-                         if (isym->st_shndx == SHN_BAD)
+                         if (sym.st_shndx == SHN_BAD)
                            return false;
 
-                         isym->st_value += sec->output_offset;
+                         sym.st_value += sec->output_offset;
                          if (! finfo->info->relocateable)
                            {
-                             isym->st_value += osec->vma;
-                             if (ELF_ST_TYPE (isym->st_info) == STT_TLS)
+                             sym.st_value += osec->vma;
+                             if (ELF_ST_TYPE (sym.st_info) == STT_TLS)
                                {
                                  /* STT_TLS symbols are relative to PT_TLS
                                     segment base.  */
                                  BFD_ASSERT (finfo->first_tls_sec != NULL);
-                                 isym->st_value -= finfo->first_tls_sec->vma;
+                                 sym.st_value -= finfo->first_tls_sec->vma;
                                }
                            }
 
                          finfo->indices[r_symndx]
                            = bfd_get_symcount (output_bfd);
 
-                         if (! elf_link_output_sym (finfo, name, isym, sec))
+                         if (! elf_link_output_sym (finfo, name, &sym, sec))
                            return false;
                        }
 
@@ -7177,20 +7133,20 @@ elf_link_input_bfd (finfo, input_bfd)
              else
                reloc_emitter = elf_link_output_relocs;
 
-             if (! (*reloc_emitter) (output_bfd, o, input_rel_hdr,
-                                     internal_relocs))
+             if (input_rel_hdr->sh_size != 0
+                 && ! (*reloc_emitter) (output_bfd, o, input_rel_hdr,
+                                        internal_relocs))
                return false;
 
-             input_rel_hdr = elf_section_data (o)->rel_hdr2;
-             if (input_rel_hdr)
+             input_rel_hdr2 = elf_section_data (o)->rel_hdr2;
+             if (input_rel_hdr2 && input_rel_hdr2->sh_size != 0)
                {
                  internal_relocs += (NUM_SHDR_ENTRIES (input_rel_hdr)
                                      * bed->s->int_rels_per_ext_rel);
-                 if (! (*reloc_emitter) (output_bfd, o, input_rel_hdr,
+                 if (! (*reloc_emitter) (output_bfd, o, input_rel_hdr2,
                                          internal_relocs))
                    return false;
                }
-
            }
        }
 
@@ -7707,28 +7663,27 @@ elf_finish_pointer_linker_section (output_bfd, input_bfd, info, lsect, h,
 /* Garbage collect unused sections.  */
 
 static boolean elf_gc_mark
-  PARAMS ((struct bfd_link_info *info, asection *sec,
-          asection * (*gc_mark_hook)
-            PARAMS ((bfd *, struct bfd_link_info *, Elf_Internal_Rela *,
-                     struct elf_link_hash_entry *, Elf_Internal_Sym *))));
+  PARAMS ((struct bfd_link_info *, asection *,
+          asection * (*) (asection *, struct bfd_link_info *,
+                          Elf_Internal_Rela *, struct elf_link_hash_entry *,
+                          Elf_Internal_Sym *)));
 
 static boolean elf_gc_sweep
-  PARAMS ((struct bfd_link_info *info,
-          boolean (*gc_sweep_hook)
-            PARAMS ((bfd *abfd, struct bfd_link_info *info, asection *o,
-                     const Elf_Internal_Rela *relocs))));
+  PARAMS ((struct bfd_link_info *,
+          boolean (*) (bfd *, struct bfd_link_info *, asection *,
+                       const Elf_Internal_Rela *)));
 
 static boolean elf_gc_sweep_symbol
-  PARAMS ((struct elf_link_hash_entry *h, PTR idxptr));
+  PARAMS ((struct elf_link_hash_entry *, PTR));
 
 static boolean elf_gc_allocate_got_offsets
-  PARAMS ((struct elf_link_hash_entry *h, PTR offarg));
+  PARAMS ((struct elf_link_hash_entry *, PTR));
 
 static boolean elf_gc_propagate_vtable_entries_used
-  PARAMS ((struct elf_link_hash_entry *h, PTR dummy));
+  PARAMS ((struct elf_link_hash_entry *, PTR));
 
 static boolean elf_gc_smash_unused_vtentry_relocs
-  PARAMS ((struct elf_link_hash_entry *h, PTR dummy));
+  PARAMS ((struct elf_link_hash_entry *, PTR));
 
 /* The mark phase of garbage collection.  For a given section, mark
    it and any sections in this section's group, and all the sections
@@ -7738,9 +7693,10 @@ static boolean
 elf_gc_mark (info, sec, gc_mark_hook)
      struct bfd_link_info *info;
      asection *sec;
-     asection * (*gc_mark_hook)
-       PARAMS ((bfd *, struct bfd_link_info *, Elf_Internal_Rela *,
-               struct elf_link_hash_entry *, Elf_Internal_Sym *));
+     asection * (*gc_mark_hook) PARAMS ((asection *, struct bfd_link_info *,
+                                        Elf_Internal_Rela *,
+                                        struct elf_link_hash_entry *,
+                                        Elf_Internal_Sym *));
 {
   boolean ret;
   asection *group_sec;
@@ -7759,17 +7715,12 @@ elf_gc_mark (info, sec, gc_mark_hook)
     {
       Elf_Internal_Rela *relstart, *rel, *relend;
       Elf_Internal_Shdr *symtab_hdr;
-      Elf_Internal_Shdr *shndx_hdr;
       struct elf_link_hash_entry **sym_hashes;
       size_t nlocsyms;
       size_t extsymoff;
-      Elf_External_Sym *locsyms, *freesyms = NULL;
-      Elf_External_Sym_Shndx *locsym_shndx;
       bfd *input_bfd = sec->owner;
       struct elf_backend_data *bed = get_elf_backend_data (input_bfd);
-
-      /* GCFIXME: how to arrange so that relocs and symbols are not
-        reread continually?  */
+      Elf_Internal_Sym *isym = NULL;
 
       symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
       sym_hashes = elf_sym_hashes (input_bfd);
@@ -7783,37 +7734,18 @@ elf_gc_mark (info, sec, gc_mark_hook)
       else
        extsymoff = nlocsyms = symtab_hdr->sh_info;
 
-      if (symtab_hdr->contents)
-       locsyms = (Elf_External_Sym *) symtab_hdr->contents;
-      else if (nlocsyms == 0)
-       locsyms = NULL;
-      else
+      isym = (Elf_Internal_Sym *) symtab_hdr->contents;
+      if (isym == NULL && nlocsyms != 0)
        {
-         bfd_size_type amt = nlocsyms * sizeof (Elf_External_Sym);
-         locsyms = freesyms = bfd_malloc (amt);
-         if (freesyms == NULL
-             || bfd_seek (input_bfd, symtab_hdr->sh_offset, SEEK_SET) != 0
-             || bfd_bread (locsyms, amt, input_bfd) != amt)
-           {
-             ret = false;
-             goto out1;
-           }
-       }
-
-      shndx_hdr = &elf_tdata (input_bfd)->symtab_shndx_hdr;
-      locsym_shndx = NULL;
-      if (shndx_hdr->sh_size != 0 && nlocsyms != 0)
-       {
-         bfd_size_type amt = nlocsyms * sizeof (Elf_External_Sym_Shndx);
-         locsym_shndx = (Elf_External_Sym_Shndx *) bfd_malloc (amt);
-         if (bfd_seek (input_bfd, shndx_hdr->sh_offset, SEEK_SET) != 0
-             || bfd_bread (locsym_shndx, amt, input_bfd) != amt)
+         isym = bfd_elf_get_elf_syms (input_bfd, symtab_hdr, nlocsyms, 0,
+                                      NULL, NULL, NULL);
+         if (isym == NULL)
            return false;
        }
 
       /* Read the relocations.  */
       relstart = (NAME(_bfd_elf,link_read_relocs)
-                 (sec->owner, sec, NULL, (Elf_Internal_Rela *) NULL,
+                 (input_bfd, sec, NULL, (Elf_Internal_Rela *) NULL,
                   info->keep_memory));
       if (relstart == NULL)
        {
@@ -7827,41 +7759,20 @@ elf_gc_mark (info, sec, gc_mark_hook)
          unsigned long r_symndx;
          asection *rsec;
          struct elf_link_hash_entry *h;
-         Elf_Internal_Sym s;
-         Elf_External_Sym_Shndx *locshndx;
 
          r_symndx = ELF_R_SYM (rel->r_info);
          if (r_symndx == 0)
            continue;
 
-         if (elf_bad_symtab (sec->owner))
-           {
-             locshndx = locsym_shndx + (locsym_shndx ? r_symndx : 0);
-             elf_swap_symbol_in (input_bfd,
-                                 (const PTR) (locsyms + r_symndx),
-                                 (const PTR) locshndx,
-                                 &s);
-             if (ELF_ST_BIND (s.st_info) == STB_LOCAL)
-               rsec = (*gc_mark_hook) (sec->owner, info, rel, NULL, &s);
-             else
-               {
-                 h = sym_hashes[r_symndx - extsymoff];
-                 rsec = (*gc_mark_hook) (sec->owner, info, rel, h, NULL);
-               }
-           }
-         else if (r_symndx >= nlocsyms)
+         if (r_symndx >= nlocsyms
+             || ELF_ST_BIND (isym[r_symndx].st_info) != STB_LOCAL)
            {
              h = sym_hashes[r_symndx - extsymoff];
-             rsec = (*gc_mark_hook) (sec->owner, info, rel, h, NULL);
+             rsec = (*gc_mark_hook) (sec, info, rel, h, NULL);
            }
          else
            {
-             locshndx = locsym_shndx + (locsym_shndx ? r_symndx : 0);
-             elf_swap_symbol_in (input_bfd,
-                                 (const PTR) (locsyms + r_symndx),
-                                 (const PTR) locshndx,
-                                 &s);
-             rsec = (*gc_mark_hook) (sec->owner, info, rel, NULL, &s);
+             rsec = (*gc_mark_hook) (sec, info, rel, NULL, &isym[r_symndx]);
            }
 
          if (rsec && !rsec->gc_mark)
@@ -7877,11 +7788,16 @@ elf_gc_mark (info, sec, gc_mark_hook)
        }
 
     out2:
-      if (!info->keep_memory)
+      if (elf_section_data (sec)->relocs != relstart)
        free (relstart);
     out1:
-      if (freesyms)
-       free (freesyms);
+      if (isym != NULL && symtab_hdr->contents != (unsigned char *) isym)
+       {
+         if (! info->keep_memory)
+           free (isym);
+         else
+           symtab_hdr->contents = (unsigned char *) isym;
+       }
     }
 
   return ret;
@@ -7892,9 +7808,8 @@ elf_gc_mark (info, sec, gc_mark_hook)
 static boolean
 elf_gc_sweep (info, gc_sweep_hook)
      struct bfd_link_info *info;
-     boolean (*gc_sweep_hook)
-       PARAMS ((bfd *abfd, struct bfd_link_info *info, asection *o,
-               const Elf_Internal_Rela *relocs));
+     boolean (*gc_sweep_hook) PARAMS ((bfd *, struct bfd_link_info *,
+                                      asection *, const Elf_Internal_Rela *));
 {
   bfd *sub;
 
@@ -7938,7 +7853,7 @@ elf_gc_sweep (info, gc_sweep_hook)
 
              r = (*gc_sweep_hook) (o->owner, info, o, internal_relocs);
 
-             if (!info->keep_memory)
+             if (elf_section_data (o)->relocs != internal_relocs)
                free (internal_relocs);
 
              if (!r)
@@ -8109,7 +8024,7 @@ elf_gc_sections (abfd, info)
   boolean ok = true;
   bfd *sub;
   asection * (*gc_mark_hook)
-    PARAMS ((bfd *, struct bfd_link_info *, Elf_Internal_Rela *,
+    PARAMS ((asection *, struct bfd_link_info *, Elf_Internal_Rela *,
             struct elf_link_hash_entry *h, Elf_Internal_Sym *));
 
   if (!get_elf_backend_data (abfd)->can_gc_sections
@@ -8436,7 +8351,6 @@ elf_reloc_symbol_deleted_p (offset, cookie)
   for (; rcookie->rel < rcookie->relend; rcookie->rel++)
     {
       unsigned long r_symndx = ELF_R_SYM (rcookie->rel->r_info);
-      Elf_Internal_Sym isym;
 
       if (! rcookie->bad_symtab)
        if (rcookie->rel->r_offset > offset)
@@ -8444,22 +8358,8 @@ elf_reloc_symbol_deleted_p (offset, cookie)
       if (rcookie->rel->r_offset != offset)
        continue;
 
-      if (rcookie->locsyms && r_symndx < rcookie->locsymcount)
-       {
-         Elf_External_Sym *lsym;
-         Elf_External_Sym_Shndx *lshndx;
-
-         lsym = (Elf_External_Sym *) rcookie->locsyms + r_symndx;
-         lshndx = (Elf_External_Sym_Shndx *) rcookie->locsym_shndx;
-         if (lshndx != NULL)
-           lshndx += r_symndx;
-         elf_swap_symbol_in (rcookie->abfd, (const PTR) lsym,
-                             (const PTR) lshndx, &isym);
-       }
-
       if (r_symndx >= rcookie->locsymcount
-         || (rcookie->locsyms
-             && ELF_ST_BIND (isym.st_info) != STB_LOCAL))
+         || ELF_ST_BIND (rcookie->locsyms[r_symndx].st_info) != STB_LOCAL)
        {
          struct elf_link_hash_entry *h;
 
@@ -8476,17 +8376,19 @@ elf_reloc_symbol_deleted_p (offset, cookie)
          else
            return false;
        }
-      else if (rcookie->locsyms)
+      else
        {
          /* It's not a relocation against a global symbol,
             but it could be a relocation against a local
             symbol for a discarded section.  */
          asection *isec;
+         Elf_Internal_Sym *isym;
 
          /* Need to: get the symbol; get the section.  */
-         if (isym.st_shndx < SHN_LORESERVE || isym.st_shndx > SHN_HIRESERVE)
+         isym = &rcookie->locsyms[r_symndx];
+         if (isym->st_shndx < SHN_LORESERVE || isym->st_shndx > SHN_HIRESERVE)
            {
-             isec = section_from_elf_index (rcookie->abfd, isym.st_shndx);
+             isec = section_from_elf_index (rcookie->abfd, isym->st_shndx);
              if (isec != NULL && elf_discarded_section (isec))
                return true;
            }
@@ -8509,8 +8411,6 @@ elf_bfd_discard_info (output_bfd, info)
   struct elf_reloc_cookie cookie;
   asection *stab, *eh, *ehdr;
   Elf_Internal_Shdr *symtab_hdr;
-  Elf_Internal_Shdr *shndx_hdr;
-  Elf_External_Sym *freesyms;
   struct elf_backend_data *bed;
   bfd *abfd;
   boolean ret = false;
@@ -8561,8 +8461,6 @@ elf_bfd_discard_info (output_bfd, info)
        continue;
 
       symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
-      shndx_hdr = &elf_tdata (abfd)->symtab_shndx_hdr;
-
       cookie.abfd = abfd;
       cookie.sym_hashes = elf_sym_hashes (abfd);
       cookie.bad_symtab = elf_bad_symtab (abfd);
@@ -8578,48 +8476,20 @@ elf_bfd_discard_info (output_bfd, info)
          cookie.extsymoff = symtab_hdr->sh_info;
        }
 
-      freesyms = NULL;
-      if (symtab_hdr->contents)
-       cookie.locsyms = (void *) symtab_hdr->contents;
-      else if (cookie.locsymcount == 0)
-       cookie.locsyms = NULL;
-      else
+      cookie.locsyms = (Elf_Internal_Sym *) symtab_hdr->contents;
+      if (cookie.locsyms == NULL && cookie.locsymcount != 0)
        {
-         bfd_size_type amt = cookie.locsymcount * sizeof (Elf_External_Sym);
-         cookie.locsyms = bfd_malloc (amt);
+         cookie.locsyms = bfd_elf_get_elf_syms (abfd, symtab_hdr,
+                                                cookie.locsymcount, 0,
+                                                NULL, NULL, NULL);
          if (cookie.locsyms == NULL)
            return false;
-         freesyms = cookie.locsyms;
-         if (bfd_seek (abfd, symtab_hdr->sh_offset, SEEK_SET) != 0
-             || bfd_bread (cookie.locsyms, amt, abfd) != amt)
-           {
-           error_ret_free_loc:
-             free (cookie.locsyms);
-             return false;
-           }
-       }
-
-      cookie.locsym_shndx = NULL;
-      if (shndx_hdr->sh_size != 0 && cookie.locsymcount != 0)
-       {
-         bfd_size_type amt;
-         amt = cookie.locsymcount * sizeof (Elf_External_Sym_Shndx);
-         cookie.locsym_shndx = bfd_malloc (amt);
-         if (cookie.locsym_shndx == NULL)
-           goto error_ret_free_loc;
-         if (bfd_seek (abfd, shndx_hdr->sh_offset, SEEK_SET) != 0
-             || bfd_bread (cookie.locsym_shndx, amt, abfd) != amt)
-           {
-             free (cookie.locsym_shndx);
-             goto error_ret_free_loc;
-           }
        }
 
       if (stab)
        {
          cookie.rels = (NAME(_bfd_elf,link_read_relocs)
-                        (abfd, stab, (PTR) NULL,
-                         (Elf_Internal_Rela *) NULL,
+                        (abfd, stab, (PTR) NULL, (Elf_Internal_Rela *) NULL,
                          info->keep_memory));
          if (cookie.rels)
            {
@@ -8631,7 +8501,7 @@ elf_bfd_discard_info (output_bfd, info)
                                              elf_reloc_symbol_deleted_p,
                                              &cookie))
                ret = true;
-             if (! info->keep_memory)
+             if (elf_section_data (stab)->relocs != cookie.rels)
                free (cookie.rels);
            }
        }
@@ -8654,8 +8524,13 @@ elf_bfd_discard_info (output_bfd, info)
          if (_bfd_elf_discard_section_eh_frame (abfd, info, eh, ehdr,
                                                 elf_reloc_symbol_deleted_p,
                                                 &cookie))
-           ret = true;
-         if (! info->keep_memory)
+           {
+             /* Relocs have been edited.  Ensure edited version is
+                used later in relocate_section.  */
+             elf_section_data (eh)->relocs = cookie.rels;
+             ret = true;
+           }
+         if (cookie.rels && elf_section_data (eh)->relocs != cookie.rels)
            free (cookie.rels);
        }
 
@@ -8665,11 +8540,14 @@ elf_bfd_discard_info (output_bfd, info)
            ret = true;
        }
 
-      if (cookie.locsym_shndx != NULL)
-       free (cookie.locsym_shndx);
-
-      if (freesyms != NULL)
-       free (freesyms);
+      if (cookie.locsyms != NULL
+         && symtab_hdr->contents != (unsigned char *) cookie.locsyms)
+       {
+         if (! info->keep_memory)
+           free (cookie.locsyms);
+         else
+           symtab_hdr->contents = (unsigned char *) cookie.locsyms;
+       }
     }
 
   if (ehdr && _bfd_elf_discard_section_eh_frame_hdr (output_bfd, info, ehdr))
This page took 0.071748 seconds and 4 git commands to generate.