Fix elf linker's handling of commons in archive maps

This commit is contained in:
Nick Clifton 1999-12-10 20:17:28 +00:00
parent 77fb9c28ac
commit a3a8c91d41
2 changed files with 120 additions and 1 deletions

View File

@ -1,3 +1,14 @@
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.

View File

@ -80,6 +80,97 @@ elf_bfd_link_add_symbols (abfd, info)
}
}
/* 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 @@ elf_link_add_archive_symbols (abfd, info)
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;