Fix elf linker's handling of commons in archive maps
diff --git a/bfd/ChangeLog b/bfd/ChangeLog
index e351bfb..fe91368 100644
--- a/bfd/ChangeLog
+++ b/bfd/ChangeLog
@@ -1,5 +1,16 @@
 1999-12-10  Nick Clifton  <nickc@cygnus.com>
 
+	* elflink.h (elf_link_is_defined_archive_symbol): New
+	function: Decide if a symbol, in an archive map is there
+	because it is defined in the archive element, or because it is
+	just another common declaration of it.
+	(elf_link_add_archive_symbols): Use
+	elf_link_is_defined_archive_symbol to decide if an archive
+	element contain a reference to a common symbol should be
+	linked in or not.
+
+1999-12-10  Nick Clifton  <nickc@cygnus.com>
+
 	* elflink.h: Revert previous patch.
 	* targets.c: Revert previous patch.
 	* libbfd-in2.h: Revert previous patch.
diff --git a/bfd/elflink.h b/bfd/elflink.h
index ab679a7..6e21a1f 100644
--- a/bfd/elflink.h
+++ b/bfd/elflink.h
@@ -80,6 +80,97 @@
     }
 }
 
+/* Search the symbol table of the archive element of the archive ABFD
+   whoes archove map contains a mention of SYMDEF, and determine if
+   the symbol is defined in this element.  */
+static boolean
+elf_link_is_defined_archive_symbol (abfd, symdef)
+     bfd * abfd;
+     carsym * symdef;
+{
+  Elf_Internal_Shdr * hdr;
+  Elf_External_Sym *  esym;
+  Elf_External_Sym *  esymend;
+  Elf_External_Sym *  buf = NULL;
+  size_t symcount;
+  size_t extsymcount;
+  size_t extsymoff;
+  boolean result = false;
+  
+  abfd = _bfd_get_elt_at_filepos (abfd, symdef->file_offset);
+  if (abfd == (bfd *) NULL)
+    return false;
+
+  if (! bfd_check_format (abfd, bfd_object))
+    return false;
+
+  /* Select the appropriate symbol table.  */
+  if ((abfd->flags & DYNAMIC) == 0 || 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.  */
+  if (elf_bad_symtab (abfd))
+    {
+      extsymcount = symcount;
+      extsymoff = 0;
+    }
+  else
+    {
+      extsymcount = symcount - hdr->sh_info;
+      extsymoff = hdr->sh_info;
+    }
+
+  buf = ((Elf_External_Sym *)
+	 bfd_malloc (extsymcount * sizeof (Elf_External_Sym)));
+  if (buf == NULL && extsymcount != 0)
+    return false;
+
+  /* Read in the symbol table.
+     FIXME:  This ought to be cached somewhere.  */
+  if (bfd_seek (abfd,
+		hdr->sh_offset + extsymoff * sizeof (Elf_External_Sym),
+		SEEK_SET) != 0
+      || (bfd_read ((PTR) buf, sizeof (Elf_External_Sym), extsymcount, abfd)
+	  != extsymcount * sizeof (Elf_External_Sym)))
+    {
+      free (buf);
+      return false;
+    }
+
+  /* Scan the symbol table looking for SYMDEF.  */
+  esymend = buf + extsymcount;
+  for (esym = buf;
+       esym < esymend;
+       esym++)
+    {
+      Elf_Internal_Sym sym;
+      const char * name;
+
+      elf_swap_symbol_in (abfd, esym, & sym);
+
+      name = bfd_elf_string_from_elf_section (abfd, hdr->sh_link, sym.st_name);
+      if (name == (const char *) NULL)
+	break;
+
+      if (strcmp (name, symdef->name) == 0)
+	{
+	  result =
+	    (ELF_ST_BIND (sym.st_info) == STB_GLOBAL)
+	    && (sym.st_shndx != SHN_UNDEF);
+	  break;
+	}
+    }
+
+  free (buf);
+  
+  return result;
+}
+
 
 /* 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
@@ -200,7 +291,24 @@
 	  if (h == NULL)
 	    continue;
 
-	  if (h->root.type != bfd_link_hash_undefined)
+	  if (h->root.type == bfd_link_hash_common)
+	    {
+	      /* We currently have a common symbol.  The archive map contains
+		 a reference to this symbol, so we may want to include it.  We
+		 only want to include it however, if this archive element
+		 contains a definition of the symbol, not just another common
+		 declaration of it.
+
+		 Unfortunately some archivers (including GNU ar) will put
+		 declarations of common symbols into their archive maps, as
+		 well as real definitions, so we cannot just go by the archive
+		 map alone.  Instead we must read in the element's symbol
+		 table and check that to see what kind of symbol definition
+		 this is.  */
+	      if (! elf_link_is_defined_archive_symbol (abfd, symdef))
+		continue;
+	    }
+	  else if (h->root.type != bfd_link_hash_undefined)
 	    {
 	      if (h->root.type != bfd_link_hash_undefweak)
 		defined[i] = true;