From Eric Youngdale <eric@andante.jic.com>:

* elf-bfd.h (ELF_LINK_FORCED_LOCAL): Define.
	* elf.c (bfd_elf_print_symbol): Correct errors in last change.
	* elflink.h (elf_link_add_object_symbols): Handle cases in which a
	versioned symbol appears in both a regular and a shared object.
	(elf_link_assign_sym_version): Set ELF_LINK_FORCED_LOCAL when
	appropriate.  Improve error message.
	(struct elf_outext_info): Rename from elf_finfo_failed.  Change
	all uses.  Add localsyms field.
	(elf_bfd_final_link): When generating a shared library, call
	elf_link_output_extsym to output all local symbols.
	(elf_link_output_extsym): Handle symbols which were forced to
	become local.
This commit is contained in:
Ian Lance Taylor
1997-03-11 06:46:46 +00:00
parent 6d8dfa04d4
commit 52c92c7f75

View File

@ -1058,7 +1058,7 @@ elf_link_add_object_symbols (abfd, info)
if (p != NULL && p[1] == ELF_VER_CHR) if (p != NULL && p[1] == ELF_VER_CHR)
{ {
char *shortname; char *shortname;
struct elf_link_hash_entry *hi; struct elf_link_hash_entry *hold;
shortname = bfd_hash_allocate (&info->hash->table, shortname = bfd_hash_allocate (&info->hash->table,
p - name + 1); p - name + 1);
@ -1067,6 +1067,52 @@ elf_link_add_object_symbols (abfd, info)
strncpy (shortname, name, p - name); strncpy (shortname, name, p - name);
shortname[p - name] = '\0'; shortname[p - name] = '\0';
/* First look to see if we have an existing symbol
with this name. */
hold = elf_link_hash_lookup (elf_hash_table (info),
shortname, false, false,
false);
/* If we are looking at a normal object, and the
symbol was seen in a shared object, clobber the
definition in the shared object. */
if (hold != NULL
&& ! dynamic
&& (hold->root.type == bfd_link_hash_defined
|| hold->root.type == bfd_link_hash_defweak)
&& (hold->elf_link_hash_flags
& ELF_LINK_HASH_DEF_DYNAMIC) != 0
&& ((hold->root.u.def.section->owner->flags & DYNAMIC)
!= 0))
{
/* Change the hash table entry to undefined, so
that _bfd_generic_link_add_one_symbol will do
the right thing. */
hold->root.type = bfd_link_hash_undefined;
hold->root.u.undef.abfd =
hold->root.u.def.section->owner;
hold->verinfo.vertree = NULL;
hold = NULL;
}
/* If we are looking at a shared object, and we have
already seen this symbol defined elsewhere, then
don't try to define it again. */
if (hold != NULL
&& dynamic
&& (hold->root.type == bfd_link_hash_defined
|| hold->root.type == bfd_link_hash_defweak
|| hold->root.type == bfd_link_hash_indirect
|| (hold->root.type == bfd_link_hash_common
&& (bind == STB_WEAK
|| ELF_ST_TYPE (sym.st_info) == STT_FUNC))))
{
/* Don't add an indirect symbol. */
}
else
{
struct elf_link_hash_entry *hi;
hi = NULL; hi = NULL;
if (! (_bfd_generic_link_add_one_symbol if (! (_bfd_generic_link_add_one_symbol
(info, abfd, shortname, BSF_INDIRECT, (info, abfd, shortname, BSF_INDIRECT,
@ -1074,17 +1120,24 @@ elf_link_add_object_symbols (abfd, info)
collect, (struct bfd_link_hash_entry **) &hi))) collect, (struct bfd_link_hash_entry **) &hi)))
goto error_return; goto error_return;
/* If there is a duplicate definition somewhere,
then HI may not point to an indirect symbol.
We will have reported an error to the user in
that case. */
if (hi->root.type == bfd_link_hash_indirect) if (hi->root.type == bfd_link_hash_indirect)
{ {
hi->elf_link_hash_flags &= ~ ELF_LINK_NON_ELF; hi->elf_link_hash_flags &= ~ ELF_LINK_NON_ELF;
if (dynamic) if (dynamic)
hi->elf_link_hash_flags |= ELF_LINK_HASH_DEF_DYNAMIC; hi->elf_link_hash_flags |=
/* We don't set DEF_REGULAR because we don't the ELF_LINK_HASH_DEF_DYNAMIC;
symbol to get exported even if we are /* We don't set DEF_REGULAR because we don't
exporting all defined symbols. FIXME: What a the symbol to get exported even if we are
hack. */ exporting all defined symbols. FIXME:
/* FIXME: Do we need to copy any flags from H to What a hack. */
HI? */ /* FIXME: Do we need to copy any flags from
H to HI? */
}
} }
/* We also need to define an indirection from the /* We also need to define an indirection from the
@ -1097,6 +1150,52 @@ elf_link_add_object_symbols (abfd, info)
strncpy (shortname, name, p - name); strncpy (shortname, name, p - name);
strcpy (shortname + (p - name), p + 1); strcpy (shortname + (p - name), p + 1);
/* First look to see if we have an existing symbol
with this name. */
hold = elf_link_hash_lookup (elf_hash_table (info),
shortname, false, false,
false);
/* If we are looking at a normal object, and the
symbol was seen in a shared object, clobber the
definition in the shared object. */
if (hold != NULL
&& ! dynamic
&& (hold->root.type == bfd_link_hash_defined
|| hold->root.type == bfd_link_hash_defweak)
&& (hold->elf_link_hash_flags
& ELF_LINK_HASH_DEF_DYNAMIC) != 0
&& ((hold->root.u.def.section->owner->flags & DYNAMIC)
!= 0))
{
/* Change the hash table entry to undefined, so
that _bfd_generic_link_add_one_symbol will do
the right thing. */
hold->root.type = bfd_link_hash_undefined;
hold->root.u.undef.abfd =
hold->root.u.def.section->owner;
hold->verinfo.vertree = NULL;
hold = NULL;
}
/* If we are looking at a shared object, and we have
already seen this symbol defined elsewhere, then
don't try to define it again. */
if (hold != NULL
&& dynamic
&& (hold->root.type == bfd_link_hash_defined
|| hold->root.type == bfd_link_hash_defweak
|| hold->root.type == bfd_link_hash_indirect
|| (hold->root.type == bfd_link_hash_common
&& (bind == STB_WEAK
|| ELF_ST_TYPE (sym.st_info) == STT_FUNC))))
{
/* Don't add an indirect symbol. */
}
else
{
struct elf_link_hash_entry *hi;
hi = NULL; hi = NULL;
if (! (_bfd_generic_link_add_one_symbol if (! (_bfd_generic_link_add_one_symbol
(info, abfd, shortname, BSF_INDIRECT, (info, abfd, shortname, BSF_INDIRECT,
@ -1104,11 +1203,24 @@ elf_link_add_object_symbols (abfd, info)
collect, (struct bfd_link_hash_entry **) &hi))) collect, (struct bfd_link_hash_entry **) &hi)))
goto error_return; goto error_return;
/* If there is a duplicate definition somewhere,
then HI may not point to an indirect symbol.
We will have reported an error to the user in
that case. */
if (hi->root.type == bfd_link_hash_indirect) if (hi->root.type == bfd_link_hash_indirect)
{ {
hi->elf_link_hash_flags &= ~ ELF_LINK_NON_ELF; hi->elf_link_hash_flags &= ~ ELF_LINK_NON_ELF;
if (dynamic) if (dynamic)
hi->elf_link_hash_flags |= ELF_LINK_HASH_DEF_DYNAMIC; hi->elf_link_hash_flags |=
ELF_LINK_HASH_DEF_DYNAMIC;
/* We don't set DEF_REGULAR because we don't
the symbol to get exported even if we are
exporting all defined symbols. FIXME:
What a hack. */
/* FIXME: Do we need to copy any flags from
H to HI? */
}
} }
} }
} }
@ -2602,6 +2714,7 @@ elf_link_assign_sym_version (h, data)
& ELF_LINK_HASH_NEEDS_PLT) == 0) & ELF_LINK_HASH_NEEDS_PLT) == 0)
{ {
sinfo->removed_dynamic = true; sinfo->removed_dynamic = true;
h->elf_link_hash_flags |= ELF_LINK_FORCED_LOCAL;
h->dynindx = -1; h->dynindx = -1;
/* FIXME: The name of the symbol has /* FIXME: The name of the symbol has
already been recorded in the dynamic already been recorded in the dynamic
@ -2661,8 +2774,8 @@ elf_link_assign_sym_version (h, data)
/* We could not find the version for a symbol when /* We could not find the version for a symbol when
generating a shared archive. Return an error. */ generating a shared archive. Return an error. */
(*_bfd_error_handler) (*_bfd_error_handler)
("%s: invalid version %s", bfd_get_filename (sinfo->output_bfd), ("%s: undefined version name %s",
h->root.root.string); bfd_get_filename (sinfo->output_bfd), h->root.root.string);
bfd_set_error (bfd_error_bad_value); bfd_set_error (bfd_error_bad_value);
sinfo->failed = true; sinfo->failed = true;
return false; return false;
@ -2717,6 +2830,7 @@ elf_link_assign_sym_version (h, data)
& ELF_LINK_HASH_NEEDS_PLT) == 0) & ELF_LINK_HASH_NEEDS_PLT) == 0)
{ {
sinfo->removed_dynamic = true; sinfo->removed_dynamic = true;
h->elf_link_hash_flags |= ELF_LINK_FORCED_LOCAL;
h->dynindx = -1; h->dynindx = -1;
/* FIXME: The name of the symbol has already /* FIXME: The name of the symbol has already
been recorded in the dynamic string table been recorded in the dynamic string table
@ -2740,6 +2854,7 @@ elf_link_assign_sym_version (h, data)
&& (h->elf_link_hash_flags & ELF_LINK_HASH_NEEDS_PLT) == 0) && (h->elf_link_hash_flags & ELF_LINK_HASH_NEEDS_PLT) == 0)
{ {
sinfo->removed_dynamic = true; sinfo->removed_dynamic = true;
h->elf_link_hash_flags |= ELF_LINK_FORCED_LOCAL;
h->dynindx = -1; h->dynindx = -1;
/* FIXME: The name of the symbol has already been /* FIXME: The name of the symbol has already been
recorded in the dynamic string table section. */ recorded in the dynamic string table section. */
@ -2827,12 +2942,12 @@ static boolean elf_reloc_link_order
PARAMS ((bfd *, struct bfd_link_info *, asection *, PARAMS ((bfd *, struct bfd_link_info *, asection *,
struct bfd_link_order *)); struct bfd_link_order *));
/* This struct is used to pass information to routines called via /* This struct is used to pass information to elf_link_output_extsym. */
elf_link_hash_traverse which must return failure. */
struct elf_finfo_failed struct elf_outext_info
{ {
boolean failed; boolean failed;
boolean localsyms;
struct elf_final_link_info *finfo; struct elf_final_link_info *finfo;
}; };
@ -2859,7 +2974,7 @@ elf_bfd_final_link (abfd, info)
Elf_Internal_Shdr *symtab_hdr; Elf_Internal_Shdr *symtab_hdr;
Elf_Internal_Shdr *symstrtab_hdr; Elf_Internal_Shdr *symstrtab_hdr;
struct elf_backend_data *bed = get_elf_backend_data (abfd); struct elf_backend_data *bed = get_elf_backend_data (abfd);
struct elf_finfo_failed eif; struct elf_outext_info eoinfo;
if (info->shared) if (info->shared)
abfd->flags |= DYNAMIC; abfd->flags |= DYNAMIC;
@ -3196,6 +3311,23 @@ elf_bfd_final_link (abfd, info)
/* That wrote out all the local symbols. Finish up the symbol table /* That wrote out all the local symbols. Finish up the symbol table
with the global symbols. */ with the global symbols. */
if (info->strip != strip_all && info->shared)
{
/* Output any global symbols that got converted to local in a
version script. We do this in a separate step since ELF
requires all local symbols to appear prior to any global
symbols. FIXME: We should only do this if some global
symbols were, in fact, converted to become local. FIXME:
Will this work correctly with the Irix 5 linker? */
eoinfo.failed = false;
eoinfo.finfo = &finfo;
eoinfo.localsyms = true;
elf_link_hash_traverse (elf_hash_table (info), elf_link_output_extsym,
(PTR) &eoinfo);
if (eoinfo.failed)
return false;
}
/* The sh_info field records the index of the first non local /* The sh_info field records the index of the first non local
symbol. */ symbol. */
symtab_hdr->sh_info = abfd->symcount; symtab_hdr->sh_info = abfd->symcount;
@ -3203,11 +3335,12 @@ elf_bfd_final_link (abfd, info)
elf_section_data (finfo.dynsym_sec->output_section)->this_hdr.sh_info = 1; elf_section_data (finfo.dynsym_sec->output_section)->this_hdr.sh_info = 1;
/* We get the global symbols from the hash table. */ /* We get the global symbols from the hash table. */
eif.failed = false; eoinfo.failed = false;
eif.finfo = &finfo; eoinfo.localsyms = false;
eoinfo.finfo = &finfo;
elf_link_hash_traverse (elf_hash_table (info), elf_link_output_extsym, elf_link_hash_traverse (elf_hash_table (info), elf_link_output_extsym,
(PTR) &eif); (PTR) &eoinfo);
if (eif.failed) if (eoinfo.failed)
return false; return false;
/* Flush all symbols to the file. */ /* Flush all symbols to the file. */
@ -3592,19 +3725,35 @@ elf_link_flush_output_syms (finfo)
} }
/* Add an external symbol to the symbol table. This is called from /* Add an external symbol to the symbol table. This is called from
the hash table traversal routine. */ the hash table traversal routine. When generating a shared object,
we go through the symbol table twice. The first time we output
anything that might have been forced to local scope in a version
script. The second time we output the symbols that are still
global symbols. */
static boolean static boolean
elf_link_output_extsym (h, data) elf_link_output_extsym (h, data)
struct elf_link_hash_entry *h; struct elf_link_hash_entry *h;
PTR data; PTR data;
{ {
struct elf_finfo_failed *eif = (struct elf_finfo_failed *) data; struct elf_outext_info *eoinfo = (struct elf_outext_info *) data;
struct elf_final_link_info *finfo = eif->finfo; struct elf_final_link_info *finfo = eoinfo->finfo;
boolean strip; boolean strip;
Elf_Internal_Sym sym; Elf_Internal_Sym sym;
asection *input_sec; asection *input_sec;
/* Decide whether to output this symbol in this pass. */
if (eoinfo->localsyms)
{
if ((h->elf_link_hash_flags & ELF_LINK_FORCED_LOCAL) == 0)
return true;
}
else
{
if ((h->elf_link_hash_flags & ELF_LINK_FORCED_LOCAL) != 0)
return true;
}
/* If we are not creating a shared library, and this symbol is /* If we are not creating a shared library, and this symbol is
referenced by a shared library but is not defined anywhere, then referenced by a shared library but is not defined anywhere, then
warn that it is undefined. If we do not do this, the runtime warn that it is undefined. If we do not do this, the runtime
@ -3622,7 +3771,7 @@ elf_link_output_extsym (h, data)
(finfo->info, h->root.root.string, h->root.u.undef.abfd, (finfo->info, h->root.root.string, h->root.u.undef.abfd,
(asection *) NULL, 0))) (asection *) NULL, 0)))
{ {
eif->failed = true; eoinfo->failed = true;
return false; return false;
} }
} }
@ -3655,7 +3804,9 @@ elf_link_output_extsym (h, data)
sym.st_value = 0; sym.st_value = 0;
sym.st_size = h->size; sym.st_size = h->size;
sym.st_other = h->other; sym.st_other = h->other;
if (h->root.type == bfd_link_hash_undefweak if ((h->elf_link_hash_flags & ELF_LINK_FORCED_LOCAL) != 0)
sym.st_info = ELF_ST_INFO (STB_LOCAL, h->type);
else if (h->root.type == bfd_link_hash_undefweak
|| h->root.type == bfd_link_hash_defweak) || h->root.type == bfd_link_hash_defweak)
sym.st_info = ELF_ST_INFO (STB_WEAK, h->type); sym.st_info = ELF_ST_INFO (STB_WEAK, h->type);
else else
@ -3689,7 +3840,7 @@ elf_link_output_extsym (h, data)
input_sec->output_section); input_sec->output_section);
if (sym.st_shndx == (unsigned short) -1) if (sym.st_shndx == (unsigned short) -1)
{ {
eif->failed = true; eoinfo->failed = true;
return false; return false;
} }
@ -3761,7 +3912,7 @@ elf_link_output_extsym (h, data)
if (! ((*bed->elf_backend_finish_dynamic_symbol) if (! ((*bed->elf_backend_finish_dynamic_symbol)
(finfo->output_bfd, finfo->info, h, &sym))) (finfo->output_bfd, finfo->info, h, &sym)))
{ {
eif->failed = true; eoinfo->failed = true;
return false; return false;
} }
@ -3835,7 +3986,7 @@ elf_link_output_extsym (h, data)
if (! elf_link_output_sym (finfo, h->root.root.string, &sym, input_sec)) if (! elf_link_output_sym (finfo, h->root.root.string, &sym, input_sec))
{ {
eif->failed = true; eoinfo->failed = true;
return false; return false;
} }