* elfxx-target.h (bfd_elfNN_bfd_link_add_symbols): Define.
authorAlan Modra <amodra@gmail.com>
Fri, 26 Mar 2004 05:55:15 +0000 (05:55 +0000)
committerAlan Modra <amodra@gmail.com>
Fri, 26 Mar 2004 05:55:15 +0000 (05:55 +0000)
* elf-bfd.h (_bfd_elf_link_add_archive_symbols): Delete.
(_bfd_elf_sort_symbol, _bfd_elf_add_dt_needed_tag): Delete.
(_bfd_elf_finalize_dynstr, bfd_elf32_bfd_link_add_symbols): Delete.
(bfd_elf64_bfd_link_add_symbols): Delete.
(bfd_elf_link_add_symbols): Declare.
* elfcode.h (elf_bfd_link_add_symbols): Delete.
* elflink.c: Include safe-ctype.h.
(elf_add_dt_needed_tag): Rename from _bfd_elf_add_dt_needed_tag,
make static.
(elf_sort_symbol): Rename from _bfd_elf_sort_symbol, make static.
(elf_finalize_dynstr): Rename from _bfd_elf_finalize_dynstr, make
static.
(elf_link_add_archive_symbols): Rename from
_bfd_elf_link_add_archive_symbols, make static.
(elf_link_add_object_symbols): New function.  Corresponding
elflink.h function converted to use elf_size_info.
(bfd_elf_link_add_symbols): Likewise.
(bfd_elf_size_dynamic_sections): Adjust.
* elflink.h (elf_bfd_link_add_symbols): Delete.
(elf_link_add_object_symbols): Delete.
* elf32-gen.c (elf32_generic_link_add_symbols): Call
bfd_elf_link_add_symbols.
* elf64-gen.c (elf64_generic_link_add_symbols): Likewise.

bfd/ChangeLog
bfd/elf-bfd.h
bfd/elf32-gen.c
bfd/elf64-gen.c
bfd/elfcode.h
bfd/elflink.c
bfd/elflink.h
bfd/elfxx-target.h

index 2a19c495c7346e5f0adcb6f0606981af7fb128e0..3ccef11600961d790648b9adb8608e3bd822ce58 100644 (file)
@@ -1,3 +1,30 @@
+2004-03-26  Alan Modra  <amodra@bigpond.net.au>
+
+       * elfxx-target.h (bfd_elfNN_bfd_link_add_symbols): Define.
+       * elf-bfd.h (_bfd_elf_link_add_archive_symbols): Delete.
+       (_bfd_elf_sort_symbol, _bfd_elf_add_dt_needed_tag): Delete.
+       (_bfd_elf_finalize_dynstr, bfd_elf32_bfd_link_add_symbols): Delete.
+       (bfd_elf64_bfd_link_add_symbols): Delete.
+       (bfd_elf_link_add_symbols): Declare.
+       * elfcode.h (elf_bfd_link_add_symbols): Delete.
+       * elflink.c: Include safe-ctype.h.
+       (elf_add_dt_needed_tag): Rename from _bfd_elf_add_dt_needed_tag,
+       make static.
+       (elf_sort_symbol): Rename from _bfd_elf_sort_symbol, make static.
+       (elf_finalize_dynstr): Rename from _bfd_elf_finalize_dynstr, make
+       static.
+       (elf_link_add_archive_symbols): Rename from
+       _bfd_elf_link_add_archive_symbols, make static.
+       (elf_link_add_object_symbols): New function.  Corresponding
+       elflink.h function converted to use elf_size_info.
+       (bfd_elf_link_add_symbols): Likewise.
+       (bfd_elf_size_dynamic_sections): Adjust.
+       * elflink.h (elf_bfd_link_add_symbols): Delete.
+       (elf_link_add_object_symbols): Delete.
+       * elf32-gen.c (elf32_generic_link_add_symbols): Call
+       bfd_elf_link_add_symbols.
+       * elf64-gen.c (elf64_generic_link_add_symbols): Likewise.
+
 2004-03-25  Alan Modra  <amodra@bigpond.net.au>
 
        * elflink.h (elf_link_add_object_symbols): Add DT_NEEDED for as-needed
index c2cd5374d77c4df1a773395cf0cca70279a13f0b..6b7730ae4a6531059bb873718513446e0428aafb 100644 (file)
@@ -1544,9 +1544,6 @@ extern bfd_boolean _bfd_elf_dynamic_symbol_p
 extern bfd_boolean _bfd_elf_symbol_refs_local_p
   (struct elf_link_hash_entry *, struct bfd_link_info *, bfd_boolean);
 
-extern bfd_boolean _bfd_elf_link_add_archive_symbols
-  (bfd *, struct bfd_link_info *);
-
 extern const bfd_target *bfd_elf32_object_p
   (bfd *);
 extern const bfd_target *bfd_elf32_core_file_p
@@ -1558,8 +1555,6 @@ extern int bfd_elf32_core_file_failing_signal
 extern bfd_boolean bfd_elf32_core_file_matches_executable_p
   (bfd *, bfd *);
 
-extern bfd_boolean bfd_elf32_bfd_link_add_symbols
-  (bfd *, struct bfd_link_info *);
 extern bfd_boolean bfd_elf32_bfd_final_link
   (bfd *, struct bfd_link_info *);
 
@@ -1604,8 +1599,6 @@ extern int bfd_elf64_core_file_failing_signal
   (bfd *);
 extern bfd_boolean bfd_elf64_core_file_matches_executable_p
   (bfd *, bfd *);
-extern bfd_boolean bfd_elf64_bfd_link_add_symbols
-  (bfd *, struct bfd_link_info *);
 extern bfd_boolean bfd_elf64_bfd_final_link
   (bfd *, struct bfd_link_info *);
 
@@ -1640,14 +1633,10 @@ extern void bfd_elf64_write_relocs
 extern bfd_boolean bfd_elf64_slurp_reloc_table
   (bfd *, asection *, asymbol **, bfd_boolean);
 
+extern bfd_boolean bfd_elf_link_add_symbols
+  (bfd *, struct bfd_link_info *);
 extern bfd_boolean _bfd_elf_add_dynamic_entry
   (struct bfd_link_info *, bfd_vma, bfd_vma);
-extern int _bfd_elf_add_dt_needed_tag
-  (struct bfd_link_info *, const char *, bfd_boolean);
-extern int _bfd_elf_sort_symbol
-  (const void *, const void *);
-extern bfd_boolean _bfd_elf_finalize_dynstr
-  (bfd *, struct bfd_link_info *);
 
 #define bfd_elf32_link_record_dynamic_symbol \
   _bfd_elf_link_record_dynamic_symbol
index b1ad74486f43524ad92c7aeb229a17c3707d0dee..f2edf69da6b88f14279bc722429a8aaf8ff5ef12 100644 (file)
@@ -1,5 +1,5 @@
 /* Generic support for 32-bit ELF
-   Copyright 1993, 1995, 1998, 1999, 2001, 2002
+   Copyright 1993, 1995, 1998, 1999, 2001, 2002, 2004
    Free Software Foundation, Inc.
 
 This file is part of BFD, the Binary File Descriptor library.
@@ -88,7 +88,7 @@ elf32_generic_link_add_symbols (abfd, info)
        return FALSE;
       }
 
-  return bfd_elf32_bfd_link_add_symbols (abfd, info);
+  return bfd_elf_link_add_symbols (abfd, info);
 }
 
 #define TARGET_LITTLE_SYM              bfd_elf32_little_generic_vec
index 590456ccbf65f3ebbf9f85f45cdd062710f5b2bd..be1dc3e00ed68a785e5fa830d7e4041caacdffe6 100644 (file)
@@ -1,5 +1,6 @@
 /* Generic support for 64-bit ELF
-   Copyright 1993, 1995, 1998, 1999, 2001, 2002 Free Software Foundation, Inc.
+   Copyright 1993, 1995, 1998, 1999, 2001, 2002, 2004
+   Free Software Foundation, Inc.
 
 This file is part of BFD, the Binary File Descriptor library.
 
@@ -87,7 +88,7 @@ elf64_generic_link_add_symbols (abfd, info)
        return FALSE;
       }
 
-  return bfd_elf64_bfd_link_add_symbols (abfd, info);
+  return bfd_elf_link_add_symbols (abfd, info);
 }
 
 #define TARGET_LITTLE_SYM              bfd_elf64_little_generic_vec
index 6f8ddc6f79ba8598348bea85dd8a070aa465b687..d0dd9eddfbda22b596d01c7036b215652fe78a49 100644 (file)
@@ -115,7 +115,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
 #define elf_no_info_to_howto           NAME(bfd_elf,no_info_to_howto)
 #define elf_no_info_to_howto_rel       NAME(bfd_elf,no_info_to_howto_rel)
 #define elf_find_section               NAME(bfd_elf,find_section)
-#define elf_bfd_link_add_symbols       NAME(bfd_elf,bfd_link_add_symbols)
 #define elf_write_shdrs_and_ehdr       NAME(bfd_elf,write_shdrs_and_ehdr)
 #define elf_write_out_phdrs            NAME(bfd_elf,write_out_phdrs)
 #define elf_write_relocs               NAME(bfd_elf,write_relocs)
index fce550d2aa79b8efcfd90af60bdb7ae0eed77878..61495fcc6da957e9934ce75ec243005b89c09256 100644 (file)
@@ -24,6 +24,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
 #include "libbfd.h"
 #define ARCH_SIZE 0
 #include "elf-bfd.h"
+#include "safe-ctype.h"
 
 bfd_boolean
 _bfd_elf_create_got_section (bfd *abfd, struct bfd_link_info *info)
@@ -2626,10 +2627,10 @@ _bfd_elf_add_dynamic_entry (struct bfd_link_info *info,
    otherwise just check whether one already exists.  Returns -1 on error,
    1 if a DT_NEEDED tag already exists, and 0 on success.  */
 
-int
-_bfd_elf_add_dt_needed_tag (struct bfd_link_info *info,
-                           const char *soname,
-                           bfd_boolean do_it)
+static int
+elf_add_dt_needed_tag (struct bfd_link_info *info,
+                      const char *soname,
+                      bfd_boolean do_it)
 {
   struct elf_link_hash_table *hash_table;
   bfd_size_type oldsize;
@@ -2680,8 +2681,8 @@ _bfd_elf_add_dt_needed_tag (struct bfd_link_info *info,
 }
 
 /* Sort symbol by value and section.  */
-int
-_bfd_elf_sort_symbol (const void *arg1, const void *arg2)
+static int
+elf_sort_symbol (const void *arg1, const void *arg2)
 {
   const struct elf_link_hash_entry *h1;
   const struct elf_link_hash_entry *h2;
@@ -2700,7 +2701,7 @@ _bfd_elf_sort_symbol (const void *arg1, const void *arg2)
     }
   return 0;
 }
-\f
+
 /* This function is used to adjust offsets into .dynstr for
    dynamic symbols.  This is called via elf_link_hash_traverse.  */
 
@@ -2720,8 +2721,8 @@ elf_adjust_dynstr_offsets (struct elf_link_hash_entry *h, void *data)
 /* Assign string offsets in .dynstr, update all structures referencing
    them.  */
 
-bfd_boolean
-_bfd_elf_finalize_dynstr (bfd *output_bfd, struct bfd_link_info *info)
+static bfd_boolean
+elf_finalize_dynstr (bfd *output_bfd, struct bfd_link_info *info)
 {
   struct elf_link_hash_table *hash_table = elf_hash_table (info);
   struct elf_link_local_dynamic_entry *entry;
@@ -2841,6 +2842,1309 @@ _bfd_elf_finalize_dynstr (bfd *output_bfd, struct bfd_link_info *info)
   return TRUE;
 }
 \f
