summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorH.J. Lu <hjl.tools@gmail.com>2015-07-28 05:11:02 -0700
committerH.J. Lu <hjl.tools@gmail.com>2015-08-07 05:25:32 -0700
commit84031c1729ef5aedd9932eaacb04694810bd1632 (patch)
tree62651d72f6996bb7fe27a79a20e5b959109e6336
parent6e33951edcbed1fd803beabcde2af3b252b92164 (diff)
downloadbinutils-gdb-users/hjl/pr18720.tar.gz
Add a versioned field to elf_link_hash_entryusers/hjl/pr18720
This patch adds a versioned field to elf_link_hash_entry so that we can avoid calling strchr and strrchr if the symbol is unversioned. * elf-bfd.h (elf_link_hash_entry): Add 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.
-rw-r--r--bfd/elf-bfd.h6
-rw-r--r--bfd/elflink.c109
2 files changed, 77 insertions, 38 deletions
diff --git a/bfd/elf-bfd.h b/bfd/elf-bfd.h
index e08b2d6ed43..df71083a03a 100644
--- a/bfd/elf-bfd.h
+++ b/bfd/elf-bfd.h
@@ -178,6 +178,12 @@ struct elf_link_hash_entry
unsigned int needs_plt : 1;
/* Symbol appears in a non-ELF input file. */
unsigned int non_elf : 1;
+ /* Symbol version information:
+ 0: unknown
+ 1: unversioned
+ 2: versioned
+ */
+ unsigned int versioned : 2;
/* Symbol should be marked as hidden in the version information. */
unsigned int hidden : 1;
/* Symbol was forced to local scope due to a version script file. */
diff --git a/bfd/elflink.c b/bfd/elflink.c
index 832b374c698..ce2876494f7 100644
--- a/bfd/elflink.c
+++ b/bfd/elflink.c
@@ -971,15 +971,27 @@ _bfd_elf_merge_symbol (bfd *abfd,
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 != 1)
{
- 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 == 0)
+ {
+ h->versioned = 2;
+ if (new_version > name && new_version[-1] != ELF_VER_CHR)
+ h->hidden = 1;
+ }
+ new_version += 1;
+ if (new_version[0] == '\0')
+ new_version = NULL;
+ }
+ else
+ h->versioned = 1;
}
+ 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. */
@@ -1008,14 +1020,13 @@ _bfd_elf_merge_symbol (bfd *abfd,
{
/* 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 == 2)
+ 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. */
@@ -1674,13 +1685,31 @@ _bfd_elf_add_default_symbol (bfd *abfd,
asection *tmp_sec;
bfd_boolean matched;
+ if (h->versioned == 1 || h->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 == 0)
+ {
+ if (p == NULL)
+ {
+ h->versioned = 1;
+ return TRUE;
+ }
+ else
+ {
+ h->versioned = 2;
+ if (p[1] != ELF_VER_CHR)
+ {
+ h->hidden = 1;
+ return TRUE;
+ }
+ }
+ }
bed = get_elf_backend_data (abfd);
collect = bed->collect;
@@ -5230,7 +5259,6 @@ elf_collect_hash_codes (struct elf_link_hash_entry *h, void *data)
{
struct hash_codes_info *inf = (struct hash_codes_info *) data;
const char *name;
- char *p;
unsigned long ha;
char *alc = NULL;
@@ -5239,18 +5267,21 @@ elf_collect_hash_codes (struct elf_link_hash_entry *h, void *data)
return TRUE;
name = h->root.root.string;
- p = strchr (name, ELF_VER_CHR);
- if (p != NULL)
+ if (h->versioned == 2)
{
- 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. */
@@ -5298,7 +5329,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;
const char *name;
- char *p;
unsigned long ha;
char *alc = NULL;
@@ -5311,18 +5341,21 @@ elf_collect_gnu_hash_codes (struct elf_link_hash_entry *h, void *data)
return TRUE;
name = h->root.root.string;
- p = strchr (name, ELF_VER_CHR);
- if (p != NULL)
+ if (h->versioned == 2)
{
- 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. */
@@ -12541,7 +12574,7 @@ bfd_elf_gc_mark_dynamic_ref_symbol (struct elf_link_hash_entry *h, void *inf)
|| (h->dynamic
&& d != NULL
&& (*d->match) (&d->head, NULL, h->root.root.string)))
- && (strchr (h->root.root.string, ELF_VER_CHR) != NULL
+ && (h->versioned == 2
|| !bfd_hide_sym_by_version (info->version_info,
h->root.root.string)))))
h->root.u.def.section->flags |= SEC_KEEP;