This is the mail archive of the binutils@sources.redhat.com mailing list for the binutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: move elflink.h code to elflink.c


On Thu, Mar 25, 2004 at 11:15:53PM +1030, Alan Modra wrote:
> This moves 1200 lines of code from elflink.h (where it is compiled

More migration of code from elflink.h to elflink.c.

	* 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.

Index: bfd/elf-bfd.h
===================================================================
RCS file: /cvs/src/src/bfd/elf-bfd.h,v
retrieving revision 1.132
diff -u -p -r1.132 elf-bfd.h
--- bfd/elf-bfd.h	25 Mar 2004 12:48:31 -0000	1.132
+++ bfd/elf-bfd.h	26 Mar 2004 04:26:46 -0000
@@ -1544,9 +1544,6 @@ extern bfd_boolean _bfd_elf_dynamic_symb
 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_s
 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_s
   (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: bfd/elf32-gen.c
===================================================================
RCS file: /cvs/src/src/bfd/elf32-gen.c,v
retrieving revision 1.10
diff -u -p -r1.10 elf32-gen.c
--- bfd/elf32-gen.c	30 Nov 2002 08:39:37 -0000	1.10
+++ bfd/elf32-gen.c	26 Mar 2004 04:26:47 -0000
@@ -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, in
 	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: bfd/elf64-gen.c
===================================================================
RCS file: /cvs/src/src/bfd/elf64-gen.c,v
retrieving revision 1.10
diff -u -p -r1.10 elf64-gen.c
--- bfd/elf64-gen.c	30 Nov 2002 08:39:38 -0000	1.10
+++ bfd/elf64-gen.c	26 Mar 2004 04:26:59 -0000
@@ -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, in
 	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: bfd/elfcode.h
===================================================================
RCS file: /cvs/src/src/bfd/elfcode.h,v
retrieving revision 1.51
diff -u -p -r1.51 elfcode.h
--- bfd/elfcode.h	25 Mar 2004 12:48:41 -0000	1.51
+++ bfd/elfcode.h	26 Mar 2004 04:27:10 -0000
@@ -115,7 +115,6 @@ Foundation, Inc., 59 Temple Place - Suit
 #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: bfd/elflink.c
===================================================================
RCS file: /cvs/src/src/bfd/elflink.c,v
retrieving revision 1.60
diff -u -p -r1.60 elflink.c
--- bfd/elflink.c	25 Mar 2004 12:48:41 -0000	1.60
+++ bfd/elflink.c	26 Mar 2004 04:48:39 -0000
@@ -24,6 +24,7 @@ Foundation, Inc., 59 Temple Place - Suit
 #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_l
    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_l
 }
 
 /* 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, 
     }
   return 0;
 }
-
+
 /* 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_li
 /* 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_bf
   return TRUE;
 }
 
+/* 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_bf
    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 *
     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;
+    }
+}
 
 /* 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 *outp
       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: bfd/elflink.h
===================================================================
RCS file: /cvs/src/src/bfd/elflink.h,v
retrieving revision 1.258
diff -u -p -r1.258 elflink.h
--- bfd/elflink.h	25 Mar 2004 12:48:42 -0000	1.258
+++ bfd/elflink.h	26 Mar 2004 04:27:15 -0000
@@ -20,1333 +20,8 @@
 
 /* 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;
-}
-
 /* Final phase of ELF linker.  */
 
 /* A structure we use to avoid passing large numbers of arguments.  */
Index: bfd/elfxx-target.h
===================================================================
RCS file: /cvs/src/src/bfd/elfxx-target.h,v
retrieving revision 1.60
diff -u -p -r1.60 elfxx-target.h
--- bfd/elfxx-target.h	28 Feb 2004 00:35:45 -0000	1.60
+++ bfd/elfxx-target.h	26 Mar 2004 04:27:24 -0000
@@ -189,6 +189,9 @@
 #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

-- 
Alan Modra
IBM OzLabs - Linux Technology Centre


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]