+/* Add symbols from an ELF object file to the linker hash table.  */
+
+static bfd_boolean
+elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info)
+{
+  bfd_boolean (*add_symbol_hook)
+    (bfd *, struct bfd_link_info *, const Elf_Internal_Sym *,
+     const char **, flagword *, asection **, bfd_vma *);
+  bfd_boolean (*check_relocs)
+    (bfd *, struct bfd_link_info *, asection *, const Elf_Internal_Rela *);
+  bfd_boolean collect;
+  Elf_Internal_Shdr *hdr;
+  bfd_size_type symcount;
+  bfd_size_type extsymcount;
+  bfd_size_type extsymoff;
+  struct elf_link_hash_entry **sym_hash;
+  bfd_boolean dynamic;
+  Elf_External_Versym *extversym = NULL;
+  Elf_External_Versym *ever;
+  struct elf_link_hash_entry *weaks;
+  struct elf_link_hash_entry **nondeflt_vers = NULL;
+  bfd_size_type nondeflt_vers_cnt = 0;
+  Elf_Internal_Sym *isymbuf = NULL;
+  Elf_Internal_Sym *isym;
+  Elf_Internal_Sym *isymend;
+  const struct elf_backend_data *bed;
+  bfd_boolean add_needed;
+  struct elf_link_hash_table * hash_table;
+  bfd_size_type amt;
+
+  hash_table = elf_hash_table (info);
+
+  bed = get_elf_backend_data (abfd);
+  add_symbol_hook = bed->elf_add_symbol_hook;
+  collect = bed->collect;
+
+  if ((abfd->flags & DYNAMIC) == 0)
+    dynamic = FALSE;
+  else
+    {
+      dynamic = TRUE;
+
+      /* You can't use -r against a dynamic object.  Also, there's no
+        hope of using a dynamic object which does not exactly match
+        the format of the output file.  */
+      if (info->relocatable
+         || !is_elf_hash_table (hash_table)
+         || hash_table->root.creator != abfd->xvec)
+       {
+         bfd_set_error (bfd_error_invalid_operation);
+         goto error_return;
+       }
+    }
+
+  /* As a GNU extension, any input sections which are named
+     .gnu.warning.SYMBOL are treated as warning symbols for the given
+     symbol.  This differs from .gnu.warning sections, which generate
+     warnings when they are included in an output file.  */
+  if (info->executable)
+    {
+      asection *s;
+
+      for (s = abfd->sections; s != NULL; s = s->next)
+       {
+         const char *name;
+
+         name = bfd_get_section_name (abfd, s);
+         if (strncmp (name, ".gnu.warning.", sizeof ".gnu.warning." - 1) == 0)
+           {
+             char *msg;
+             bfd_size_type sz;
+             bfd_size_type prefix_len;
+             const char * gnu_warning_prefix = _("warning: ");
+
+             name += sizeof ".gnu.warning." - 1;
+
+             /* If this is a shared object, then look up the symbol
+                in the hash table.  If it is there, and it is already
+                been defined, then we will not be using the entry
+                from this shared object, so we don't need to warn.
+                FIXME: If we see the definition in a regular object
+                later on, we will warn, but we shouldn't.  The only
+                fix is to keep track of what warnings we are supposed
+                to emit, and then handle them all at the end of the
+                link.  */
+             if (dynamic)
+               {
+                 struct elf_link_hash_entry *h;
+
+                 h = elf_link_hash_lookup (hash_table, name,
+                                           FALSE, FALSE, TRUE);
+
+                 /* FIXME: What about bfd_link_hash_common?  */
+                 if (h != NULL
+                     && (h->root.type == bfd_link_hash_defined
+                         || h->root.type == bfd_link_hash_defweak))
+                   {
+                     /* We don't want to issue this warning.  Clobber
+                        the section size so that the warning does not
+                        get copied into the output file.  */
+                     s->_raw_size = 0;
+                     continue;
+                   }
+               }
+
+             sz = bfd_section_size (abfd, s);
+             prefix_len = strlen (gnu_warning_prefix);
+             msg = bfd_alloc (abfd, prefix_len + sz + 1);
+             if (msg == NULL)
+               goto error_return;
+
+             strcpy (msg, gnu_warning_prefix);
+             if (! bfd_get_section_contents (abfd, s, msg + prefix_len, 0, sz))
+               goto error_return;
+
+             msg[prefix_len + sz] = '\0';
+
+             if (! (_bfd_generic_link_add_one_symbol
+                    (info, abfd, name, BSF_WARNING, s, 0, msg,
+                     FALSE, collect, NULL)))
+               goto error_return;
+
+             if (! info->relocatable)
+               {
+                 /* Clobber the section size so that the warning does
+                    not get copied into the output file.  */
+                 s->_raw_size = 0;
+               }
+           }
+       }
+    }
+
+  add_needed = TRUE;
+  if (! dynamic)
+    {
+      /* If we are creating a shared library, create all the dynamic
+        sections immediately.  We need to attach them to something,
+        so we attach them to this BFD, provided it is the right
+        format.  FIXME: If there are no input BFD's of the same
+        format as the output, we can't make a shared library.  */
+      if (info->shared
+         && is_elf_hash_table (hash_table)
+         && hash_table->root.creator == abfd->xvec
+         && ! hash_table->dynamic_sections_created)
+       {
+         if (! _bfd_elf_link_create_dynamic_sections (abfd, info))
+           goto error_return;
+       }
+    }
+  else if (!is_elf_hash_table (hash_table))
+    goto error_return;
+  else
+    {
+      asection *s;
+      const char *soname = NULL;
+      struct bfd_link_needed_list *rpath = NULL, *runpath = NULL;
+      int ret;
+
+      /* 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
+         && s->sec_info_type == ELF_INFO_TYPE_JUST_SYMS)
+       goto error_return;
+
+      /* If this dynamic lib was specified on the command line with
+        --as-needed in effect, then we don't want to add a DT_NEEDED
+        tag unless the lib is actually used.  Similary for libs brought
+        in by another lib's DT_NEEDED.  */
+      add_needed = elf_dyn_lib_class (abfd) == DYN_NORMAL;
+
+      s = bfd_get_section_by_name (abfd, ".dynamic");
+      if (s != NULL)
+       {
+         bfd_byte *dynbuf;
+         bfd_byte *extdyn;
+         int elfsec;
+         unsigned long shlink;
+
+         dynbuf = bfd_malloc (s->_raw_size);
+         if (dynbuf == NULL)
+           goto error_return;
+
+         if (! bfd_get_section_contents (abfd, s, dynbuf, 0, s->_raw_size))
+           goto error_free_dyn;
+
+         elfsec = _bfd_elf_section_from_bfd_section (abfd, s);
+         if (elfsec == -1)
+           goto error_free_dyn;
+         shlink = elf_elfsections (abfd)[elfsec]->sh_link;
+
+         for (extdyn = dynbuf;
+              extdyn < dynbuf + s->_raw_size;
+              extdyn += bed->s->sizeof_dyn)
+           {
+             Elf_Internal_Dyn dyn;
+
+             bed->s->swap_dyn_in (abfd, extdyn, &dyn);
+             if (dyn.d_tag == DT_SONAME)
+               {
+                 unsigned int tagv = dyn.d_un.d_val;
+                 soname = bfd_elf_string_from_elf_section (abfd, shlink, tagv);
+                 if (soname == NULL)
+                   goto error_free_dyn;
+               }
+             if (dyn.d_tag == DT_NEEDED)
+               {
+                 struct bfd_link_needed_list *n, **pn;
+                 char *fnm, *anm;
+                 unsigned int tagv = dyn.d_un.d_val;
+
+                 amt = sizeof (struct bfd_link_needed_list);
+                 n = bfd_alloc (abfd, amt);
+                 fnm = bfd_elf_string_from_elf_section (abfd, shlink, tagv);
+                 if (n == NULL || fnm == NULL)
+                   goto error_free_dyn;
+                 amt = strlen (fnm) + 1;
+                 anm = bfd_alloc (abfd, amt);
+                 if (anm == NULL)
+                   goto error_free_dyn;
+                 memcpy (anm, fnm, amt);
+                 n->name = anm;
+                 n->by = abfd;
+                 n->next = NULL;
+                 for (pn = & hash_table->needed;
+                      *pn != NULL;
+                      pn = &(*pn)->next)
+                   ;
+                 *pn = n;
+               }
+             if (dyn.d_tag == DT_RUNPATH)
+               {
+                 struct bfd_link_needed_list *n, **pn;
+                 char *fnm, *anm;
+                 unsigned int tagv = dyn.d_un.d_val;
+
+                 amt = sizeof (struct bfd_link_needed_list);
+                 n = bfd_alloc (abfd, amt);
+                 fnm = bfd_elf_string_from_elf_section (abfd, shlink, tagv);
+                 if (n == NULL || fnm == NULL)
+                   goto error_free_dyn;
+                 amt = strlen (fnm) + 1;
+                 anm = bfd_alloc (abfd, amt);
+                 if (anm == NULL)
+                   goto error_free_dyn;
+                 memcpy (anm, fnm, amt);
+                 n->name = anm;
+                 n->by = abfd;
+                 n->next = NULL;
+                 for (pn = & runpath;
+                      *pn != NULL;
+                      pn = &(*pn)->next)
+                   ;
+                 *pn = n;
+               }
+             /* Ignore DT_RPATH if we have seen DT_RUNPATH.  */
+             if (!runpath && dyn.d_tag == DT_RPATH)
+               {
+                 struct bfd_link_needed_list *n, **pn;
+                 char *fnm, *anm;
+                 unsigned int tagv = dyn.d_un.d_val;
+
+                 amt = sizeof (struct bfd_link_needed_list);
+                 n = bfd_alloc (abfd, amt);
+                 fnm = bfd_elf_string_from_elf_section (abfd, shlink, tagv);
+                 if (n == NULL || fnm == NULL)
+                   goto error_free_dyn;
+                 amt = strlen (fnm) + 1;
+                 anm = bfd_alloc (abfd, amt);
+                 if (anm == NULL)
+                   {
+                   error_free_dyn:
+                     free (dynbuf);
+                     goto error_return;
+                   }
+                 memcpy (anm, fnm, amt);
+                 n->name = anm;
+                 n->by = abfd;
+                 n->next = NULL;
+                 for (pn = & rpath;
+                      *pn != NULL;
+                      pn = &(*pn)->next)
+                   ;
+                 *pn = n;
+               }
+           }
+
+         free (dynbuf);
+       }
+
+      /* 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
+        object in the output file.  We hack by simply clobbering the
+        list of sections in the BFD.  This could be handled more
+        cleanly by, say, a new section flag; the existing
+        SEC_NEVER_LOAD flag is not the one we want, because that one
+        still implies that the section takes up space in the output
+        file.  */
+      bfd_section_list_clear (abfd);
+
+      /* If this is the first dynamic object found in the link, create
+        the special sections required for dynamic linking.  */
+      if (! _bfd_elf_link_create_dynamic_sections (abfd, info))
+       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.
+        Otherwise, if the generic linker stuck something in
+        elf_dt_name, we use that.  Otherwise, we just use the file
+        name.  */
+      if (soname == NULL || *soname == '\0')
+       {
+         soname = elf_dt_name (abfd);
+         if (soname == NULL || *soname == '\0')
+           soname = bfd_get_filename (abfd);
+       }
+
+      /* Save the SONAME because sometimes the linker emulation code
+        will need to know it.  */
+      elf_dt_name (abfd) = soname;
+
+      ret = elf_add_dt_needed_tag (info, soname, add_needed);
+      if (ret < 0)
+       goto error_return;
+
+      /* If we have already included this dynamic object in the
+        link, just ignore it.  There is no reason to include a
+        particular dynamic object more than once.  */
+      if (ret > 0)
+       return TRUE;
+    }
+
+  /* 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 / bed->s->sizeof_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;
+    }
+
+  sym_hash = NULL;
+  if (extsymcount != 0)
+    {
+      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 = 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 = 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 (extversym, amt, abfd) != amt)
+           goto error_free_vers;
+       }
+    }
+
+  weaks = NULL;
+
+  ever = extversym != NULL ? extversym + extsymoff : NULL;
+  for (isym = isymbuf, isymend = isymbuf + extsymcount;
+       isym < isymend;
+       isym++, sym_hash++, ever = (ever != NULL ? ever + 1 : NULL))
+    {
+      int bind;
+      bfd_vma value;
+      asection *sec;
+      flagword flags;
+      const char *name;
+      struct elf_link_hash_entry *h;
+      bfd_boolean definition;
+      bfd_boolean size_change_ok;
+      bfd_boolean type_change_ok;
+      bfd_boolean new_weakdef;
+      bfd_boolean override;
+      unsigned int old_alignment;
+      bfd *old_bfd;
+
+      override = FALSE;
+
+      flags = BSF_NO_FLAGS;
+      sec = NULL;
+      value = isym->st_value;
+      *sym_hash = NULL;
+
+      bind = ELF_ST_BIND (isym->st_info);
+      if (bind == STB_LOCAL)
+       {
+         /* This should be impossible, since ELF requires that all
+            global symbols follow all local symbols, and that sh_info
+            point to the first global symbol.  Unfortunately, Irix 5
+            screws this up.  */
+         continue;
+       }
+      else if (bind == STB_GLOBAL)
+       {
+         if (isym->st_shndx != SHN_UNDEF
+             && isym->st_shndx != SHN_COMMON)
+           flags = BSF_GLOBAL;
+       }
+      else if (bind == STB_WEAK)
+       flags = BSF_WEAK;
+      else
+       {
+         /* Leave it up to the processor backend.  */
+       }
+
+      if (isym->st_shndx == SHN_UNDEF)
+       sec = bfd_und_section_ptr;
+      else if (isym->st_shndx < SHN_LORESERVE || isym->st_shndx > SHN_HIRESERVE)
+       {
+         sec = bfd_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 (isym->st_shndx == SHN_ABS)
+       sec = bfd_abs_section_ptr;
+      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 = isym->st_size;
+       }
+      else
+       {
+         /* Leave it up to the processor backend.  */
+       }
+
+      name = bfd_elf_string_from_elf_section (abfd, hdr->sh_link,
+                                             isym->st_name);
+      if (name == NULL)
+       goto error_free_vers;
+
+      if (isym->st_shndx == SHN_COMMON
+         && ELF_ST_TYPE (isym->st_info) == STT_TLS)
+       {
+         asection *tcomm = bfd_get_section_by_name (abfd, ".tcommon");
+
+         if (tcomm == NULL)
+           {
+             tcomm = bfd_make_section (abfd, ".tcommon");
+             if (tcomm == NULL
+                 || !bfd_set_section_flags (abfd, tcomm, (SEC_ALLOC
+                                                          | SEC_IS_COMMON
+                                                          | SEC_LINKER_CREATED
+                                                          | SEC_THREAD_LOCAL)))
+               goto error_free_vers;
+           }
+         sec = tcomm;
+       }
+      else if (add_symbol_hook)
+       {
+         if (! (*add_symbol_hook) (abfd, info, isym, &name, &flags, &sec,
+                                   &value))
+           goto error_free_vers;
+
+         /* The hook function sets the name to NULL if this symbol
+            should be skipped for some reason.  */
+         if (name == NULL)
+           continue;
+       }
+
+      /* Sanity check that all possibilities were handled.  */
+      if (sec == NULL)
+       {
+         bfd_set_error (bfd_error_bad_value);
+         goto error_free_vers;
+       }
+
+      if (bfd_is_und_section (sec)
+         || bfd_is_com_section (sec))
+       definition = FALSE;
+      else
+       definition = TRUE;
+
+      size_change_ok = FALSE;
+      type_change_ok = get_elf_backend_data (abfd)->type_change_ok;
+      old_alignment = 0;
+      old_bfd = NULL;
+
+      if (is_elf_hash_table (hash_table))
+       {
+         Elf_Internal_Versym iver;
+         unsigned int vernum = 0;
+         bfd_boolean skip;
+
+         if (ever != NULL)
+           {
+             _bfd_elf_swap_versym_in (abfd, ever, &iver);
+             vernum = iver.vs_vers & VERSYM_VERSION;
+
+             /* If this is a hidden symbol, or if it is not version
+                1, we append the version name to the symbol name.
+                However, we do not modify a non-hidden absolute
+                symbol, because it might be the version symbol
+                itself.  FIXME: What if it isn't?  */
+             if ((iver.vs_vers & VERSYM_HIDDEN) != 0
+                 || (vernum > 1 && ! bfd_is_abs_section (sec)))
+               {
+                 const char *verstr;
+                 size_t namelen, verlen, newlen;
+                 char *newname, *p;
+
+                 if (isym->st_shndx != SHN_UNDEF)
+                   {
+                     if (vernum > elf_tdata (abfd)->dynverdef_hdr.sh_info)
+                       {
+                         (*_bfd_error_handler)
+                           (_("%s: %s: invalid version %u (max %d)"),
+                            bfd_archive_filename (abfd), name, vernum,
+                            elf_tdata (abfd)->dynverdef_hdr.sh_info);
+                         bfd_set_error (bfd_error_bad_value);
+                         goto error_free_vers;
+                       }
+                     else if (vernum > 1)
+                       verstr =
+                         elf_tdata (abfd)->verdef[vernum - 1].vd_nodename;
+                     else
+                       verstr = "";
+                   }
+                 else
+                   {
+                     /* We cannot simply test for the number of
+                        entries in the VERNEED section since the
+                        numbers for the needed versions do not start
+                        at 0.  */
+                     Elf_Internal_Verneed *t;
+
+                     verstr = NULL;
+                     for (t = elf_tdata (abfd)->verref;
+                          t != NULL;
+                          t = t->vn_nextref)
+                       {
+                         Elf_Internal_Vernaux *a;
+
+                         for (a = t->vn_auxptr; a != NULL; a = a->vna_nextptr)
+                           {
+                             if (a->vna_other == vernum)
+                               {
+                                 verstr = a->vna_nodename;
+                                 break;
+                               }
+                           }
+                         if (a != NULL)
+                           break;
+                       }
+                     if (verstr == NULL)
+                       {
+                         (*_bfd_error_handler)
+                           (_("%s: %s: invalid needed version %d"),
+                            bfd_archive_filename (abfd), name, vernum);
+                         bfd_set_error (bfd_error_bad_value);
+                         goto error_free_vers;
+                       }
+                   }
+
+                 namelen = strlen (name);
+                 verlen = strlen (verstr);
+                 newlen = namelen + verlen + 2;
+                 if ((iver.vs_vers & VERSYM_HIDDEN) == 0
+                     && isym->st_shndx != SHN_UNDEF)
+                   ++newlen;
+
+                 newname = bfd_alloc (abfd, newlen);
+                 if (newname == NULL)
+                   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
+                     && isym->st_shndx != SHN_UNDEF)
+                   *p++ = ELF_VER_CHR;
+                 memcpy (p, verstr, verlen + 1);
+
+                 name = newname;
+               }
+           }
+
+         if (!_bfd_elf_merge_symbol (abfd, info, name, isym, &sec, &value,
+                                     sym_hash, &skip, &override,
+                                     &type_change_ok, &size_change_ok))
+           goto error_free_vers;
+
+         if (skip)
+           continue;
+
+         if (override)
+           definition = FALSE;
+
+         h = *sym_hash;
+         while (h->root.type == bfd_link_hash_indirect
+                || h->root.type == bfd_link_hash_warning)
+           h = (struct elf_link_hash_entry *) h->root.u.i.link;
+
+         /* Remember the old alignment if this is a common symbol, so
+            that we don't reduce the alignment later on.  We can't
+            check later, because _bfd_generic_link_add_one_symbol
+            will set a default for the alignment which we want to
+            override. We also remember the old bfd where the existing
+            definition comes from.  */
+         switch (h->root.type)
+           {
+           default:
+             break;
+
+           case bfd_link_hash_defined:
+           case bfd_link_hash_defweak:
+             old_bfd = h->root.u.def.section->owner;
+             break;
+
+           case bfd_link_hash_common:
+             old_bfd = h->root.u.c.p->section->owner;
+             old_alignment = h->root.u.c.p->alignment_power;
+             break;
+           }
+
+         if (elf_tdata (abfd)->verdef != NULL
+             && ! override
+             && vernum > 1
+             && definition)
+           h->verinfo.verdef = &elf_tdata (abfd)->verdef[vernum - 1];
+       }
+
+      if (! (_bfd_generic_link_add_one_symbol
+            (info, abfd, name, flags, sec, value, NULL, FALSE, collect,
+             (struct bfd_link_hash_entry **) sym_hash)))
+       goto error_free_vers;
+
+      h = *sym_hash;
+      while (h->root.type == bfd_link_hash_indirect
+            || h->root.type == bfd_link_hash_warning)
+       h = (struct elf_link_hash_entry *) h->root.u.i.link;
+      *sym_hash = h;
+
+      new_weakdef = FALSE;
+      if (dynamic
+         && definition
+         && (flags & BSF_WEAK) != 0
+         && ELF_ST_TYPE (isym->st_info) != STT_FUNC
+         && is_elf_hash_table (hash_table)
+         && h->weakdef == NULL)
+       {
+         /* Keep a list of all weak defined non function symbols from
+            a dynamic object, using the weakdef field.  Later in this
+            function we will set the weakdef field to the correct
+            value.  We only put non-function symbols from dynamic
+            objects on this list, because that happens to be the only
+            time we need to know the normal symbol corresponding to a
+            weak symbol, and the information is time consuming to
+            figure out.  If the weakdef field is not already NULL,
+            then this symbol was already defined by some previous
+            dynamic object, and we will be using that previous
+            definition anyhow.  */
+
+         h->weakdef = weaks;
+         weaks = h;
+         new_weakdef = TRUE;
+       }
+
+      /* Set the alignment of a common symbol.  */
+      if (isym->st_shndx == SHN_COMMON
+         && h->root.type == bfd_link_hash_common)
+       {
+         unsigned int align;
+
+         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.  */
+             || (isym->st_value == 1 && old_alignment == 0))
+           h->root.u.c.p->alignment_power = align;
+         else
+           h->root.u.c.p->alignment_power = old_alignment;
+       }
+
+      if (is_elf_hash_table (hash_table))
+       {
+         int old_flags;
+         bfd_boolean dynsym;
+         int new_flag;
+
+         /* Check the alignment when a common symbol is involved. This
+            can change when a common symbol is overridden by a normal
+            definition or a common symbol is ignored due to the old
+            normal definition. We need to make sure the maximum
+            alignment is maintained.  */
+         if ((old_alignment || isym->st_shndx == SHN_COMMON)
+             && h->root.type != bfd_link_hash_common)
+           {
+             unsigned int common_align;
+             unsigned int normal_align;
+             unsigned int symbol_align;
+             bfd *normal_bfd;
+             bfd *common_bfd;
+
+             symbol_align = ffs (h->root.u.def.value) - 1;
+             if (h->root.u.def.section->owner != NULL
+                 && (h->root.u.def.section->owner->flags & DYNAMIC) == 0)
+               {
+                 normal_align = h->root.u.def.section->alignment_power;
+                 if (normal_align > symbol_align)
+                   normal_align = symbol_align;
+               }
+             else
+               normal_align = symbol_align;
+
+             if (old_alignment)
+               {
+                 common_align = old_alignment;
+                 common_bfd = old_bfd;
+                 normal_bfd = abfd;
+               }
+             else
+               {
+                 common_align = bfd_log2 (isym->st_value);
+                 common_bfd = abfd;
+                 normal_bfd = old_bfd;
+               }
+
+             if (normal_align < common_align)
+               (*_bfd_error_handler)
+                 (_("Warning: alignment %u of symbol `%s' in %s is smaller than %u in %s"),
+                  1 << normal_align,
+                  name,
+                  bfd_archive_filename (normal_bfd),
+                  1 << common_align,
+                  bfd_archive_filename (common_bfd));
+           }
+
+         /* Remember the symbol size and type.  */
+         if (isym->st_size != 0
+             && (definition || h->size == 0))
+           {
+             if (h->size != 0 && h->size != isym->st_size && ! size_change_ok)
+               (*_bfd_error_handler)
+                 (_("Warning: size of symbol `%s' changed from %lu in %s to %lu in %s"),
+                  name, (unsigned long) h->size,
+                  bfd_archive_filename (old_bfd),
+                  (unsigned long) isym->st_size,
+                  bfd_archive_filename (abfd));
+
+             h->size = isym->st_size;
+           }
+
+         /* If this is a common symbol, then we always want H->SIZE
+            to be the size of the common symbol.  The code just above
+            won't fix the size if a common symbol becomes larger.  We
+            don't warn about a size change here, because that is
+            covered by --warn-common.  */
+         if (h->root.type == bfd_link_hash_common)
+           h->size = h->root.u.c.size;
+
+         if (ELF_ST_TYPE (isym->st_info) != STT_NOTYPE
+             && (definition || h->type == STT_NOTYPE))
+           {
+             if (h->type != STT_NOTYPE
+                 && 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 (isym->st_info),
+                  bfd_archive_filename (abfd));
+
+             h->type = ELF_ST_TYPE (isym->st_info);
+           }
+
+         /* If st_other has a processor-specific meaning, specific
+            code might be needed here. We never merge the visibility
+            attribute with the one from a dynamic object.  */
+         if (bed->elf_backend_merge_symbol_attribute)
+           (*bed->elf_backend_merge_symbol_attribute) (h, isym, definition,
+                                                       dynamic);
+
+         if (isym->st_other != 0 && !dynamic)
+           {
+             unsigned char hvis, symvis, other, nvis;
+
+             /* Take the balance of OTHER from the definition.  */
+             other = (definition ? isym->st_other : h->other);
+             other &= ~ ELF_ST_VISIBILITY (-1);
+
+             /* Combine visibilities, using the most constraining one.  */
+             hvis   = ELF_ST_VISIBILITY (h->other);
+             symvis = ELF_ST_VISIBILITY (isym->st_other);
+             if (! hvis)
+               nvis = symvis;
+             else if (! symvis)
+               nvis = hvis;
+             else
+               nvis = hvis < symvis ? hvis : symvis;
+
+             h->other = other | nvis;
+           }
+
+         /* Set a flag in the hash table entry indicating the type of
+            reference or definition we just found.  Keep a count of
+            the number of dynamic symbols we find.  A dynamic symbol
+            is one which is referenced or defined by both a regular
+            object and a shared object.  */
+         old_flags = h->elf_link_hash_flags;
+         dynsym = FALSE;
+         if (! dynamic)
+           {
+             if (! definition)
+               {
+                 new_flag = ELF_LINK_HASH_REF_REGULAR;
+                 if (bind != STB_WEAK)
+                   new_flag |= ELF_LINK_HASH_REF_REGULAR_NONWEAK;
+               }
+             else
+               new_flag = ELF_LINK_HASH_DEF_REGULAR;
+             if (! info->executable
+                 || (old_flags & (ELF_LINK_HASH_DEF_DYNAMIC
+                                  | ELF_LINK_HASH_REF_DYNAMIC)) != 0)
+               dynsym = TRUE;
+           }
+         else
+           {
+             if (! definition)
+               new_flag = ELF_LINK_HASH_REF_DYNAMIC;
+             else
+               new_flag = ELF_LINK_HASH_DEF_DYNAMIC;
+             if ((old_flags & (ELF_LINK_HASH_DEF_REGULAR
+                               | ELF_LINK_HASH_REF_REGULAR)) != 0
+                 || (h->weakdef != NULL
+                     && ! new_weakdef
+                     && h->weakdef->dynindx != -1))
+               dynsym = TRUE;
+           }
+
+         h->elf_link_hash_flags |= new_flag;
+
+         /* 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 (!_bfd_elf_add_default_symbol (abfd, info, h, name, isym,
+                                             &sec, &value, &dynsym,
+                                             override))
+             goto error_free_vers;
+
+         if (definition && !dynamic)
+           {
+             char *p = strchr (name, ELF_VER_CHR);
+             if (p != NULL && p[1] != ELF_VER_CHR)
+               {
+                 /* Queue non-default versions so that .symver x, x@FOO
+                    aliases can be checked.  */
+                 if (! nondeflt_vers)
+                   {
+                     amt = (isymend - isym + 1)
+                           * sizeof (struct elf_link_hash_entry *);
+                     nondeflt_vers = bfd_malloc (amt);
+                   }
+                 nondeflt_vers [nondeflt_vers_cnt++] = h;
+               }
+           }
+
+         if (dynsym && h->dynindx == -1)
+           {
+             if (! _bfd_elf_link_record_dynamic_symbol (info, h))
+               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_free_vers;
+               }
+           }
+         else if (dynsym && h->dynindx != -1)
+           /* If the symbol already has a dynamic index, but
+              visibility says it should not be visible, turn it into
+              a local symbol.  */
+           switch (ELF_ST_VISIBILITY (h->other))
+             {
+             case STV_INTERNAL:
+             case STV_HIDDEN:
+               (*bed->elf_backend_hide_symbol) (info, h, TRUE);
+               dynsym = FALSE;
+               break;
+             }
+
+         if (!add_needed
+             && definition
+             && dynsym
+             && (h->elf_link_hash_flags
+                 & ELF_LINK_HASH_REF_REGULAR) != 0)
+           {
+             int ret;
+             const char *soname = elf_dt_name (abfd);
+
+             /* A symbol from a library loaded via DT_NEEDED of some
+                other library is referenced by a regular object.
+                Add a DT_NEEDED entry for it.  */
+             add_needed = TRUE;
+             ret = elf_add_dt_needed_tag (info, soname, add_needed);
+             if (ret < 0)
+               goto error_free_vers;
+
+             BFD_ASSERT (ret == 0);
+           }
+       }
+    }
+
+  /* Now that all the symbols from this input file are created, handle
+     .symver foo, foo@BAR such that any relocs against foo become foo@BAR.  */
+  if (nondeflt_vers != NULL)
+    {
+      bfd_size_type cnt, symidx;
+
+      for (cnt = 0; cnt < nondeflt_vers_cnt; ++cnt)
+       {
+         struct elf_link_hash_entry *h = nondeflt_vers[cnt], *hi;
+         char *shortname, *p;
+
+         p = strchr (h->root.root.string, ELF_VER_CHR);
+         if (p == NULL
+             || (h->root.type != bfd_link_hash_defined
+                 && h->root.type != bfd_link_hash_defweak))
+           continue;
+
+         amt = p - h->root.root.string;
+         shortname = bfd_malloc (amt + 1);
+         memcpy (shortname, h->root.root.string, amt);
+         shortname[amt] = '\0';
+
+         hi = (struct elf_link_hash_entry *)
+              bfd_link_hash_lookup (&hash_table->root, shortname,
+                                    FALSE, FALSE, FALSE);
+         if (hi != NULL
+             && hi->root.type == h->root.type
+             && hi->root.u.def.value == h->root.u.def.value
+             && hi->root.u.def.section == h->root.u.def.section)
+           {
+             (*bed->elf_backend_hide_symbol) (info, hi, TRUE);
+             hi->root.type = bfd_link_hash_indirect;
+             hi->root.u.i.link = (struct bfd_link_hash_entry *) h;
+             (*bed->elf_backend_copy_indirect_symbol) (bed, h, hi);
+             sym_hash = elf_sym_hashes (abfd);
+             if (sym_hash)
+               for (symidx = 0; symidx < extsymcount; ++symidx)
+                 if (sym_hash[symidx] == hi)
+                   {
+                     sym_hash[symidx] = h;
+                     break;
+                   }
+           }
+         free (shortname);
+       }
+      free (nondeflt_vers);
+      nondeflt_vers = NULL;
+    }
+
+  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
+     dynamic objects, that's the only time we actually put anything on
+     the list WEAKS.  We need this information so that if a regular
+     object refers to a symbol defined weakly in a dynamic object, the
+     real symbol in the dynamic object is also put in the dynamic
+     symbols; we also must arrange for both symbols to point to the
+     same memory location.  We could handle the general case of symbol
+     aliasing, but a general symbol alias can only be generated in
+     assembler code, handling it correctly would be very time
+     consuming, and other ELF linkers don't handle general aliasing
+     either.  */
+  if (weaks != NULL)
+    {
+      struct elf_link_hash_entry **hpp;
+      struct elf_link_hash_entry **hppend;
+      struct elf_link_hash_entry **sorted_sym_hash;
+      struct elf_link_hash_entry *h;
+      size_t sym_count;
+
+      /* Since we have to search the whole symbol list for each weak
+        defined symbol, search time for N weak defined symbols will be
+        O(N^2). Binary search will cut it down to O(NlogN).  */
+      amt = extsymcount * sizeof (struct elf_link_hash_entry *);
+      sorted_sym_hash = bfd_malloc (amt);
+      if (sorted_sym_hash == NULL)
+       goto error_return;
+      sym_hash = sorted_sym_hash;
+      hpp = elf_sym_hashes (abfd);
+      hppend = hpp + extsymcount;
+      sym_count = 0;
+      for (; hpp < hppend; hpp++)
+       {
+         h = *hpp;
+         if (h != NULL
+             && h->root.type == bfd_link_hash_defined
+             && h->type != STT_FUNC)
+           {
+             *sym_hash = h;
+             sym_hash++;
+             sym_count++;
+           }
+       }
+
+      qsort (sorted_sym_hash, sym_count,
+            sizeof (struct elf_link_hash_entry *),
+            elf_sort_symbol);
+
+      while (weaks != NULL)
+       {
+         struct elf_link_hash_entry *hlook;
+         asection *slook;
+         bfd_vma vlook;
+         long ilook;
+         size_t i, j, idx;
+
+         hlook = weaks;
+         weaks = hlook->weakdef;
+         hlook->weakdef = NULL;
+
+         BFD_ASSERT (hlook->root.type == bfd_link_hash_defined
+                     || hlook->root.type == bfd_link_hash_defweak
+                     || hlook->root.type == bfd_link_hash_common
+                     || hlook->root.type == bfd_link_hash_indirect);
+         slook = hlook->root.u.def.section;
+         vlook = hlook->root.u.def.value;
+
+         ilook = -1;
+         i = 0;
+         j = sym_count;
+         while (i < j)
+           {
+             bfd_signed_vma vdiff;
+             idx = (i + j) / 2;
+             h = sorted_sym_hash [idx];
+             vdiff = vlook - h->root.u.def.value;
+             if (vdiff < 0)
+               j = idx;
+             else if (vdiff > 0)
+               i = idx + 1;
+             else
+               {
+                 long sdiff = slook - h->root.u.def.section;
+                 if (sdiff < 0)
+                   j = idx;
+                 else if (sdiff > 0)
+                   i = idx + 1;
+                 else
+                   {
+                     ilook = idx;
+                     break;
+                   }
+               }
+           }
+
+         /* We didn't find a value/section match.  */
+         if (ilook == -1)
+           continue;
+
+         for (i = ilook; i < sym_count; i++)
+           {
+             h = sorted_sym_hash [i];
+
+             /* Stop if value or section doesn't match.  */
+             if (h->root.u.def.value != vlook
+                 || h->root.u.def.section != slook)
+               break;
+             else if (h != hlook)
+               {
+                 hlook->weakdef = h;
+
+                 /* If the weak definition is in the list of dynamic
+                    symbols, make sure the real definition is put
+                    there as well.  */
+                 if (hlook->dynindx != -1 && h->dynindx == -1)
+                   {
+                     if (! _bfd_elf_link_record_dynamic_symbol (info,
+                                                                h))
+                       goto error_return;
+                   }
+
+                 /* If the real definition is in the list of dynamic
+                    symbols, make sure the weak definition is put
+                    there as well.  If we don't do this, then the
+                    dynamic loader might not merge the entries for the
+                    real definition and the weak definition.  */
+                 if (h->dynindx != -1 && hlook->dynindx == -1)
+                   {
+                     if (! _bfd_elf_link_record_dynamic_symbol (info,
+                                                                hlook))
+                       goto error_return;
+                   }
+                 break;
+               }
+           }
+       }
+
+      free (sorted_sym_hash);
+    }
+
+  /* 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.
+
+     This is required to build global offset table entries and to
+     arrange for dynamic relocs.  It is not required for the
+     particular common case of linking non PIC code, even when linking
+     against shared libraries, but unfortunately there is no way of
+     knowing whether an object file has been compiled PIC or not.
+     Looking through the relocs is not particularly time consuming.
+     The problem is that we must either (1) keep the relocs in memory,
+     which causes the linker to require additional runtime memory or
+     (2) read the relocs twice from the input file, which wastes time.
+     This would be a good case for using mmap.
+
+     I have no idea how to handle linking PIC code into a file of a
+     different format.  It probably can't be done.  */
+  check_relocs = get_elf_backend_data (abfd)->check_relocs;
+  if (! dynamic
+      && is_elf_hash_table (hash_table)
+      && hash_table->root.creator == abfd->xvec
+      && check_relocs != NULL)
+    {
+      asection *o;
+
+      for (o = abfd->sections; o != NULL; o = o->next)
+       {
+         Elf_Internal_Rela *internal_relocs;
+         bfd_boolean ok;
+
+         if ((o->flags & SEC_RELOC) == 0
+             || o->reloc_count == 0
+             || ((info->strip == strip_all || info->strip == strip_debugger)
+                 && (o->flags & SEC_DEBUGGING) != 0)
+             || bfd_is_abs_section (o->output_section))
+           continue;
+
+         internal_relocs = _bfd_elf_link_read_relocs (abfd, o, NULL, NULL,
+                                                      info->keep_memory);
+         if (internal_relocs == NULL)
+           goto error_return;
+
+         ok = (*check_relocs) (abfd, info, o, internal_relocs);
+
+         if (elf_section_data (o)->relocs != internal_relocs)
+           free (internal_relocs);
+
+         if (! ok)
+           goto error_return;
+       }
+    }
+
+  /* If this is a non-traditional link, try to optimize the handling
+     of the .stab/.stabstr sections.  */
+  if (! dynamic
+      && ! info->traditional_format
+      && is_elf_hash_table (hash_table)
+      && (info->strip != strip_all && info->strip != strip_debugger))
+    {
+      asection *stabstr;
+
+      stabstr = bfd_get_section_by_name (abfd, ".stabstr");
+      if (stabstr != NULL)
+       {
+         bfd_size_type string_offset = 0;
+         asection *stab;
+
+         for (stab = abfd->sections; stab; stab = stab->next)
+           if (strncmp (".stab", stab->name, 5) == 0
+               && (!stab->name[5] ||
+                   (stab->name[5] == '.' && ISDIGIT (stab->name[6])))
+               && (stab->flags & SEC_MERGE) == 0
+               && !bfd_is_abs_section (stab->output_section))
+             {
+               struct bfd_elf_section_data *secdata;
+
+               secdata = elf_section_data (stab);
+               if (! _bfd_link_section_stabs (abfd,
+                                              & hash_table->stab_info,
+                                              stab, stabstr,
+                                              &secdata->sec_info,
+                                              &string_offset))
+                 goto error_return;
+               if (secdata->sec_info)
+                 stab->sec_info_type = ELF_INFO_TYPE_STABS;
+           }
+       }
+    }
+
+  if (! info->relocatable
+      && ! dynamic
+      && is_elf_hash_table (hash_table))
+    {
+      asection *s;
+
+      for (s = abfd->sections; s != NULL; s = s->next)
+       if ((s->flags & SEC_MERGE) != 0
+           && !bfd_is_abs_section (s->output_section))
+         {
+           struct bfd_elf_section_data *secdata;
+
+           secdata = elf_section_data (s);
+           if (! _bfd_merge_section (abfd,
+                                     & hash_table->merge_info,
+                                     s, &secdata->sec_info))
+             goto error_return;
+           else if (secdata->sec_info)
+             s->sec_info_type = ELF_INFO_TYPE_MERGE;
+         }
+    }
+
+  if (is_elf_hash_table (hash_table))
+    {
+      /* Add this bfd to the loaded list.  */
+      struct elf_link_loaded_list *n;
+
+      n = bfd_alloc (abfd, sizeof (struct elf_link_loaded_list));
+      if (n == NULL)
+       goto error_return;
+      n->abfd = abfd;
+      n->next = hash_table->loaded;
+      hash_table->loaded = n;
+    }
+
+  return TRUE;
+
+ error_free_vers:
+  if (nondeflt_vers != NULL)
+    free (nondeflt_vers);
+  if (extversym != NULL)
+    free (extversym);
+ error_free_sym:
+  if (isymbuf != NULL)
+    free (isymbuf);
+ error_return:
+  return FALSE;
+}
+
 /* Add symbols from an ELF archive file to the linker hash table.  We
    don't use _bfd_generic_link_add_archive_symbols because of a
    problem which arises on UnixWare.  The UnixWare libc.so is an
@@ -2866,9 +4170,8 @@ _bfd_elf_finalize_dynstr (bfd *output_bfd, struct bfd_link_info *info)
    Unfortunately, we do have to make multiple passes over the symbol
    table until nothing further is resolved.  */
 
