Replace hidden with versioned in elf_link_hash_entry
This patch replaces the "hidden" field with the "versioned" field in elf_link_hash_entry so that we can avoid calling strchr and strrchr if the symbol is unversioned. * elf-bfd.h (elf_symbol_version): New enum. (elf_link_hash_entry): Replace hidden with versioned. * elflink.c (_bfd_elf_merge_symbol): Don't look for symbol version if the symbol is unversioned. Initialize versioned. (_bfd_elf_add_default_symbol): Don't look for symbol version if the symbol is unversioned or hidden. Initialize versioned. (elf_collect_hash_codes): Don't look for symbol version if the symbol is unversioned. (elf_collect_gnu_hash_codes): Likewise. (bfd_elf_gc_mark_dynamic_ref_symbol): Likewise. (_bfd_elf_link_hash_copy_indirect): Check versioned instead of hidden. (elf_link_output_extsym): Likewise.
This commit is contained in:
parent
75fb7498c2
commit
422f11824b
|
@ -1,3 +1,19 @@
|
||||||
|
2015-08-10 H.J. Lu <hongjiu.lu@intel.com>
|
||||||
|
|
||||||
|
* elf-bfd.h (elf_symbol_version): New enum.
|
||||||
|
(elf_link_hash_entry): Replace hidden with versioned.
|
||||||
|
* elflink.c (_bfd_elf_merge_symbol): Don't look for symbol
|
||||||
|
version if the symbol is unversioned. Initialize versioned.
|
||||||
|
(_bfd_elf_add_default_symbol): Don't look for symbol version
|
||||||
|
if the symbol is unversioned or hidden. Initialize versioned.
|
||||||
|
(elf_collect_hash_codes): Don't look for symbol version if the
|
||||||
|
symbol is unversioned.
|
||||||
|
(elf_collect_gnu_hash_codes): Likewise.
|
||||||
|
(bfd_elf_gc_mark_dynamic_ref_symbol): Likewise.
|
||||||
|
(_bfd_elf_link_hash_copy_indirect): Check versioned instead of
|
||||||
|
hidden.
|
||||||
|
(elf_link_output_extsym): Likewise.
|
||||||
|
|
||||||
2015-08-07 H.J. Lu <hongjiu.lu@intel.com>
|
2015-08-07 H.J. Lu <hongjiu.lu@intel.com>
|
||||||
|
|
||||||
PR binutils/18785
|
PR binutils/18785
|
||||||
|
@ -27,7 +43,7 @@
|
||||||
(elf_link_output_extsym): Bind a symbol locally when linking
|
(elf_link_output_extsym): Bind a symbol locally when linking
|
||||||
executable if it is locally defined, hidden versioned, not
|
executable if it is locally defined, hidden versioned, not
|
||||||
referenced by shared library and not exported. Turn on
|
referenced by shared library and not exported. Turn on
|
||||||
VERSYM_HIDDEN only if the hidden vesioned symbol is defined
|
VERSYM_HIDDEN only if the hidden versioned symbol is defined
|
||||||
locally.
|
locally.
|
||||||
|
|
||||||
2015-08-05 Nick Clifton <nickc@redhat.com>
|
2015-08-05 Nick Clifton <nickc@redhat.com>
|
||||||
|
|
|
@ -108,6 +108,15 @@ struct elf_link_virtual_table_entry
|
||||||
struct elf_link_hash_entry *parent;
|
struct elf_link_hash_entry *parent;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* ELF symbol version. */
|
||||||
|
enum elf_symbol_version
|
||||||
|
{
|
||||||
|
unknown = 0,
|
||||||
|
unversioned,
|
||||||
|
versioned,
|
||||||
|
versioned_hidden
|
||||||
|
};
|
||||||
|
|
||||||
/* ELF linker hash table entries. */
|
/* ELF linker hash table entries. */
|
||||||
|
|
||||||
struct elf_link_hash_entry
|
struct elf_link_hash_entry
|
||||||
|
@ -178,8 +187,8 @@ struct elf_link_hash_entry
|
||||||
unsigned int needs_plt : 1;
|
unsigned int needs_plt : 1;
|
||||||
/* Symbol appears in a non-ELF input file. */
|
/* Symbol appears in a non-ELF input file. */
|
||||||
unsigned int non_elf : 1;
|
unsigned int non_elf : 1;
|
||||||
/* Symbol should be marked as hidden in the version information. */
|
/* Symbol version information. */
|
||||||
unsigned int hidden : 1;
|
ENUM_BITFIELD (elf_symbol_version) versioned : 2;
|
||||||
/* Symbol was forced to local scope due to a version script file. */
|
/* Symbol was forced to local scope due to a version script file. */
|
||||||
unsigned int forced_local : 1;
|
unsigned int forced_local : 1;
|
||||||
/* Symbol was forced to be dynamic due to a version script file. */
|
/* Symbol was forced to be dynamic due to a version script file. */
|
||||||
|
|
123
bfd/elflink.c
123
bfd/elflink.c
|
@ -971,15 +971,28 @@ _bfd_elf_merge_symbol (bfd *abfd,
|
||||||
bed = get_elf_backend_data (abfd);
|
bed = get_elf_backend_data (abfd);
|
||||||
|
|
||||||
/* NEW_VERSION is the symbol version of the new symbol. */
|
/* NEW_VERSION is the symbol version of the new symbol. */
|
||||||
new_version = strrchr (name, ELF_VER_CHR);
|
if (h->versioned != unversioned)
|
||||||
if (new_version)
|
|
||||||
{
|
{
|
||||||
if (new_version > name && new_version[-1] != ELF_VER_CHR)
|
/* Symbol version is unknown or versioned. */
|
||||||
h->hidden = 1;
|
new_version = strrchr (name, ELF_VER_CHR);
|
||||||
new_version += 1;
|
if (new_version)
|
||||||
if (new_version[0] == '\0')
|
{
|
||||||
new_version = NULL;
|
if (h->versioned == unknown)
|
||||||
|
{
|
||||||
|
if (new_version > name && new_version[-1] != ELF_VER_CHR)
|
||||||
|
h->versioned = versioned_hidden;
|
||||||
|
else
|
||||||
|
h->versioned = versioned;
|
||||||
|
}
|
||||||
|
new_version += 1;
|
||||||
|
if (new_version[0] == '\0')
|
||||||
|
new_version = NULL;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
h->versioned = unversioned;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
new_version = NULL;
|
||||||
|
|
||||||
/* For merging, we only care about real symbols. But we need to make
|
/* For merging, we only care about real symbols. But we need to make
|
||||||
sure that indirect symbol dynamic flags are updated. */
|
sure that indirect symbol dynamic flags are updated. */
|
||||||
|
@ -998,8 +1011,8 @@ _bfd_elf_merge_symbol (bfd *abfd,
|
||||||
to the symbol with the same symbol version. NEW_HIDDEN is
|
to the symbol with the same symbol version. NEW_HIDDEN is
|
||||||
true if the new symbol is only visibile to the symbol with
|
true if the new symbol is only visibile to the symbol with
|
||||||
the same symbol version. */
|
the same symbol version. */
|
||||||
bfd_boolean old_hidden = h->hidden;
|
bfd_boolean old_hidden = h->versioned == versioned_hidden;
|
||||||
bfd_boolean new_hidden = hi->hidden;
|
bfd_boolean new_hidden = hi->versioned == versioned_hidden;
|
||||||
if (!old_hidden && !new_hidden)
|
if (!old_hidden && !new_hidden)
|
||||||
/* The new symbol matches the existing symbol if both
|
/* The new symbol matches the existing symbol if both
|
||||||
aren't hidden. */
|
aren't hidden. */
|
||||||
|
@ -1008,14 +1021,13 @@ _bfd_elf_merge_symbol (bfd *abfd,
|
||||||
{
|
{
|
||||||
/* OLD_VERSION is the symbol version of the existing
|
/* OLD_VERSION is the symbol version of the existing
|
||||||
symbol. */
|
symbol. */
|
||||||
char *old_version = strrchr (h->root.root.string,
|
char *old_version;
|
||||||
ELF_VER_CHR);
|
|
||||||
if (old_version)
|
if (h->versioned >= versioned)
|
||||||
{
|
old_version = strrchr (h->root.root.string,
|
||||||
old_version += 1;
|
ELF_VER_CHR) + 1;
|
||||||
if (old_version[0] == '\0')
|
else
|
||||||
old_version = NULL;
|
old_version = NULL;
|
||||||
}
|
|
||||||
|
|
||||||
/* The new symbol matches the existing symbol if they
|
/* The new symbol matches the existing symbol if they
|
||||||
have the same symbol version. */
|
have the same symbol version. */
|
||||||
|
@ -1674,13 +1686,32 @@ _bfd_elf_add_default_symbol (bfd *abfd,
|
||||||
asection *tmp_sec;
|
asection *tmp_sec;
|
||||||
bfd_boolean matched;
|
bfd_boolean matched;
|
||||||
|
|
||||||
|
if (h->versioned == unversioned || h->versioned == versioned_hidden)
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
/* If this symbol has a version, and it is the default version, we
|
/* If this symbol has a version, and it is the default version, we
|
||||||
create an indirect symbol from the default name to the fully
|
create an indirect symbol from the default name to the fully
|
||||||
decorated name. This will cause external references which do not
|
decorated name. This will cause external references which do not
|
||||||
specify a version to be bound to this version of the symbol. */
|
specify a version to be bound to this version of the symbol. */
|
||||||
p = strchr (name, ELF_VER_CHR);
|
p = strchr (name, ELF_VER_CHR);
|
||||||
if (p == NULL || p[1] != ELF_VER_CHR)
|
if (h->versioned == unknown)
|
||||||
return TRUE;
|
{
|
||||||
|
if (p == NULL)
|
||||||
|
{
|
||||||
|
h->versioned = unversioned;
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (p[1] != ELF_VER_CHR)
|
||||||
|
{
|
||||||
|
h->versioned = versioned_hidden;
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
h->versioned = versioned;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bed = get_elf_backend_data (abfd);
|
bed = get_elf_backend_data (abfd);
|
||||||
collect = bed->collect;
|
collect = bed->collect;
|
||||||
|
@ -5230,7 +5261,6 @@ elf_collect_hash_codes (struct elf_link_hash_entry *h, void *data)
|
||||||
{
|
{
|
||||||
struct hash_codes_info *inf = (struct hash_codes_info *) data;
|
struct hash_codes_info *inf = (struct hash_codes_info *) data;
|
||||||
const char *name;
|
const char *name;
|
||||||
char *p;
|
|
||||||
unsigned long ha;
|
unsigned long ha;
|
||||||
char *alc = NULL;
|
char *alc = NULL;
|
||||||
|
|
||||||
|
@ -5239,18 +5269,21 @@ elf_collect_hash_codes (struct elf_link_hash_entry *h, void *data)
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
|
||||||
name = h->root.root.string;
|
name = h->root.root.string;
|
||||||
p = strchr (name, ELF_VER_CHR);
|
if (h->versioned >= versioned)
|
||||||
if (p != NULL)
|
|
||||||
{
|
{
|
||||||
alc = (char *) bfd_malloc (p - name + 1);
|
char *p = strchr (name, ELF_VER_CHR);
|
||||||
if (alc == NULL)
|
if (p != NULL)
|
||||||
{
|
{
|
||||||
inf->error = TRUE;
|
alc = (char *) bfd_malloc (p - name + 1);
|
||||||
return FALSE;
|
if (alc == NULL)
|
||||||
|
{
|
||||||
|
inf->error = TRUE;
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
memcpy (alc, name, p - name);
|
||||||
|
alc[p - name] = '\0';
|
||||||
|
name = alc;
|
||||||
}
|
}
|
||||||
memcpy (alc, name, p - name);
|
|
||||||
alc[p - name] = '\0';
|
|
||||||
name = alc;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Compute the hash value. */
|
/* Compute the hash value. */
|
||||||
|
@ -5298,7 +5331,6 @@ elf_collect_gnu_hash_codes (struct elf_link_hash_entry *h, void *data)
|
||||||
{
|
{
|
||||||
struct collect_gnu_hash_codes *s = (struct collect_gnu_hash_codes *) data;
|
struct collect_gnu_hash_codes *s = (struct collect_gnu_hash_codes *) data;
|
||||||
const char *name;
|
const char *name;
|
||||||
char *p;
|
|
||||||
unsigned long ha;
|
unsigned long ha;
|
||||||
char *alc = NULL;
|
char *alc = NULL;
|
||||||
|
|
||||||
|
@ -5311,18 +5343,21 @@ elf_collect_gnu_hash_codes (struct elf_link_hash_entry *h, void *data)
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
|
||||||
name = h->root.root.string;
|
name = h->root.root.string;
|
||||||
p = strchr (name, ELF_VER_CHR);
|
if (h->versioned >= versioned)
|
||||||
if (p != NULL)
|
|
||||||
{
|
{
|
||||||
alc = (char *) bfd_malloc (p - name + 1);
|
char *p = strchr (name, ELF_VER_CHR);
|
||||||
if (alc == NULL)
|
if (p != NULL)
|
||||||
{
|
{
|
||||||
s->error = TRUE;
|
alc = (char *) bfd_malloc (p - name + 1);
|
||||||
return FALSE;
|
if (alc == NULL)
|
||||||
|
{
|
||||||
|
s->error = TRUE;
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
memcpy (alc, name, p - name);
|
||||||
|
alc[p - name] = '\0';
|
||||||
|
name = alc;
|
||||||
}
|
}
|
||||||
memcpy (alc, name, p - name);
|
|
||||||
alc[p - name] = '\0';
|
|
||||||
name = alc;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Compute the hash value. */
|
/* Compute the hash value. */
|
||||||
|
@ -6859,7 +6894,7 @@ _bfd_elf_link_hash_copy_indirect (struct bfd_link_info *info,
|
||||||
symbol which just became indirect if DIR isn't a hidden versioned
|
symbol which just became indirect if DIR isn't a hidden versioned
|
||||||
symbol. */
|
symbol. */
|
||||||
|
|
||||||
if (!dir->hidden)
|
if (dir->versioned != versioned_hidden)
|
||||||
{
|
{
|
||||||
dir->ref_dynamic |= ind->ref_dynamic;
|
dir->ref_dynamic |= ind->ref_dynamic;
|
||||||
dir->ref_regular |= ind->ref_regular;
|
dir->ref_regular |= ind->ref_regular;
|
||||||
|
@ -8963,7 +8998,7 @@ elf_link_output_extsym (struct bfd_hash_entry *bh, void *data)
|
||||||
&& !h->dynamic
|
&& !h->dynamic
|
||||||
&& !h->ref_dynamic
|
&& !h->ref_dynamic
|
||||||
&& h->def_regular
|
&& h->def_regular
|
||||||
&& h->hidden));
|
&& h->versioned == versioned_hidden));
|
||||||
|
|
||||||
if (h->root.type == bfd_link_hash_warning)
|
if (h->root.type == bfd_link_hash_warning)
|
||||||
{
|
{
|
||||||
|
@ -9359,9 +9394,9 @@ elf_link_output_extsym (struct bfd_hash_entry *bh, void *data)
|
||||||
iversym.vs_vers++;
|
iversym.vs_vers++;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Turn on VERSYM_HIDDEN only if the hidden vesioned symbol is
|
/* Turn on VERSYM_HIDDEN only if the hidden versioned symbol is
|
||||||
defined locally. */
|
defined locally. */
|
||||||
if (h->hidden && h->def_regular)
|
if (h->versioned == versioned_hidden && h->def_regular)
|
||||||
iversym.vs_vers |= VERSYM_HIDDEN;
|
iversym.vs_vers |= VERSYM_HIDDEN;
|
||||||
|
|
||||||
eversym = (Elf_External_Versym *) flinfo->symver_sec->contents;
|
eversym = (Elf_External_Versym *) flinfo->symver_sec->contents;
|
||||||
|
@ -12541,7 +12576,7 @@ bfd_elf_gc_mark_dynamic_ref_symbol (struct elf_link_hash_entry *h, void *inf)
|
||||||
|| (h->dynamic
|
|| (h->dynamic
|
||||||
&& d != NULL
|
&& d != NULL
|
||||||
&& (*d->match) (&d->head, NULL, h->root.root.string)))
|
&& (*d->match) (&d->head, NULL, h->root.root.string)))
|
||||||
&& (strchr (h->root.root.string, ELF_VER_CHR) != NULL
|
&& (h->versioned >= versioned
|
||||||
|| !bfd_hide_sym_by_version (info->version_info,
|
|| !bfd_hide_sym_by_version (info->version_info,
|
||||||
h->root.root.string)))))
|
h->root.root.string)))))
|
||||||
h->root.u.def.section->flags |= SEC_KEEP;
|
h->root.u.def.section->flags |= SEC_KEEP;
|
||||||
|
|
Loading…
Reference in New Issue