2001-11-30 H.J. Lu <hjl@gnu.org>

* elflink.h (elf_add_default_symbol): New.
	(elf_link_add_object_symbols): Call elf_add_default_symbol ()
	to create an indirect symbol from the default for the symbol
	with the default version if needed.
This commit is contained in:
H.J. Lu 2001-11-30 15:50:56 +00:00
parent 82e03011ac
commit 215007a648
2 changed files with 261 additions and 214 deletions

View File

@ -1,3 +1,10 @@
2001-11-30 H.J. Lu <hjl@gnu.org>
* elflink.h (elf_add_default_symbol): New.
(elf_link_add_object_symbols): Call elf_add_default_symbol ()
to create an indirect symbol from the default for the symbol
with the default version if needed.
2001-11-29 "Peter.Schauer" <Peter.Schauer@regent.e-technik.tu-muenchen.de>
* elf.c (elfcore_grok_prstatus): Do not overwite the core signal

View File

@ -39,9 +39,14 @@ static boolean elf_link_add_object_symbols
static boolean elf_link_add_archive_symbols
PARAMS ((bfd *, struct bfd_link_info *));
static boolean elf_merge_symbol
PARAMS ((bfd *, struct bfd_link_info *, const char *, Elf_Internal_Sym *,
asection **, bfd_vma *, struct elf_link_hash_entry **,
boolean *, boolean *, boolean *, boolean));
PARAMS ((bfd *, struct bfd_link_info *, const char *,
Elf_Internal_Sym *, asection **, bfd_vma *,
struct elf_link_hash_entry **, boolean *, boolean *,
boolean *, boolean));
static boolean elf_add_default_symbol
PARAMS ((bfd *, struct bfd_link_info *, struct elf_link_hash_entry *,
const char *, Elf_Internal_Sym *, asection **, bfd_vma *,
boolean *, boolean, boolean));
static boolean elf_export_symbol
PARAMS ((struct elf_link_hash_entry *, PTR));
static boolean elf_finalize_dynstr
@ -894,6 +899,243 @@ elf_merge_symbol (abfd, info, name, sym, psec, pvalue, sym_hash,
return true;
}
/* This function is called to create an indirect symbol from the
default for the symbol with the default version if needed. The
symbol is described by H, NAME, SYM, SEC, VALUE, and OVERRIDE. We
set DYNSYM if the new indirect symbol is dynamic. DT_NEEDED
indicates if it comes from a DT_NEEDED entry of a shared object. */
static boolean
elf_add_default_symbol (abfd, info, h, name, sym, sec, value,
dynsym, override, dt_needed)
bfd *abfd;
struct bfd_link_info *info;
struct elf_link_hash_entry *h;
const char *name;
Elf_Internal_Sym *sym;
asection **sec;
bfd_vma *value;
boolean *dynsym;
boolean override;
boolean dt_needed;
{
boolean type_change_ok;
boolean size_change_ok;
char *shortname;
struct elf_link_hash_entry *hi;
struct elf_backend_data *bed;
boolean collect;
boolean dynamic;
char *p;
/* If this symbol has a version, and it is the default version, we
create an indirect symbol from the default name to the fully
decorated name. This will cause external references which do not
specify a version to be bound to this version of the symbol. */
p = strchr (name, ELF_VER_CHR);
if (p == NULL || p[1] != ELF_VER_CHR)
return true;
if (override)
{
/* We are overridden by an old defition. We need to check if we
need to crreate the indirect symbol from the default name. */
hi = elf_link_hash_lookup (elf_hash_table (info), name, true,
false, false);
BFD_ASSERT (hi != NULL);
if (hi == h)
return true;
while (hi->root.type == bfd_link_hash_indirect
|| hi->root.type == bfd_link_hash_warning)
{
hi = (struct elf_link_hash_entry *) hi->root.u.i.link;
if (hi == h)
return true;
}
}
bed = get_elf_backend_data (abfd);
collect = bed->collect;
dynamic = (abfd->flags & DYNAMIC) != 0;
shortname = bfd_hash_allocate (&info->hash->table,
(size_t) (p - name + 1));
if (shortname == NULL)
return false;
strncpy (shortname, name, (size_t) (p - name));
shortname [p - name] = '\0';
/* We are going to create a new symbol. Merge it with any existing
symbol with this name. For the purposes of the merge, act as
though we were defining the symbol we just defined, although we
actually going to define an indirect symbol. */
type_change_ok = false;
size_change_ok = false;
if (! elf_merge_symbol (abfd, info, shortname, sym, sec, value,
&hi, &override, &type_change_ok,
&size_change_ok, dt_needed))
return false;
if (! override)
{
if (! (_bfd_generic_link_add_one_symbol
(info, abfd, shortname, BSF_INDIRECT, bfd_ind_section_ptr,
(bfd_vma) 0, name, false, collect,
(struct bfd_link_hash_entry **) &hi)))
return false;
}
else
{
/* In this case the symbol named SHORTNAME is overriding the
indirect symbol we want to add. We were planning on making
SHORTNAME an indirect symbol referring to NAME. SHORTNAME
is the name without a version. NAME is the fully versioned
name, and it is the default version.
Overriding means that we already saw a definition for the
symbol SHORTNAME in a regular object, and it is overriding
the symbol defined in the dynamic object.
When this happens, we actually want to change NAME, the
symbol we just added, to refer to SHORTNAME. This will cause
references to NAME in the shared object to become references
to SHORTNAME in the regular object. This is what we expect
when we override a function in a shared object: that the
references in the shared object will be mapped to the
definition in the regular object. */
while (hi->root.type == bfd_link_hash_indirect
|| hi->root.type == bfd_link_hash_warning)
hi = (struct elf_link_hash_entry *) hi->root.u.i.link;
h->root.type = bfd_link_hash_indirect;
h->root.u.i.link = (struct bfd_link_hash_entry *) hi;
if (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC)
{
h->elf_link_hash_flags &=~ ELF_LINK_HASH_DEF_DYNAMIC;
hi->elf_link_hash_flags |= ELF_LINK_HASH_REF_DYNAMIC;
if (hi->elf_link_hash_flags
& (ELF_LINK_HASH_REF_REGULAR
| ELF_LINK_HASH_DEF_REGULAR))
{
if (! _bfd_elf_link_record_dynamic_symbol (info, hi))
return false;
}
}
/* Now set HI to H, so that the following code will set the
other fields correctly. */
hi = h;
}
/* 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)
{
struct elf_link_hash_entry *ht;
/* If the symbol became indirect, then we assume that we have
not seen a definition before. */
BFD_ASSERT ((hi->elf_link_hash_flags
& (ELF_LINK_HASH_DEF_DYNAMIC
| ELF_LINK_HASH_DEF_REGULAR)) == 0);
ht = (struct elf_link_hash_entry *) hi->root.u.i.link;
(*bed->elf_backend_copy_indirect_symbol) (ht, hi);
/* See if the new flags lead us to realize that the symbol must
be dynamic. */
if (! *dynsym)
{
if (! dynamic)
{
if (info->shared
|| ((hi->elf_link_hash_flags
& ELF_LINK_HASH_REF_DYNAMIC) != 0))
*dynsym = true;
}
else
{
if ((hi->elf_link_hash_flags
& ELF_LINK_HASH_REF_REGULAR) != 0)
*dynsym = true;
}
}
}
/* We also need to define an indirection from the nondefault version
of the symbol. */
shortname = bfd_hash_allocate (&info->hash->table, strlen (name));
if (shortname == NULL)
return false;
strncpy (shortname, name, (size_t) (p - name));
strcpy (shortname + (p - name), p + 1);
/* Once again, merge with any existing symbol. */
type_change_ok = false;
size_change_ok = false;
if (! elf_merge_symbol (abfd, info, shortname, sym, sec, value,
&hi, &override, &type_change_ok,
&size_change_ok, dt_needed))
return false;
if (override)
{
/* Here SHORTNAME is a versioned name, so we don't expect to see
the type of override we do in the case above. */
(*_bfd_error_handler)
(_("%s: warning: unexpected redefinition of `%s'"),
bfd_archive_filename (abfd), shortname);
}
else
{
if (! (_bfd_generic_link_add_one_symbol
(info, abfd, shortname, BSF_INDIRECT,
bfd_ind_section_ptr, (bfd_vma) 0, name, false,
collect, (struct bfd_link_hash_entry **) &hi)))
return false;
/* 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 the symbol became indirect, then we assume that we have
not seen a definition before. */
BFD_ASSERT ((hi->elf_link_hash_flags
& (ELF_LINK_HASH_DEF_DYNAMIC
| ELF_LINK_HASH_DEF_REGULAR)) == 0);
(*bed->elf_backend_copy_indirect_symbol) (h, hi);
/* See if the new flags lead us to realize that the symbol
must be dynamic. */
if (! *dynsym)
{
if (! dynamic)
{
if (info->shared
|| ((hi->elf_link_hash_flags
& ELF_LINK_HASH_REF_DYNAMIC) != 0))
*dynsym = true;
}
else
{
if ((hi->elf_link_hash_flags
& ELF_LINK_HASH_REF_REGULAR) != 0)
*dynsym = true;
}
}
}
}
return true;
}
/* Add symbols from an ELF object file to the linker hash table. */
static boolean
@ -1373,6 +1615,9 @@ elf_link_add_object_symbols (abfd, info)
boolean size_change_ok, type_change_ok;
boolean new_weakdef;
unsigned int old_alignment;
boolean override;
override = false;
elf_swap_symbol_in (abfd, esym, &sym);
@ -1463,7 +1708,6 @@ elf_link_add_object_symbols (abfd, info)
{
Elf_Internal_Versym iver;
unsigned int vernum = 0;
boolean override;
if (ever != NULL)
{
@ -1735,217 +1979,13 @@ elf_link_add_object_symbols (abfd, info)
h->elf_link_hash_flags |= new_flag;
/* If this symbol has a version, and it is the default
version, we create an indirect symbol from the default
name to the fully decorated name. This will cause
external references which do not specify a version to be
bound to this version of the symbol. */
/* Check to see if we need to add an indirect symbol for
the default name. */
if (definition || h->root.type == bfd_link_hash_common)
{
char *p;
p = strchr (name, ELF_VER_CHR);
if (p != NULL && p[1] == ELF_VER_CHR)
{
char *shortname;
struct elf_link_hash_entry *hi;
boolean override;
shortname = bfd_hash_allocate (&info->hash->table,
(size_t) (p - name + 1));
if (shortname == NULL)
goto error_return;
strncpy (shortname, name, (size_t) (p - name));
shortname[p - name] = '\0';
/* We are going to create a new symbol. Merge it
with any existing symbol with this name. For the
purposes of the merge, act as though we were
defining the symbol we just defined, although we
actually going to define an indirect symbol. */
type_change_ok = false;
size_change_ok = false;
if (! elf_merge_symbol (abfd, info, shortname, &sym, &sec,
&value, &hi, &override,
&type_change_ok,
&size_change_ok, dt_needed))
goto error_return;
if (! override)
{
if (! (_bfd_generic_link_add_one_symbol
(info, abfd, shortname, BSF_INDIRECT,
bfd_ind_section_ptr, (bfd_vma) 0, name, false,
collect, (struct bfd_link_hash_entry **) &hi)))
goto error_return;
}
else
{
/* In this case the symbol named SHORTNAME is
overriding the indirect symbol we want to
add. We were planning on making SHORTNAME an
indirect symbol referring to NAME. SHORTNAME
is the name without a version. NAME is the
fully versioned name, and it is the default
version.
Overriding means that we already saw a
definition for the symbol SHORTNAME in a
regular object, and it is overriding the
symbol defined in the dynamic object.
When this happens, we actually want to change
NAME, the symbol we just added, to refer to
SHORTNAME. This will cause references to
NAME in the shared object to become
references to SHORTNAME in the regular
object. This is what we expect when we
override a function in a shared object: that
the references in the shared object will be
mapped to the definition in the regular
object. */
while (hi->root.type == bfd_link_hash_indirect
|| hi->root.type == bfd_link_hash_warning)
hi = (struct elf_link_hash_entry *) hi->root.u.i.link;
h->root.type = bfd_link_hash_indirect;
h->root.u.i.link = (struct bfd_link_hash_entry *) hi;
if (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC)
{
h->elf_link_hash_flags &=~ ELF_LINK_HASH_DEF_DYNAMIC;
hi->elf_link_hash_flags |= ELF_LINK_HASH_REF_DYNAMIC;
if (hi->elf_link_hash_flags
& (ELF_LINK_HASH_REF_REGULAR
| ELF_LINK_HASH_DEF_REGULAR))
{
if (! _bfd_elf_link_record_dynamic_symbol (info,
hi))
goto error_return;
}
}
/* Now set HI to H, so that the following code
will set the other fields correctly. */
hi = h;
}
/* 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)
{
struct elf_link_hash_entry *ht;
/* If the symbol became indirect, then we assume
that we have not seen a definition before. */
BFD_ASSERT ((hi->elf_link_hash_flags
& (ELF_LINK_HASH_DEF_DYNAMIC
| ELF_LINK_HASH_DEF_REGULAR))
== 0);
ht = (struct elf_link_hash_entry *) hi->root.u.i.link;
(*bed->elf_backend_copy_indirect_symbol) (ht, hi);
/* See if the new flags lead us to realize that
the symbol must be dynamic. */
if (! dynsym)
{
if (! dynamic)
{
if (info->shared
|| ((hi->elf_link_hash_flags
& ELF_LINK_HASH_REF_DYNAMIC)
!= 0))
dynsym = true;
}
else
{
if ((hi->elf_link_hash_flags
& ELF_LINK_HASH_REF_REGULAR) != 0)
dynsym = true;
}
}
}
/* We also need to define an indirection from the
nondefault version of the symbol. */
shortname = bfd_hash_allocate (&info->hash->table,
strlen (name));
if (shortname == NULL)
goto error_return;
strncpy (shortname, name, (size_t) (p - name));
strcpy (shortname + (p - name), p + 1);
/* Once again, merge with any existing symbol. */
type_change_ok = false;
size_change_ok = false;
if (! elf_merge_symbol (abfd, info, shortname, &sym, &sec,
&value, &hi, &override,
&type_change_ok,
&size_change_ok, dt_needed))
goto error_return;
if (override)
{
/* Here SHORTNAME is a versioned name, so we
don't expect to see the type of override we
do in the case above. */
(*_bfd_error_handler)
(_("%s: warning: unexpected redefinition of `%s'"),
bfd_archive_filename (abfd), shortname);
}
else
{
if (! (_bfd_generic_link_add_one_symbol
(info, abfd, shortname, BSF_INDIRECT,
bfd_ind_section_ptr, (bfd_vma) 0, name, false,
collect, (struct bfd_link_hash_entry **) &hi)))
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 the symbol became indirect, then we
assume that we have not seen a definition
before. */
BFD_ASSERT ((hi->elf_link_hash_flags
& (ELF_LINK_HASH_DEF_DYNAMIC
| ELF_LINK_HASH_DEF_REGULAR))
== 0);
(*bed->elf_backend_copy_indirect_symbol) (h, hi);
/* See if the new flags lead us to realize
that the symbol must be dynamic. */
if (! dynsym)
{
if (! dynamic)
{
if (info->shared
|| ((hi->elf_link_hash_flags
& ELF_LINK_HASH_REF_DYNAMIC)
!= 0))
dynsym = true;
}
else
{
if ((hi->elf_link_hash_flags
& ELF_LINK_HASH_REF_REGULAR) != 0)
dynsym = true;
}
}
}
}
}
}
if (! elf_add_default_symbol (abfd, info, h, name, &sym,
&sec, &value, &dynsym,
override, dt_needed))
goto error_return;
if (dynsym && h->dynindx == -1)
{