}
}
\f
+/* Return true iff this is a non-common definition of a symbol. */
+static boolean
+is_global_symbol_definition (abfd, sym)
+ bfd * abfd;
+ Elf_Internal_Sym * sym;
+{
+ /* Local symbols do not count, but target specific ones might. */
+ if (ELF_ST_BIND (sym->st_info) != STB_GLOBAL
+ && ELF_ST_BIND (sym->st_info) < STB_LOOS)
+ return false;
+
+ /* If the section is undefined, then so is the symbol. */
+ if (sym->st_shndx == SHN_UNDEF)
+ return false;
+
+ /* If the symbol is defined in the common section, then
+ it is a common definition and so does not count. */
+ if (sym->st_shndx == SHN_COMMON)
+ return false;
+
+ /* If the symbol is in a target specific section then we
+ must rely upon the backend to tell us what it is. */
+ if (sym->st_shndx >= SHN_LORESERVE && sym->st_shndx < SHN_ABS)
+ /* FIXME - this function is not coded yet:
+
+ return _bfd_is_global_symbol_definition (abfd, sym);
+
+ Instead for now assume that the definition is not global,
+ Even if this is wrong, at least the linker will behave
+ in the same way that it used to do. */
+ return false;
+
+ return true;
+}
+
+
+/* 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;
+
+ /* If we have already included the element containing this symbol in the
+ link then we do not need to include it again. Just claim that any symbol
+ it contains is not a definition, so that our caller will not decide to
+ (re)include this element. */
+ if (abfd->archive_pass)
+ 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 = is_global_symbol_definition (abfd, & sym);
+ break;
+ }
+ }
+
+ free (buf);
+
+ return result;
+}
+\f
/* 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
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;
h->type = ELF_ST_TYPE (sym.st_info);
}
- if (sym.st_other != 0
- && (definition || h->other == 0))
- h->other = sym.st_other;
+ /* If st_other has a processor-specific meaning, specific code
+ might be needed here. */
+ if (sym.st_other != 0)
+ {
+ /* Combine visibilities, using the most constraining one. */
+ unsigned char hvis = ELF_ST_VISIBILITY (h->other);
+ unsigned char symvis = ELF_ST_VISIBILITY (sym.st_other);
+
+ if (symvis && (hvis > symvis || hvis == 0))
+ h->other = sym.st_other;
+
+ /* If neither has visibility, use the st_other of the
+ definition. This is an arbitrary choice, since the
+ other bits have no general meaning. */
+ if (!symvis && !hvis
+ && (definition || h->other == 0))
+ h->other = sym.st_other;
+ }
/* Set a flag in the hash table entry indicating the type of
reference or definition we just found. Keep a count of
if (dynobj == NULL)
return true;
- /* If we are supposed to export all symbols into the dynamic symbol
- table (this is not the normal case), then do so. */
- if (export_dynamic)
- {
- struct elf_info_failed eif;
-
- eif.failed = false;
- eif.info = info;
- elf_link_hash_traverse (elf_hash_table (info), elf_export_symbol,
- (PTR) &eif);
- if (eif.failed)
- return false;
- }
-
if (elf_hash_table (info)->dynamic_sections_created)
{
struct elf_info_failed eif;
}
}
+ /* If we are supposed to export all symbols into the dynamic symbol
+ table (this is not the normal case), then do so. */
+ if (export_dynamic)
+ {
+ struct elf_info_failed eif;
+
+ eif.failed = false;
+ eif.info = info;
+ elf_link_hash_traverse (elf_hash_table (info), elf_export_symbol,
+ (PTR) &eif);
+ if (eif.failed)
+ return false;
+ }
+
/* Attach all the symbols to their version information. */
asvinfo.output_bfd = output_bfd;
asvinfo.info = info;
Elf_Internal_Sym sym;
Elf_External_Sym *dynsym =
(Elf_External_Sym *)finfo.dynsym_sec->contents;
- unsigned long last_local = 0;
+ long last_local = 0;
/* Write out the section symbols for the output sections. */
if (info->shared)
}
}
- elf_section_data (finfo.dynsym_sec->output_section)
- ->this_hdr.sh_info = last_local + 1;
+ elf_section_data (finfo.dynsym_sec->output_section)->this_hdr.sh_info =
+ last_local + 1;
}
/* We get the global symbols from the hash table. */