diff options
Diffstat (limited to 'bfd/elflink.c')
-rw-r--r-- | bfd/elflink.c | 72 |
1 files changed, 39 insertions, 33 deletions
diff --git a/bfd/elflink.c b/bfd/elflink.c index ce1dff7..43379c7 100644 --- a/bfd/elflink.c +++ b/bfd/elflink.c @@ -2010,41 +2010,36 @@ _bfd_elf_link_assign_sym_version (struct elf_link_hash_entry *h, void *data) if (h->verinfo.vertree == NULL && sinfo->verdefs != NULL) { struct bfd_elf_version_tree *t; - struct bfd_elf_version_tree *local_ver; + struct bfd_elf_version_tree *local_ver, *global_ver, *exist_ver; struct bfd_elf_version_expr *d; /* See if can find what version this symbol is in. If the symbol is supposed to be local, then don't actually register it. */ local_ver = NULL; + global_ver = NULL; + exist_ver = NULL; for (t = sinfo->verdefs; t != NULL; t = t->next) { if (t->globals.list != NULL) { - bfd_boolean matched; - - matched = FALSE; d = NULL; while ((d = (*t->match) (&t->globals, d, h->root.root.string)) != NULL) - if (d->symver) - matched = TRUE; - else - { - /* There is a version without definition. Make - the symbol the default definition for this - version. */ - h->verinfo.vertree = t; - local_ver = NULL; - d->script = 1; + { + global_ver = t; + local_ver = NULL; + if (d->symver) + exist_ver = t; + d->script = 1; + /* If the match is a wildcard pattern, keep looking for + a more explicit, perhaps even local, match. */ + if (d->literal) break; - } + } + if (d != NULL) break; - else if (matched) - /* There is no undefined version for this symbol. Hide the - default one. */ - (*bed->elf_backend_hide_symbol) (info, h, TRUE); } if (t->locals.list != NULL) @@ -2054,11 +2049,14 @@ _bfd_elf_link_assign_sym_version (struct elf_link_hash_entry *h, void *data) h->root.root.string)) != NULL) { local_ver = t; - /* If the match is "*", keep looking for a more - explicit, perhaps even global, match. - XXX: Shouldn't this be !d->wildcard instead? */ - if (d->pattern[0] != '*' || d->pattern[1] != '\0') - break; + /* If the match is a wildcard pattern, keep looking for + a more explicit, perhaps even global, match. */ + if (d->literal) + { + /* An exact match overrides a global wildcard. */ + global_ver = NULL; + break; + } } if (d != NULL) @@ -2066,14 +2064,22 @@ _bfd_elf_link_assign_sym_version (struct elf_link_hash_entry *h, void *data) } } - if (local_ver != NULL) + if (global_ver != NULL) + { + h->verinfo.vertree = global_ver; + /* If we already have a versioned symbol that matches the + node for this symbol, then we don't want to create a + duplicate from the unversioned symbol. Instead hide the + unversioned symbol. */ + if (exist_ver == global_ver) + (*bed->elf_backend_hide_symbol) (info, h, TRUE); + } + else if (local_ver != NULL) { h->verinfo.vertree = local_ver; - if (h->dynindx != -1 - && ! info->export_dynamic) - { - (*bed->elf_backend_hide_symbol) (info, h, TRUE); - } + if (!info->export_dynamic + || exist_ver == local_ver) + (*bed->elf_backend_hide_symbol) (info, h, TRUE); } } @@ -5566,14 +5572,14 @@ bfd_elf_size_dynamic_sections (bfd *output_bfd, /* Make all global versions with definition. */ for (t = verdefs; t != NULL; t = t->next) for (d = t->globals.list; d != NULL; d = d->next) - if (!d->symver && d->symbol) + if (!d->symver && d->literal) { const char *verstr, *name; size_t namelen, verlen, newlen; char *newname, *p; struct elf_link_hash_entry *newh; - name = d->symbol; + name = d->pattern; namelen = strlen (name); verstr = t->name; verlen = strlen (verstr); @@ -5631,7 +5637,7 @@ bfd_elf_size_dynamic_sections (bfd *output_bfd, all_defined = TRUE; for (t = verdefs; t != NULL; t = t->next) for (d = t->globals.list; d != NULL; d = d->next) - if (!d->symver && !d->script) + if (d->literal && !d->symver && !d->script) { (*_bfd_error_handler) (_("%s: undefined version: %s"), |