* elf-bfd.h (struct elf_reloc_cookie): Remove locsym_shndx,
[deliverable/binutils-gdb.git] / bfd / elflink.h
index 6c1d0d92b8b9db43fc51ff5e0ddff869bd75e406..57819e9958930554d87b7e45ae5ed824808d966b 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;
 }
@@ -1186,25 +1151,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);
@@ -1303,85 +1263,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
@@ -1431,6 +1313,7 @@ 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;
@@ -1444,11 +1327,11 @@ 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;
 
          extdyn = dynbuf;
@@ -1465,7 +1348,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)
                {
@@ -1477,11 +1360,11 @@ 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;
+                   goto error_free_dyn;
                  amt = strlen (fnm) + 1;
                  anm = bfd_alloc (abfd, amt);
                  if (anm == NULL)
-                   goto error_return;
+                   goto error_free_dyn;
                  memcpy (anm, fnm, (size_t) amt);
                  n->name = anm;
                  n->by = abfd;
@@ -1509,11 +1392,11 @@ 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;
+                   goto error_free_dyn;
                  amt = strlen (fnm) + 1;
                  anm = bfd_alloc (abfd, amt);
                  if (anm == NULL)
-                   goto error_return;
+                   goto error_free_dyn;
                  memcpy (anm, fnm, (size_t) amt);
                  n->name = anm;
                  n->by = abfd;
@@ -1537,11 +1420,15 @@ 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;
+                   goto error_free_dyn;
                  amt = strlen (fnm) + 1;
                  anm = bfd_alloc (abfd, amt);
                  if (anm == NULL)
-                   goto error_return;
+                   {
+                   error_free_dyn:
+                     free (dynbuf);
+                     goto error_return;
+                   }
                  memcpy (anm, fnm, (size_t) amt);
                  n->name = anm;
                  n->by = abfd;
@@ -1556,7 +1443,6 @@ elf_link_add_object_symbols (abfd, info)
            }
 
          free (dynbuf);
-         dynbuf = NULL;
        }
 
       /* We do not want to include any of the sections in a dynamic
@@ -1606,10 +1492,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;
                    }
@@ -1627,31 +1509,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;
@@ -1666,14 +1596,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
@@ -1684,8 +1612,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)
@@ -1695,35 +1623,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");
 
@@ -1735,15 +1665,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.  */
@@ -1755,7 +1685,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)
@@ -1789,7 +1719,7 @@ elf_link_add_object_symbols (abfd, info)
                  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)
                        {
@@ -1798,7 +1728,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 =
@@ -1838,7 +1768,7 @@ 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;
                        }
                    }
 
@@ -1846,12 +1776,12 @@ elf_link_add_object_symbols (abfd, info)
                  verlen = strlen (verstr);
                  newlen = namelen + verlen + 2;
                  if ((iver.vs_vers & VERSYM_HIDDEN) == 0
-                     && sym.st_shndx != SHN_UNDEF)
+                     && isym->st_shndx != SHN_UNDEF)
                    ++newlen;
 
                  newname = (char *) bfd_alloc (abfd, (bfd_size_type) newlen);
                  if (newname == NULL)
-                   goto error_return;
+                   goto error_free_vers;
                  memcpy (newname, name, namelen);
                  p = newname + namelen;
                  *p++ = ELF_VER_CHR;
@@ -1859,7 +1789,7 @@ elf_link_add_object_symbols (abfd, info)
                     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;
                  memcpy (p, verstr, verlen + 1);
 
@@ -1867,10 +1797,10 @@ elf_link_add_object_symbols (abfd, info)
                }
            }
 
-         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;
@@ -1898,7 +1828,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
@@ -1910,7 +1840,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)
        {
@@ -1932,16 +1862,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;
        }
 
@@ -1952,16 +1882,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
@@ -1972,37 +1902,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
@@ -2046,21 +1976,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)
@@ -2083,7 +2013,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
@@ -2094,7 +2024,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))
                {
@@ -2120,11 +2050,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
@@ -2192,24 +2132,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.
@@ -2255,7 +2182,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)
@@ -2334,13 +2261,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;
 }
 
@@ -5050,7 +4977,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);
                }
 
@@ -6072,8 +5999,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
@@ -6090,11 +6015,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;
 
@@ -6121,17 +6046,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);
@@ -6144,26 +6063,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;
 
@@ -6180,13 +6097,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;
@@ -6611,15 +6528,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;
@@ -6654,45 +6567,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)
+  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;
     }
 
-  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)
-       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))
@@ -6731,7 +6628,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)
@@ -7001,7 +6898,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;
 
@@ -7085,7 +6982,7 @@ elf_link_input_bfd (finfo, input_bfd)
                  /* This is a reloc against a local symbol.  */
 
                  *rel_hash = NULL;
-                 isym = finfo->internal_syms + r_symndx;
+                 isym = isymbuf + r_symndx;
                  sec = finfo->sections[r_symndx];
                  if (ELF_ST_TYPE (isym->st_info) == STT_SECTION)
                    {
@@ -7762,17 +7659,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);
@@ -7786,37 +7678,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
-       {
-         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)
+      isym = (Elf_Internal_Sym *) symtab_hdr->contents;
+      if (isym == NULL && 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)
        {
@@ -7830,41 +7703,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, info, rel, NULL, &s);
-             else
-               {
-                 h = sym_hashes[r_symndx - extsymoff];
-                 rsec = (*gc_mark_hook) (sec, 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, 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, info, rel, NULL, &s);
+             rsec = (*gc_mark_hook) (sec, info, rel, NULL, &isym[r_symndx]);
            }
 
          if (rsec && !rsec->gc_mark)
@@ -7880,11 +7732,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;
@@ -7941,7 +7798,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)
@@ -8439,7 +8296,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)
@@ -8447,22 +8303,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;
 
@@ -8479,17 +8321,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;
            }
@@ -8512,8 +8356,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;
@@ -8564,8 +8406,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);
@@ -8581,48 +8421,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)
            {
@@ -8634,7 +8446,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);
            }
        }
@@ -8658,7 +8470,7 @@ elf_bfd_discard_info (output_bfd, info)
                                                 elf_reloc_symbol_deleted_p,
                                                 &cookie))
            ret = true;
-         if (! info->keep_memory)
+         if (cookie.rels && elf_section_data (eh)->relocs != cookie.rels)
            free (cookie.rels);
        }
 
@@ -8668,11 +8480,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.0415 seconds and 4 git commands to generate.