-bfd_boolean
-_bfd_elf_link_add_archive_symbols (bfd *abfd,
-                                  struct bfd_link_info *info)
+static bfd_boolean
+elf_link_add_archive_symbols (bfd *abfd, struct bfd_link_info *info)
 {
   symindex c;
   bfd_boolean *defined = NULL;
@@ -3065,6 +4368,24 @@ _bfd_elf_link_add_archive_symbols (bfd *abfd,
     free (included);
   return FALSE;
 }
+
+/* Given an ELF BFD, add symbols to the global hash table as
+   appropriate.  */
+
+bfd_boolean
+bfd_elf_link_add_symbols (bfd *abfd, struct bfd_link_info *info)
+{
+  switch (bfd_get_format (abfd))
+    {
+    case bfd_object:
+      return elf_link_add_object_symbols (abfd, info);
+    case bfd_archive:
+      return elf_link_add_archive_symbols (abfd, info);
+    default:
+      bfd_set_error (bfd_error_wrong_format);
+      return FALSE;
+    }
+}
 \f
 /* This function will be called though elf_link_hash_traverse to store
    all hash value of the exported symbols in an array.  */
@@ -4026,7 +5347,7 @@ bfd_elf_size_dynamic_sections (bfd *output_bfd,
       s = bfd_get_section_by_name (dynobj, ".dynstr");
       BFD_ASSERT (s != NULL);
 
-      _bfd_elf_finalize_dynstr (output_bfd, info);
+      elf_finalize_dynstr (output_bfd, info);
 
       s->_raw_size = _bfd_elf_strtab_size (elf_hash_table (info)->dynstr);
 
index 082db5c3bd2efaaf48bb1f917ab1aa244606acf2..de477dfbd27ccb7b5f2324c460e0e867ed3b8929 100644 (file)
 
 /* ELF linker code.  */
 
-#include "safe-ctype.h"
-
-static bfd_boolean elf_link_add_object_symbols (bfd *, struct bfd_link_info *);
 static bfd_boolean elf_section_ignore_discarded_relocs (asection *);
 
-/* Given an ELF BFD, add symbols to the global hash table as
-   appropriate.  */
-
-bfd_boolean
-elf_bfd_link_add_symbols (bfd *abfd, struct bfd_link_info *info)
-{
-  switch (bfd_get_format (abfd))
-    {
-    case bfd_object:
-      return elf_link_add_object_symbols (abfd, info);
-    case bfd_archive:
-      return _bfd_elf_link_add_archive_symbols (abfd, info);
-    default:
-      bfd_set_error (bfd_error_wrong_format);
-      return FALSE;
-    }
-}
-
-/* Add symbols from an ELF object file to the linker hash table.  */
-
-static bfd_boolean
-elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info)
-{
-  bfd_boolean (*add_symbol_hook)
-    (bfd *, struct bfd_link_info *, const Elf_Internal_Sym *,
-     const char **, flagword *, asection **, bfd_vma *);
-  bfd_boolean (*check_relocs)
-    (bfd *, struct bfd_link_info *, asection *, const Elf_Internal_Rela *);
-  bfd_boolean collect;
-  Elf_Internal_Shdr *hdr;
-  bfd_size_type symcount;
-  bfd_size_type extsymcount;
-  bfd_size_type extsymoff;
-  struct elf_link_hash_entry **sym_hash;
-  bfd_boolean dynamic;
-  Elf_External_Versym *extversym = NULL;
-  Elf_External_Versym *ever;
-  struct elf_link_hash_entry *weaks;
-  struct elf_link_hash_entry **nondeflt_vers = NULL;
-  bfd_size_type nondeflt_vers_cnt = 0;
-  Elf_Internal_Sym *isymbuf = NULL;
-  Elf_Internal_Sym *isym;
-  Elf_Internal_Sym *isymend;
-  const struct elf_backend_data *bed;
-  bfd_boolean add_needed;
-  struct elf_link_hash_table * hash_table;
-  bfd_size_type amt;
-
-  hash_table = elf_hash_table (info);
-
-  bed = get_elf_backend_data (abfd);
-  add_symbol_hook = bed->elf_add_symbol_hook;
-  collect = bed->collect;
-
-  if ((abfd->flags & DYNAMIC) == 0)
-    dynamic = FALSE;
-  else
-    {
-      dynamic = TRUE;
-
-      /* You can't use -r against a dynamic object.  Also, there's no
-        hope of using a dynamic object which does not exactly match
-        the format of the output file.  */
-      if (info->relocatable
-         || !is_elf_hash_table (hash_table)
-         || hash_table->root.creator != abfd->xvec)
-       {
-         bfd_set_error (bfd_error_invalid_operation);
-         goto error_return;
-       }
-    }
-
-  /* As a GNU extension, any input sections which are named
-     .gnu.warning.SYMBOL are treated as warning symbols for the given
-     symbol.  This differs from .gnu.warning sections, which generate
-     warnings when they are included in an output file.  */
-  if (info->executable)
-    {
-      asection *s;
-
-      for (s = abfd->sections; s != NULL; s = s->next)
-       {
-         const char *name;
-
-         name = bfd_get_section_name (abfd, s);
-         if (strncmp (name, ".gnu.warning.", sizeof ".gnu.warning." - 1) == 0)
-           {
-             char *msg;
-             bfd_size_type sz;
-             bfd_size_type prefix_len;
-             const char * gnu_warning_prefix = _("warning: ");
-
-             name += sizeof ".gnu.warning." - 1;
-
-             /* If this is a shared object, then look up the symbol
-                in the hash table.  If it is there, and it is already
-                been defined, then we will not be using the entry
-                from this shared object, so we don't need to warn.
-                FIXME: If we see the definition in a regular object
-                later on, we will warn, but we shouldn't.  The only
-                fix is to keep track of what warnings we are supposed
-                to emit, and then handle them all at the end of the
-                link.  */
-             if (dynamic)
-               {
-                 struct elf_link_hash_entry *h;
-
-                 h = elf_link_hash_lookup (hash_table, name,
-                                           FALSE, FALSE, TRUE);
-
-                 /* FIXME: What about bfd_link_hash_common?  */
-                 if (h != NULL
-                     && (h->root.type == bfd_link_hash_defined
-                         || h->root.type == bfd_link_hash_defweak))
-                   {
-                     /* We don't want to issue this warning.  Clobber
-                        the section size so that the warning does not
-                        get copied into the output file.  */
-                     s->_raw_size = 0;
-                     continue;
-                   }
-               }
-
-             sz = bfd_section_size (abfd, s);
-             prefix_len = strlen (gnu_warning_prefix);
-             msg = bfd_alloc (abfd, prefix_len + sz + 1);
-             if (msg == NULL)
-               goto error_return;
-
-             strcpy (msg, gnu_warning_prefix);
-             if (! bfd_get_section_contents (abfd, s, msg + prefix_len, 0, sz))
-               goto error_return;
-
-             msg[prefix_len + sz] = '\0';
-
-             if (! (_bfd_generic_link_add_one_symbol
-                    (info, abfd, name, BSF_WARNING, s, 0, msg,
-                     FALSE, collect, NULL)))
-               goto error_return;
-
-             if (! info->relocatable)
-               {
-                 /* Clobber the section size so that the warning does
-                    not get copied into the output file.  */
-                 s->_raw_size = 0;
-               }
-           }
-       }
-    }
-
-  add_needed = TRUE;
-  if (! dynamic)
-    {
-      /* If we are creating a shared library, create all the dynamic
-        sections immediately.  We need to attach them to something,
-        so we attach them to this BFD, provided it is the right
-        format.  FIXME: If there are no input BFD's of the same
-        format as the output, we can't make a shared library.  */
-      if (info->shared
-         && is_elf_hash_table (hash_table)
-         && hash_table->root.creator == abfd->xvec
-         && ! hash_table->dynamic_sections_created)
-       {
-         if (! _bfd_elf_link_create_dynamic_sections (abfd, info))
-           goto error_return;
-       }
-    }
-  else if (!is_elf_hash_table (hash_table))
-    goto error_return;
-  else
-    {
-      asection *s;
-      const char *soname = NULL;
-      struct bfd_link_needed_list *rpath = NULL, *runpath = NULL;
-      int ret;
-
-      /* 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
-         && s->sec_info_type == ELF_INFO_TYPE_JUST_SYMS)
-       goto error_return;
-
-      /* If this dynamic lib was specified on the command line with
-        --as-needed in effect, then we don't want to add a DT_NEEDED
-        tag unless the lib is actually used.  Similary for libs brought
-        in by another lib's DT_NEEDED.  */
-      add_needed = elf_dyn_lib_class (abfd) == DYN_NORMAL;
-
-      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;
-
-         dynbuf = bfd_malloc (s->_raw_size);
-         if (dynbuf == NULL)
-           goto error_return;
-
-         if (! bfd_get_section_contents (abfd, s, dynbuf, 0, s->_raw_size))
-           goto error_free_dyn;
-
-         elfsec = _bfd_elf_section_from_bfd_section (abfd, s);
-         if (elfsec == -1)
-           goto error_free_dyn;
-         shlink = elf_elfsections (abfd)[elfsec]->sh_link;
-
-         extdyn = dynbuf;
-         extdynend = extdyn + s->_raw_size / sizeof (Elf_External_Dyn);
-         for (; extdyn < extdynend; extdyn++)
-           {
-             Elf_Internal_Dyn dyn;
-
-             elf_swap_dyn_in (abfd, extdyn, &dyn);
-             if (dyn.d_tag == DT_SONAME)
-               {
-                 unsigned int tagv = dyn.d_un.d_val;
-                 soname = bfd_elf_string_from_elf_section (abfd, shlink, tagv);
-                 if (soname == NULL)
-                   goto error_free_dyn;
-               }
-             if (dyn.d_tag == DT_NEEDED)
-               {
-                 struct bfd_link_needed_list *n, **pn;
-                 char *fnm, *anm;
-                 unsigned int tagv = dyn.d_un.d_val;
-
-                 amt = sizeof (struct bfd_link_needed_list);
-                 n = bfd_alloc (abfd, amt);
-                 fnm = bfd_elf_string_from_elf_section (abfd, shlink, tagv);
-                 if (n == NULL || fnm == NULL)
-                   goto error_free_dyn;
-                 amt = strlen (fnm) + 1;
-                 anm = bfd_alloc (abfd, amt);
-                 if (anm == NULL)
-                   goto error_free_dyn;
-                 memcpy (anm, fnm, amt);
-                 n->name = anm;
-                 n->by = abfd;
-                 n->next = NULL;
-                 for (pn = & hash_table->needed;
-                      *pn != NULL;
-                      pn = &(*pn)->next)
-                   ;
-                 *pn = n;
-               }
-             if (dyn.d_tag == DT_RUNPATH)
-               {
-                 struct bfd_link_needed_list *n, **pn;
-                 char *fnm, *anm;
-                 unsigned int tagv = dyn.d_un.d_val;
-
-                 amt = sizeof (struct bfd_link_needed_list);
-                 n = bfd_alloc (abfd, amt);
-                 fnm = bfd_elf_string_from_elf_section (abfd, shlink, tagv);
-                 if (n == NULL || fnm == NULL)
-                   goto error_free_dyn;
-                 amt = strlen (fnm) + 1;
-                 anm = bfd_alloc (abfd, amt);
-                 if (anm == NULL)
-                   goto error_free_dyn;
-                 memcpy (anm, fnm, amt);
-                 n->name = anm;
-                 n->by = abfd;
-                 n->next = NULL;
-                 for (pn = & runpath;
-                      *pn != NULL;
-                      pn = &(*pn)->next)
-                   ;
-                 *pn = n;
-               }
-             /* Ignore DT_RPATH if we have seen DT_RUNPATH.  */
-             if (!runpath && dyn.d_tag == DT_RPATH)
-               {
-                 struct bfd_link_needed_list *n, **pn;
-                 char *fnm, *anm;
-                 unsigned int tagv = dyn.d_un.d_val;
-
-                 amt = sizeof (struct bfd_link_needed_list);
-                 n = bfd_alloc (abfd, amt);
-                 fnm = bfd_elf_string_from_elf_section (abfd, shlink, tagv);
-                 if (n == NULL || fnm == NULL)
-                   goto error_free_dyn;
-                 amt = strlen (fnm) + 1;
-                 anm = bfd_alloc (abfd, amt);
-                 if (anm == NULL)
-                   {
-                   error_free_dyn:
-                     free (dynbuf);
-                     goto error_return;
-                   }
-                 memcpy (anm, fnm, amt);
-                 n->name = anm;
-                 n->by = abfd;
-                 n->next = NULL;
-                 for (pn = & rpath;
-                      *pn != NULL;
-                      pn = &(*pn)->next)
-                   ;
-                 *pn = n;
-               }
-           }
-
-         free (dynbuf);
-       }
-
-      /* 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
-        object in the output file.  We hack by simply clobbering the
-        list of sections in the BFD.  This could be handled more
-        cleanly by, say, a new section flag; the existing
-        SEC_NEVER_LOAD flag is not the one we want, because that one
-        still implies that the section takes up space in the output
-        file.  */
-      bfd_section_list_clear (abfd);
-
-      /* If this is the first dynamic object found in the link, create
-        the special sections required for dynamic linking.  */
-      if (! _bfd_elf_link_create_dynamic_sections (abfd, info))
-       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.
-        Otherwise, if the generic linker stuck something in
-        elf_dt_name, we use that.  Otherwise, we just use the file
-        name.  */
-      if (soname == NULL || *soname == '\0')
-       {
-         soname = elf_dt_name (abfd);
-         if (soname == NULL || *soname == '\0')
-           soname = bfd_get_filename (abfd);
-       }
-
-      /* Save the SONAME because sometimes the linker emulation code
-        will need to know it.  */
-      elf_dt_name (abfd) = soname;
-
-      ret = _bfd_elf_add_dt_needed_tag (info, soname, add_needed);
-      if (ret < 0)
-       goto error_return;
-
-      /* If we have already included this dynamic object in the
-        link, just ignore it.  There is no reason to include a
-        particular dynamic object more than once.  */
-      if (ret > 0)
-       return TRUE;
-    }
-
-  /* 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;
-    }
-
-  sym_hash = NULL;
-  if (extsymcount != 0)
-    {
-      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 = 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 = 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 (extversym, amt, abfd) != amt)
-           goto error_free_vers;
-       }
-    }
-
-  weaks = NULL;
-
-  ever = extversym != NULL ? extversym + extsymoff : NULL;
-  for (isym = isymbuf, isymend = isymbuf + extsymcount;
-       isym < isymend;
-       isym++, sym_hash++, ever = (ever != NULL ? ever + 1 : NULL))
-    {
-      int bind;
-      bfd_vma value;
-      asection *sec;
-      flagword flags;
-      const char *name;
-      struct elf_link_hash_entry *h;
-      bfd_boolean definition;
-      bfd_boolean size_change_ok;
-      bfd_boolean type_change_ok;
-      bfd_boolean new_weakdef;
-      bfd_boolean override;
-      unsigned int old_alignment;
-      bfd *old_bfd;
-
-      override = FALSE;
-
-      flags = BSF_NO_FLAGS;
-      sec = NULL;
-      value = isym->st_value;
-      *sym_hash = NULL;
-
-      bind = ELF_ST_BIND (isym->st_info);
-      if (bind == STB_LOCAL)
-       {
-         /* This should be impossible, since ELF requires that all
-            global symbols follow all local symbols, and that sh_info
-            point to the first global symbol.  Unfortunately, Irix 5
-            screws this up.  */
-         continue;
-       }
-      else if (bind == STB_GLOBAL)
-       {
-         if (isym->st_shndx != SHN_UNDEF
-             && isym->st_shndx != SHN_COMMON)
-           flags = BSF_GLOBAL;
-       }
-      else if (bind == STB_WEAK)
-       flags = BSF_WEAK;
-      else
-       {
-         /* Leave it up to the processor backend.  */
-       }
-
-      if (isym->st_shndx == SHN_UNDEF)
-       sec = bfd_und_section_ptr;
-      else if (isym->st_shndx < SHN_LORESERVE || isym->st_shndx > SHN_HIRESERVE)
-       {
-         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 (isym->st_shndx == SHN_ABS)
-       sec = bfd_abs_section_ptr;
-      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 = isym->st_size;
-       }
-      else
-       {
-         /* Leave it up to the processor backend.  */
-       }
-
-      name = bfd_elf_string_from_elf_section (abfd, hdr->sh_link,
-                                             isym->st_name);
-      if (name == NULL)
-       goto error_free_vers;
-
-      if (isym->st_shndx == SHN_COMMON
-         && ELF_ST_TYPE (isym->st_info) == STT_TLS)
-       {
-         asection *tcomm = bfd_get_section_by_name (abfd, ".tcommon");
-
-         if (tcomm == NULL)
-           {
-             tcomm = bfd_make_section (abfd, ".tcommon");
-             if (tcomm == NULL
-                 || !bfd_set_section_flags (abfd, tcomm, (SEC_ALLOC
-                                                          | SEC_IS_COMMON
-                                                          | SEC_LINKER_CREATED
-                                                          | SEC_THREAD_LOCAL)))
-               goto error_free_vers;
-           }
-         sec = tcomm;
-       }
-      else if (add_symbol_hook)
-       {
-         if (! (*add_symbol_hook) (abfd, info, isym, &name, &flags, &sec,
-                                   &value))
-           goto error_free_vers;
-
-         /* The hook function sets the name to NULL if this symbol
-            should be skipped for some reason.  */
-         if (name == NULL)
-           continue;
-       }
-
-      /* Sanity check that all possibilities were handled.  */
-      if (sec == NULL)
-       {
-         bfd_set_error (bfd_error_bad_value);
-         goto error_free_vers;
-       }
-
-      if (bfd_is_und_section (sec)
-         || bfd_is_com_section (sec))
-       definition = FALSE;
-      else
-       definition = TRUE;
-
-      size_change_ok = FALSE;
-      type_change_ok = get_elf_backend_data (abfd)->type_change_ok;
-      old_alignment = 0;
-      old_bfd = NULL;
-
-      if (is_elf_hash_table (hash_table))
-       {
-         Elf_Internal_Versym iver;
-         unsigned int vernum = 0;
-         bfd_boolean skip;
-
-         if (ever != NULL)
-           {
-             _bfd_elf_swap_versym_in (abfd, ever, &iver);
-             vernum = iver.vs_vers & VERSYM_VERSION;
-
-             /* If this is a hidden symbol, or if it is not version
-                1, we append the version name to the symbol name.
-                However, we do not modify a non-hidden absolute
-                symbol, because it might be the version symbol
-                itself.  FIXME: What if it isn't?  */
-             if ((iver.vs_vers & VERSYM_HIDDEN) != 0
-                 || (vernum > 1 && ! bfd_is_abs_section (sec)))
-               {
-                 const char *verstr;
-                 size_t namelen, verlen, newlen;
-                 char *newname, *p;
-
-                 if (isym->st_shndx != SHN_UNDEF)
-                   {
-                     if (vernum > elf_tdata (abfd)->dynverdef_hdr.sh_info)
-                       {
-                         (*_bfd_error_handler)
-                           (_("%s: %s: invalid version %u (max %d)"),
-                            bfd_archive_filename (abfd), name, vernum,
-                            elf_tdata (abfd)->dynverdef_hdr.sh_info);
-                         bfd_set_error (bfd_error_bad_value);
-                         goto error_free_vers;
-                       }
-                     else if (vernum > 1)
-                       verstr =
-                         elf_tdata (abfd)->verdef[vernum - 1].vd_nodename;
-                     else
-                       verstr = "";
-                   }
-                 else
-                   {
-                     /* We cannot simply test for the number of
-                        entries in the VERNEED section since the
-                        numbers for the needed versions do not start
-                        at 0.  */
-                     Elf_Internal_Verneed *t;
-
-                     verstr = NULL;
-                     for (t = elf_tdata (abfd)->verref;
-                          t != NULL;
-                          t = t->vn_nextref)
-                       {
-                         Elf_Internal_Vernaux *a;
-
-                         for (a = t->vn_auxptr; a != NULL; a = a->vna_nextptr)
-                           {
-                             if (a->vna_other == vernum)
-                               {
-                                 verstr = a->vna_nodename;
-                                 break;
-                               }
-                           }
-                         if (a != NULL)
-                           break;
-                       }
-                     if (verstr == NULL)
-                       {
-                         (*_bfd_error_handler)
-                           (_("%s: %s: invalid needed version %d"),
-                            bfd_archive_filename (abfd), name, vernum);
-                         bfd_set_error (bfd_error_bad_value);
-                         goto error_free_vers;
-                       }
-                   }
-
-                 namelen = strlen (name);
-                 verlen = strlen (verstr);
-                 newlen = namelen + verlen + 2;
-                 if ((iver.vs_vers & VERSYM_HIDDEN) == 0
-                     && isym->st_shndx != SHN_UNDEF)
-                   ++newlen;
-
-                 newname = bfd_alloc (abfd, newlen);
-                 if (newname == NULL)
-                   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
-                     && isym->st_shndx != SHN_UNDEF)
-                   *p++ = ELF_VER_CHR;
-                 memcpy (p, verstr, verlen + 1);
-
-                 name = newname;
-               }
-           }
-
-         if (!_bfd_elf_merge_symbol (abfd, info, name, isym, &sec, &value,
-                                     sym_hash, &skip, &override,
-                                     &type_change_ok, &size_change_ok))
-           goto error_free_vers;
-
-         if (skip)
-           continue;
-
-         if (override)
-           definition = FALSE;
-
-         h = *sym_hash;
-         while (h->root.type == bfd_link_hash_indirect
-                || h->root.type == bfd_link_hash_warning)
-           h = (struct elf_link_hash_entry *) h->root.u.i.link;
-
-         /* Remember the old alignment if this is a common symbol, so
-            that we don't reduce the alignment later on.  We can't
-            check later, because _bfd_generic_link_add_one_symbol
-            will set a default for the alignment which we want to
-            override. We also remember the old bfd where the existing
-            definition comes from.  */
-         switch (h->root.type)
-           {
-           default:
-             break;
-
-           case bfd_link_hash_defined:
-           case bfd_link_hash_defweak:
-             old_bfd = h->root.u.def.section->owner;
-             break;
-
-           case bfd_link_hash_common:
-             old_bfd = h->root.u.c.p->section->owner;
-             old_alignment = h->root.u.c.p->alignment_power;
-             break;
-           }
-
-         if (elf_tdata (abfd)->verdef != NULL
-             && ! override
-             && vernum > 1
-             && definition)
-           h->verinfo.verdef = &elf_tdata (abfd)->verdef[vernum - 1];
-       }
-
-      if (! (_bfd_generic_link_add_one_symbol
-            (info, abfd, name, flags, sec, value, NULL, FALSE, collect,
-             (struct bfd_link_hash_entry **) sym_hash)))
-       goto error_free_vers;
-
-      h = *sym_hash;
-      while (h->root.type == bfd_link_hash_indirect
-            || h->root.type == bfd_link_hash_warning)
-       h = (struct elf_link_hash_entry *) h->root.u.i.link;
-      *sym_hash = h;
-
-      new_weakdef = FALSE;
-      if (dynamic
-         && definition
-         && (flags & BSF_WEAK) != 0
-         && ELF_ST_TYPE (isym->st_info) != STT_FUNC
-         && is_elf_hash_table (hash_table)
-         && h->weakdef == NULL)
-       {
-         /* Keep a list of all weak defined non function symbols from
-            a dynamic object, using the weakdef field.  Later in this
-            function we will set the weakdef field to the correct
-            value.  We only put non-function symbols from dynamic
-            objects on this list, because that happens to be the only
-            time we need to know the normal symbol corresponding to a
-            weak symbol, and the information is time consuming to
-            figure out.  If the weakdef field is not already NULL,
-            then this symbol was already defined by some previous
-            dynamic object, and we will be using that previous
-            definition anyhow.  */
-
-         h->weakdef = weaks;
-         weaks = h;
-         new_weakdef = TRUE;
-       }
-
-      /* Set the alignment of a common symbol.  */
-      if (isym->st_shndx == SHN_COMMON
-         && h->root.type == bfd_link_hash_common)
-       {
-         unsigned int align;
-
-         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.  */
-             || (isym->st_value == 1 && old_alignment == 0))
-           h->root.u.c.p->alignment_power = align;
-         else
-           h->root.u.c.p->alignment_power = old_alignment;
-       }
-
-      if (is_elf_hash_table (hash_table))
-       {
-         int old_flags;
-         bfd_boolean dynsym;
-         int new_flag;
-
-         /* Check the alignment when a common symbol is involved. This
-            can change when a common symbol is overridden by a normal
-            definition or a common symbol is ignored due to the old
-            normal definition. We need to make sure the maximum
-            alignment is maintained.  */
-         if ((old_alignment || isym->st_shndx == SHN_COMMON)
-             && h->root.type != bfd_link_hash_common)
-           {
-             unsigned int common_align;
-             unsigned int normal_align;
-             unsigned int symbol_align;
-             bfd *normal_bfd;
-             bfd *common_bfd;
-
-             symbol_align = ffs (h->root.u.def.value) - 1;
-             if (h->root.u.def.section->owner != NULL
-                 && (h->root.u.def.section->owner->flags & DYNAMIC) == 0)
-               {
-                 normal_align = h->root.u.def.section->alignment_power;
-                 if (normal_align > symbol_align)
-                   normal_align = symbol_align;
-               }
-             else
-               normal_align = symbol_align;
-
-             if (old_alignment)
-               {
-                 common_align = old_alignment;
-                 common_bfd = old_bfd;
-                 normal_bfd = abfd;
-               }
-             else
-               {
-                 common_align = bfd_log2 (isym->st_value);
-                 common_bfd = abfd;
-                 normal_bfd = old_bfd;
-               }
-
-             if (normal_align < common_align)
-               (*_bfd_error_handler)
-                 (_("Warning: alignment %u of symbol `%s' in %s is smaller than %u in %s"),
-                  1 << normal_align,
-                  name,
-                  bfd_archive_filename (normal_bfd),
-                  1 << common_align,
-                  bfd_archive_filename (common_bfd));
-           }
-
-         /* Remember the symbol size and type.  */
-         if (isym->st_size != 0
-             && (definition || h->size == 0))
-           {
-             if (h->size != 0 && h->size != isym->st_size && ! size_change_ok)
-               (*_bfd_error_handler)
-                 (_("Warning: size of symbol `%s' changed from %lu in %s to %lu in %s"),
-                  name, (unsigned long) h->size,
-                  bfd_archive_filename (old_bfd),
-                  (unsigned long) isym->st_size,
-                  bfd_archive_filename (abfd));
-
-             h->size = isym->st_size;
-           }
-
-         /* If this is a common symbol, then we always want H->SIZE
-            to be the size of the common symbol.  The code just above
-            won't fix the size if a common symbol becomes larger.  We
-            don't warn about a size change here, because that is
-            covered by --warn-common.  */
-         if (h->root.type == bfd_link_hash_common)
-           h->size = h->root.u.c.size;
-
-         if (ELF_ST_TYPE (isym->st_info) != STT_NOTYPE
-             && (definition || h->type == STT_NOTYPE))
-           {
-             if (h->type != STT_NOTYPE
-                 && 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 (isym->st_info),
-                  bfd_archive_filename (abfd));
-
-             h->type = ELF_ST_TYPE (isym->st_info);
-           }
-
-         /* If st_other has a processor-specific meaning, specific
-            code might be needed here. We never merge the visibility
-            attribute with the one from a dynamic object.  */
-         if (bed->elf_backend_merge_symbol_attribute)
-           (*bed->elf_backend_merge_symbol_attribute) (h, isym, definition,
-                                                       dynamic);
-
-         if (isym->st_other != 0 && !dynamic)
-           {
-             unsigned char hvis, symvis, other, nvis;
-
-             /* Take the balance of OTHER from the definition.  */
-             other = (definition ? isym->st_other : h->other);
-             other &= ~ ELF_ST_VISIBILITY (-1);
-
-             /* Combine visibilities, using the most constraining one.  */
-             hvis   = ELF_ST_VISIBILITY (h->other);
-             symvis = ELF_ST_VISIBILITY (isym->st_other);
-             if (! hvis)
-               nvis = symvis;
-             else if (! symvis)
-               nvis = hvis;
-             else
-               nvis = hvis < symvis ? hvis : symvis;
-
-             h->other = other | nvis;
-           }
-
-         /* Set a flag in the hash table entry indicating the type of
-            reference or definition we just found.  Keep a count of
-            the number of dynamic symbols we find.  A dynamic symbol
-            is one which is referenced or defined by both a regular
-            object and a shared object.  */
-         old_flags = h->elf_link_hash_flags;
-         dynsym = FALSE;
-         if (! dynamic)
-           {
-             if (! definition)
-               {
-                 new_flag = ELF_LINK_HASH_REF_REGULAR;
-                 if (bind != STB_WEAK)
-                   new_flag |= ELF_LINK_HASH_REF_REGULAR_NONWEAK;
-               }
-             else
-               new_flag = ELF_LINK_HASH_DEF_REGULAR;
-             if (! info->executable
-                 || (old_flags & (ELF_LINK_HASH_DEF_DYNAMIC
-                                  | ELF_LINK_HASH_REF_DYNAMIC)) != 0)
-               dynsym = TRUE;
-           }
-         else
-           {
-             if (! definition)
-               new_flag = ELF_LINK_HASH_REF_DYNAMIC;
-             else
-               new_flag = ELF_LINK_HASH_DEF_DYNAMIC;
-             if ((old_flags & (ELF_LINK_HASH_DEF_REGULAR
-                               | ELF_LINK_HASH_REF_REGULAR)) != 0
-                 || (h->weakdef != NULL
-                     && ! new_weakdef
-                     && h->weakdef->dynindx != -1))
-               dynsym = TRUE;
-           }
-
-         h->elf_link_hash_flags |= new_flag;
-
-         /* 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 (!_bfd_elf_add_default_symbol (abfd, info, h, name, isym,
-                                             &sec, &value, &dynsym,
-                                             override))
-             goto error_free_vers;
-
-         if (definition && !dynamic)
-           {
-             char *p = strchr (name, ELF_VER_CHR);
-             if (p != NULL && p[1] != ELF_VER_CHR)
-               {
-                 /* Queue non-default versions so that .symver x, x@FOO
-                    aliases can be checked.  */
-                 if (! nondeflt_vers)
-                   {
-                     amt = (isymend - isym + 1)
-                           * sizeof (struct elf_link_hash_entry *);
-                     nondeflt_vers = bfd_malloc (amt);
-                   }
-                 nondeflt_vers [nondeflt_vers_cnt++] = h;
-               }
-           }
-
-         if (dynsym && h->dynindx == -1)
-           {
-             if (! _bfd_elf_link_record_dynamic_symbol (info, h))
-               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_free_vers;
-               }
-           }
-         else if (dynsym && h->dynindx != -1)
-           /* If the symbol already has a dynamic index, but
-              visibility says it should not be visible, turn it into
-              a local symbol.  */
-           switch (ELF_ST_VISIBILITY (h->other))
-             {
-             case STV_INTERNAL:
-             case STV_HIDDEN:
-               (*bed->elf_backend_hide_symbol) (info, h, TRUE);
-               dynsym = FALSE;
-               break;
-             }
-
-         if (!add_needed
-             && definition
-             && dynsym
-             && (h->elf_link_hash_flags
-                 & ELF_LINK_HASH_REF_REGULAR) != 0)
-           {
-             int ret;
-             const char *soname = elf_dt_name (abfd);
-
-             /* A symbol from a library loaded via DT_NEEDED of some
-                other library is referenced by a regular object.
-                Add a DT_NEEDED entry for it.  */
-             add_needed = TRUE;
-             ret = _bfd_elf_add_dt_needed_tag (info, soname, add_needed);
-             if (ret < 0)
-               goto error_free_vers;
-
-             BFD_ASSERT (ret == 0);
-           }
-       }
-    }
-
-  /* Now that all the symbols from this input file are created, handle
-     .symver foo, foo@BAR such that any relocs against foo become foo@BAR.  */
-  if (nondeflt_vers != NULL)
-    {
-      bfd_size_type cnt, symidx;
-
-      for (cnt = 0; cnt < nondeflt_vers_cnt; ++cnt)
-       {
-         struct elf_link_hash_entry *h = nondeflt_vers[cnt], *hi;
-         char *shortname, *p;
-
-         p = strchr (h->root.root.string, ELF_VER_CHR);
-         if (p == NULL
-             || (h->root.type != bfd_link_hash_defined
-                 && h->root.type != bfd_link_hash_defweak))
-           continue;
-
-         amt = p - h->root.root.string;
-         shortname = bfd_malloc (amt + 1);
-         memcpy (shortname, h->root.root.string, amt);
-         shortname[amt] = '\0';
-
-         hi = (struct elf_link_hash_entry *)
-              bfd_link_hash_lookup (&hash_table->root, shortname,
-                                    FALSE, FALSE, FALSE);
-         if (hi != NULL
-             && hi->root.type == h->root.type
-             && hi->root.u.def.value == h->root.u.def.value
-             && hi->root.u.def.section == h->root.u.def.section)
-           {
-             (*bed->elf_backend_hide_symbol) (info, hi, TRUE);
-             hi->root.type = bfd_link_hash_indirect;
-             hi->root.u.i.link = (struct bfd_link_hash_entry *) h;
-             (*bed->elf_backend_copy_indirect_symbol) (bed, h, hi);
-             sym_hash = elf_sym_hashes (abfd);
-             if (sym_hash)
-               for (symidx = 0; symidx < extsymcount; ++symidx)
-                 if (sym_hash[symidx] == hi)
-                   {
-                     sym_hash[symidx] = h;
-                     break;
-                   }
-           }
-         free (shortname);
-       }
-      free (nondeflt_vers);
-      nondeflt_vers = NULL;
-    }
-
-  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
-     dynamic objects, that's the only time we actually put anything on
-     the list WEAKS.  We need this information so that if a regular
-     object refers to a symbol defined weakly in a dynamic object, the
-     real symbol in the dynamic object is also put in the dynamic
-     symbols; we also must arrange for both symbols to point to the
-     same memory location.  We could handle the general case of symbol
-     aliasing, but a general symbol alias can only be generated in
-     assembler code, handling it correctly would be very time
-     consuming, and other ELF linkers don't handle general aliasing
-     either.  */
-  if (weaks != NULL)
-    {
-      struct elf_link_hash_entry **hpp;
-      struct elf_link_hash_entry **hppend;
-      struct elf_link_hash_entry **sorted_sym_hash;
-      struct elf_link_hash_entry *h;
-      size_t sym_count;
-
-      /* Since we have to search the whole symbol list for each weak
-        defined symbol, search time for N weak defined symbols will be
-        O(N^2). Binary search will cut it down to O(NlogN).  */
-      amt = extsymcount * sizeof (struct elf_link_hash_entry *);
-      sorted_sym_hash = bfd_malloc (amt);
-      if (sorted_sym_hash == NULL)
-       goto error_return;
-      sym_hash = sorted_sym_hash;
-      hpp = elf_sym_hashes (abfd);
-      hppend = hpp + extsymcount;
-      sym_count = 0;
-      for (; hpp < hppend; hpp++)
-       {
-         h = *hpp;
-         if (h != NULL
-             && h->root.type == bfd_link_hash_defined
-             && h->type != STT_FUNC)
-           {
-             *sym_hash = h;
-             sym_hash++;
-             sym_count++;
-           }
-       }
-
-      qsort (sorted_sym_hash, sym_count,
-            sizeof (struct elf_link_hash_entry *),
-            _bfd_elf_sort_symbol);
-
-      while (weaks != NULL)
-       {
-         struct elf_link_hash_entry *hlook;
-         asection *slook;
-         bfd_vma vlook;
-         long ilook;
-         size_t i, j, idx;
-
-         hlook = weaks;
-         weaks = hlook->weakdef;
-         hlook->weakdef = NULL;
-
-         BFD_ASSERT (hlook->root.type == bfd_link_hash_defined
-                     || hlook->root.type == bfd_link_hash_defweak
-                     || hlook->root.type == bfd_link_hash_common
-                     || hlook->root.type == bfd_link_hash_indirect);
-         slook = hlook->root.u.def.section;
-         vlook = hlook->root.u.def.value;
-
-         ilook = -1;
-         i = 0;
-         j = sym_count;
-         while (i < j)
-           {
-             bfd_signed_vma vdiff;
-             idx = (i + j) / 2;
-             h = sorted_sym_hash [idx];
-             vdiff = vlook - h->root.u.def.value;
-             if (vdiff < 0)
-               j = idx;
-             else if (vdiff > 0)
-               i = idx + 1;
-             else
-               {
-                 long sdiff = slook - h->root.u.def.section;
-                 if (sdiff < 0)
-                   j = idx;
-                 else if (sdiff > 0)
-                   i = idx + 1;
-                 else
-                   {
-                     ilook = idx;
-                     break;
-                   }
-               }
-           }
-
-         /* We didn't find a value/section match.  */
-         if (ilook == -1)
-           continue;
-
-         for (i = ilook; i < sym_count; i++)
-           {
-             h = sorted_sym_hash [i];
-
-             /* Stop if value or section doesn't match.  */
-             if (h->root.u.def.value != vlook
-                 || h->root.u.def.section != slook)
-               break;
-             else if (h != hlook)
-               {
-                 hlook->weakdef = h;
-
-                 /* If the weak definition is in the list of dynamic
-                    symbols, make sure the real definition is put
-                    there as well.  */
-                 if (hlook->dynindx != -1 && h->dynindx == -1)
-                   {
-                     if (! _bfd_elf_link_record_dynamic_symbol (info,
-                                                                h))
-                       goto error_return;
-                   }
-
-                 /* If the real definition is in the list of dynamic
-                    symbols, make sure the weak definition is put
-                    there as well.  If we don't do this, then the
-                    dynamic loader might not merge the entries for the
-                    real definition and the weak definition.  */
-                 if (h->dynindx != -1 && hlook->dynindx == -1)
-                   {
-                     if (! _bfd_elf_link_record_dynamic_symbol (info,
-                                                                hlook))
-                       goto error_return;
-                   }
-                 break;
-               }
-           }
-       }
-
-      free (sorted_sym_hash);
-    }
-
-  /* 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.
-
-     This is required to build global offset table entries and to
-     arrange for dynamic relocs.  It is not required for the
-     particular common case of linking non PIC code, even when linking
-     against shared libraries, but unfortunately there is no way of
-     knowing whether an object file has been compiled PIC or not.
-     Looking through the relocs is not particularly time consuming.
-     The problem is that we must either (1) keep the relocs in memory,
-     which causes the linker to require additional runtime memory or
-     (2) read the relocs twice from the input file, which wastes time.
-     This would be a good case for using mmap.
-
-     I have no idea how to handle linking PIC code into a file of a
-     different format.  It probably can't be done.  */
-  check_relocs = get_elf_backend_data (abfd)->check_relocs;
-  if (! dynamic
-      && is_elf_hash_table (hash_table)
-      && hash_table->root.creator == abfd->xvec
-      && check_relocs != NULL)
-    {
-      asection *o;
-
-      for (o = abfd->sections; o != NULL; o = o->next)
-       {
-         Elf_Internal_Rela *internal_relocs;
-         bfd_boolean ok;
-
-         if ((o->flags & SEC_RELOC) == 0
-             || o->reloc_count == 0
-             || ((info->strip == strip_all || info->strip == strip_debugger)
-                 && (o->flags & SEC_DEBUGGING) != 0)
-             || bfd_is_abs_section (o->output_section))
-           continue;
-
-         internal_relocs = _bfd_elf_link_read_relocs (abfd, o, NULL, NULL,
-                                                      info->keep_memory);
-         if (internal_relocs == NULL)
-           goto error_return;
-
-         ok = (*check_relocs) (abfd, info, o, internal_relocs);
-
-         if (elf_section_data (o)->relocs != internal_relocs)
-           free (internal_relocs);
-
-         if (! ok)
-           goto error_return;
-       }
-    }
-
-  /* If this is a non-traditional link, try to optimize the handling
-     of the .stab/.stabstr sections.  */
-  if (! dynamic
-      && ! info->traditional_format
-      && is_elf_hash_table (hash_table)
-      && (info->strip != strip_all && info->strip != strip_debugger))
-    {
-      asection *stabstr;
-
-      stabstr = bfd_get_section_by_name (abfd, ".stabstr");
-      if (stabstr != NULL)
-       {
-         bfd_size_type string_offset = 0;
-         asection *stab;
-
-         for (stab = abfd->sections; stab; stab = stab->next)
-           if (strncmp (".stab", stab->name, 5) == 0
-               && (!stab->name[5] ||
-                   (stab->name[5] == '.' && ISDIGIT (stab->name[6])))
-               && (stab->flags & SEC_MERGE) == 0
-               && !bfd_is_abs_section (stab->output_section))
-             {
-               struct bfd_elf_section_data *secdata;
-
-               secdata = elf_section_data (stab);
-               if (! _bfd_link_section_stabs (abfd,
-                                              & hash_table->stab_info,
-                                              stab, stabstr,
-                                              &secdata->sec_info,
-                                              &string_offset))
-                 goto error_return;
-               if (secdata->sec_info)
-                 stab->sec_info_type = ELF_INFO_TYPE_STABS;
-           }
-       }
-    }
-
-  if (! info->relocatable
-      && ! dynamic
-      && is_elf_hash_table (hash_table))
-    {
-      asection *s;
-
-      for (s = abfd->sections; s != NULL; s = s->next)
-       if ((s->flags & SEC_MERGE) != 0
-           && !bfd_is_abs_section (s->output_section))
-         {
-           struct bfd_elf_section_data *secdata;
-
-           secdata = elf_section_data (s);
-           if (! _bfd_merge_section (abfd,
-                                     & hash_table->merge_info,
-                                     s, &secdata->sec_info))
-             goto error_return;
-           else if (secdata->sec_info)
-             s->sec_info_type = ELF_INFO_TYPE_MERGE;
-         }
-    }
-
-  if (is_elf_hash_table (hash_table))
-    {
-      /* Add this bfd to the loaded list.  */
-      struct elf_link_loaded_list *n;
-
-      n = bfd_alloc (abfd, sizeof (struct elf_link_loaded_list));
-      if (n == NULL)
-       goto error_return;
-      n->abfd = abfd;
-      n->next = hash_table->loaded;
-      hash_table->loaded = n;
-    }
-
-  return TRUE;
-
- error_free_vers:
-  if (nondeflt_vers != NULL)
-    free (nondeflt_vers);
-  if (extversym != NULL)
-    free (extversym);
- error_free_sym:
-  if (isymbuf != NULL)
-    free (isymbuf);
- error_return:
-  return FALSE;
-}
-\f
 /* Final phase of ELF linker.  */
 
 /* A structure we use to avoid passing large numbers of arguments.  */
index 5bf8f4d31d6ae225049f761156e7f43f1f557fb2..8dfd56a68fe420d639891ca6a37d37167a0b60d5 100644 (file)
 #ifndef bfd_elfNN_bfd_link_hash_table_create
 #define bfd_elfNN_bfd_link_hash_table_create _bfd_elf_link_hash_table_create
 #endif
+#ifndef bfd_elfNN_bfd_link_add_symbols
+#define bfd_elfNN_bfd_link_add_symbols bfd_elf_link_add_symbols
+#endif
 #else /* ! defined (elf_backend_relocate_section) */
 /* If no backend relocate_section routine, use the generic linker.
    Note - this will prevent the port from being able to use some of