aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bfd/ChangeLog8
-rw-r--r--bfd/elflink.c175
2 files changed, 91 insertions, 92 deletions
diff --git a/bfd/ChangeLog b/bfd/ChangeLog
index 3efcb94..7fe0dce 100644
--- a/bfd/ChangeLog
+++ b/bfd/ChangeLog
@@ -1,3 +1,11 @@
+2009-01-24 Alan Modra <amodra@bigpond.net.au>
+
+ PR 6022
+ * elflink.c (find_version_for_sym): New function split out from,
+ but without export_dynamic test, ..
+ (_bfd_elf_link_assign_sym_version): ..here.
+ (_bfd_elf_export_symbol): Use it.
+
2009-01-23 Alan Modra <amodra@bigpond.net.au>
* elf-bfd.h (struct elf_assign_sym_version_info): Delete.
diff --git a/bfd/elflink.c b/bfd/elflink.c
index 5bbe820..badbe9e 100644
--- a/bfd/elflink.c
+++ b/bfd/elflink.c
@@ -1798,6 +1798,80 @@ nondefault:
return TRUE;
}
+static struct bfd_elf_version_tree *
+find_version_for_sym (struct bfd_elf_version_tree *verdefs,
+ const char *sym_name,
+ bfd_boolean *hide)
+{
+ struct bfd_elf_version_tree *t;
+ struct bfd_elf_version_tree *local_ver, *global_ver, *exist_ver;
+
+ local_ver = NULL;
+ global_ver = NULL;
+ exist_ver = NULL;
+ for (t = verdefs; t != NULL; t = t->next)
+ {
+ if (t->globals.list != NULL)
+ {
+ struct bfd_elf_version_expr *d = NULL;
+
+ while ((d = (*t->match) (&t->globals, d, sym_name)) != NULL)
+ {
+ global_ver = t;
+ 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;
+ }
+
+ if (t->locals.list != NULL)
+ {
+ struct bfd_elf_version_expr *d = NULL;
+
+ while ((d = (*t->match) (&t->locals, d, sym_name)) != NULL)
+ {
+ local_ver = t;
+ /* 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)
+ break;
+ }
+ }
+
+ if (global_ver != NULL)
+ {
+ /* 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. */
+ *hide = exist_ver == global_ver;
+ return global_ver;
+ }
+
+ if (local_ver != NULL)
+ {
+ *hide = TRUE;
+ return local_ver;
+ }
+
+ return NULL;
+}
+
/* This routine is used to export all defined symbols into the dynamic
symbol table. It is called via elf_link_hash_traverse. */
@@ -1821,29 +1895,12 @@ _bfd_elf_export_symbol (struct elf_link_hash_entry *h, void *data)
&& (h->def_regular
|| h->ref_regular))
{
- struct bfd_elf_version_tree *t;
- struct bfd_elf_version_expr *d;
+ bfd_boolean hide;
- for (t = eif->verdefs; t != NULL; t = t->next)
+ if (eif->verdefs == NULL
+ || (find_version_for_sym (eif->verdefs, h->root.root.string, &hide)
+ && !hide))
{
- if (t->globals.list != NULL)
- {
- d = (*t->match) (&t->globals, NULL, h->root.root.string);
- if (d != NULL)
- goto doit;
- }
-
- if (t->locals.list != NULL)
- {
- d = (*t->match) (&t->locals, NULL, h->root.root.string);
- if (d != NULL)
- return TRUE;
- }
- }
-
- if (!eif->verdefs)
- {
- doit:
if (! bfd_elf_link_record_dynamic_symbol (eif->info, h))
{
eif->failed = TRUE;
@@ -2101,78 +2158,12 @@ _bfd_elf_link_assign_sym_version (struct elf_link_hash_entry *h, void *data)
something. */
if (h->verinfo.vertree == NULL && sinfo->verdefs != NULL)
{
- struct bfd_elf_version_tree *t;
- 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)
- {
- d = NULL;
- while ((d = (*t->match) (&t->globals, d,
- h->root.root.string)) != NULL)
- {
- 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;
- }
+ bfd_boolean hide;
- if (t->locals.list != NULL)
- {
- d = NULL;
- while ((d = (*t->match) (&t->locals, d,
- h->root.root.string)) != NULL)
- {
- local_ver = t;
- /* 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)
- break;
- }
- }
-
- 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 (!info->export_dynamic
- || exist_ver == local_ver)
- (*bed->elf_backend_hide_symbol) (info, h, TRUE);
- }
+ h->verinfo.vertree = find_version_for_sym (sinfo->verdefs,
+ h->root.root.string, &hide);
+ if (h->verinfo.vertree != NULL && hide)
+ (*bed->elf_backend_hide_symbol) (info, h, TRUE);
}
return TRUE;