diff options
author | H.J. Lu <hjl.tools@gmail.com> | 2015-07-28 05:11:02 -0700 |
---|---|---|
committer | H.J. Lu <hjl.tools@gmail.com> | 2015-08-07 05:25:32 -0700 |
commit | 84031c1729ef5aedd9932eaacb04694810bd1632 (patch) | |
tree | 62651d72f6996bb7fe27a79a20e5b959109e6336 | |
parent | 6e33951edcbed1fd803beabcde2af3b252b92164 (diff) | |
download | binutils-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.h | 6 | ||||
-rw-r--r-- | bfd/elflink.c | 109 |
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; |