+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>
PR binutils/18785
(elf_link_output_extsym): Bind a symbol locally when linking
executable if it is locally defined, hidden versioned, not
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.
2015-08-05 Nick Clifton <nickc@redhat.com>
bed = get_elf_backend_data (abfd);
/* NEW_VERSION is the symbol version of the new symbol. */
- new_version = strrchr (name, ELF_VER_CHR);
- if (new_version)
+ if (h->versioned != unversioned)
{
- if (new_version > name && new_version[-1] != ELF_VER_CHR)
- h->hidden = 1;
- new_version += 1;
- if (new_version[0] == '\0')
- new_version = NULL;
+ /* Symbol version is unknown or versioned. */
+ new_version = strrchr (name, ELF_VER_CHR);
+ if (new_version)
+ {
+ 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
sure that indirect symbol dynamic flags are updated. */
to the symbol with the same symbol version. NEW_HIDDEN is
true if the new symbol is only visibile to the symbol with
the same symbol version. */
- bfd_boolean old_hidden = h->hidden;
- bfd_boolean new_hidden = hi->hidden;
+ bfd_boolean old_hidden = h->versioned == versioned_hidden;
+ bfd_boolean new_hidden = hi->versioned == versioned_hidden;
if (!old_hidden && !new_hidden)
/* The new symbol matches the existing symbol if both
aren't hidden. */
{
/* OLD_VERSION is the symbol version of the existing
symbol. */
- char *old_version = strrchr (h->root.root.string,
- ELF_VER_CHR);
- if (old_version)
- {
- old_version += 1;
- if (old_version[0] == '\0')
- old_version = NULL;
- }
+ char *old_version;
+
+ if (h->versioned >= versioned)
+ old_version = strrchr (h->root.root.string,
+ ELF_VER_CHR) + 1;
+ else
+ old_version = NULL;
/* The new symbol matches the existing symbol if they
have the same symbol version. */
asection *tmp_sec;
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
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 (h->versioned == unknown)
+ {
+ 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);
collect = bed->collect;
{
struct hash_codes_info *inf = (struct hash_codes_info *) data;
const char *name;
- char *p;
unsigned long ha;
char *alc = NULL;
return TRUE;
name = h->root.root.string;
- p = strchr (name, ELF_VER_CHR);
- if (p != NULL)
+ if (h->versioned >= versioned)
{
- alc = (char *) bfd_malloc (p - name + 1);
- if (alc == NULL)
+ char *p = strchr (name, ELF_VER_CHR);
+ if (p != NULL)
{
- inf->error = TRUE;
- return FALSE;
+ alc = (char *) bfd_malloc (p - name + 1);
+ 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. */
{
struct collect_gnu_hash_codes *s = (struct collect_gnu_hash_codes *) data;
const char *name;
- char *p;
unsigned long ha;
char *alc = NULL;
return TRUE;
name = h->root.root.string;
- p = strchr (name, ELF_VER_CHR);
- if (p != NULL)
+ if (h->versioned >= versioned)
{
- alc = (char *) bfd_malloc (p - name + 1);
- if (alc == NULL)
+ char *p = strchr (name, ELF_VER_CHR);
+ if (p != NULL)
{
- s->error = TRUE;
- return FALSE;
+ alc = (char *) bfd_malloc (p - name + 1);
+ 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. */
symbol which just became indirect if DIR isn't a hidden versioned
symbol. */
- if (!dir->hidden)
+ if (dir->versioned != versioned_hidden)
{
dir->ref_dynamic |= ind->ref_dynamic;
dir->ref_regular |= ind->ref_regular;
&& !h->dynamic
&& !h->ref_dynamic
&& h->def_regular
- && h->hidden));
+ && h->versioned == versioned_hidden));
if (h->root.type == bfd_link_hash_warning)
{
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. */
- if (h->hidden && h->def_regular)
+ if (h->versioned == versioned_hidden && h->def_regular)
iversym.vs_vers |= VERSYM_HIDDEN;
eversym = (Elf_External_Versym *) flinfo->symver_sec->contents;
|| (h->dynamic
&& d != NULL
&& (*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,
h->root.root.string)))))
h->root.u.def.section->flags |= SEC_KEEP;