mirror of
https://github.com/espressif/binutils-gdb.git
synced 2025-06-27 22:48:57 +08:00
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:
205
bfd/elflink.h
205
bfd/elflink.h
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user