summaryrefslogtreecommitdiffstats
path: root/ld/ldlang.c
diff options
context:
space:
mode:
authorJakub Jelinek <jakub@redhat.com>2003-10-22 06:58:17 +0000
committerJakub Jelinek <jakub@redhat.com>2003-10-22 06:58:17 +0000
commit108ba30509ad6169d0f2e06b755fa39a2c28a946 (patch)
treef08f61aaf06d9e7ba1789b24f137c266bb6fc80e /ld/ldlang.c
parenta9b7fca23b894846cfca99db5bb1c9d06ea75a89 (diff)
downloadppe42-binutils-108ba30509ad6169d0f2e06b755fa39a2c28a946.tar.gz
ppe42-binutils-108ba30509ad6169d0f2e06b755fa39a2c28a946.zip
bfd/
* elflink.c (_bfd_elf_export_symbol): Adjust for globals and locals field changes. (_bfd_elf_link_assign_sym_version): Likewise. * elflink.h (size_dynamic_sections): Likewise. include/ * bfdlink.h (struct bfd_elf_version_expr): Remove match field. Add wildcard and mask fields. (BFD_ELF_VERSION_C_TYPE): Define. (BFD_ELF_VERSION_CXX_TYPE): Likewise. (BFD_ELF_VERSION_JAVA_TYPE): Likewise. (struct bfd_elf_version_expr_head): New. (struct bfd_elf_version_tree): Add match field. Change type of globals and locals fields to struct bfd_elf_version_expr_head. ld/ * ldlang.c: Include hashtab.h. (lang_vers_match_lang_c, lang_vers_match_lang_cplusplus, lang_vers_match_lang_java): Remove. (lang_vers_match): New function. (lang_new_vers_pattern): Initialize wildcard and mask fields, don't initialize match. (lang_new_vers_node): Use xcalloc. Adjust for globals and locals field type changes. Set match field. (version_expr_head_hash, version_expr_head_eq): New functions. (lang_finalize_version_expr_head): New function. (lang_register_vers_node): Call lang_finalize_version_expr_head. Search in hash table if not wildcard when looking for duplicates. * emultempl/ppc64elf.em (new_vers_pattern): Don't bother with duplicate checking. Initialize all fields of dot_entry from entry with the exception of pattern and next.
Diffstat (limited to 'ld/ldlang.c')
-rw-r--r--ld/ldlang.c298
1 files changed, 231 insertions, 67 deletions
diff --git a/ld/ldlang.c b/ld/ldlang.c
index ad75d2648e..b180edeb34 100644
--- a/ld/ldlang.c
+++ b/ld/ldlang.c
@@ -39,6 +39,7 @@
#include "ldemul.h"
#include "fnmatch.h"
#include "demangle.h"
+#include "hashtab.h"
#ifndef offsetof
#define offsetof(TYPE, MEMBER) ((size_t) & (((TYPE*) 0)->MEMBER))
@@ -4973,65 +4974,108 @@ lang_leave_overlay (etree_type *lma_expr,
struct bfd_elf_version_tree *lang_elf_version_info;
-static int
-lang_vers_match_lang_c (struct bfd_elf_version_expr *expr,
- const char *sym)
-{
- if (expr->pattern[0] == '*' && expr->pattern[1] == '\0')
- return 1;
- return fnmatch (expr->pattern, sym, 0) == 0;
-}
+/* If PREV is NULL, return first version pattern matching particular symbol.
+ If PREV is non-NULL, return first version pattern matching particular
+ symbol after PREV (previously returned by lang_vers_match). */
-static int
-lang_vers_match_lang_cplusplus (struct bfd_elf_version_expr *expr,
- const char *sym)
+static struct bfd_elf_version_expr *
+lang_vers_match (struct bfd_elf_version_expr_head *head,
+ struct bfd_elf_version_expr *prev,
+ const char *sym)
{
- char *alt_sym;
- int result;
-
- if (expr->pattern[0] == '*' && expr->pattern[1] == '\0')
- return 1;
+ const char *cxx_sym = sym;
+ const char *java_sym = sym;
+ struct bfd_elf_version_expr *expr = NULL;
- alt_sym = cplus_demangle (sym, /* DMGL_NO_TPARAMS */ 0);
- if (!alt_sym)
+ if (head->mask & BFD_ELF_VERSION_CXX_TYPE)
{
- /* cplus_demangle (also) returns NULL when it is not a C++ symbol.
- Should we early out FALSE in this case? */
- result = fnmatch (expr->pattern, sym, 0) == 0;
+ cxx_sym = cplus_demangle (sym, /* DMGL_NO_TPARAMS */ 0);
+ if (!cxx_sym)
+ cxx_sym = sym;
}
- else
+ if (head->mask & BFD_ELF_VERSION_JAVA_TYPE)
{
- result = fnmatch (expr->pattern, alt_sym, 0) == 0;
- free (alt_sym);
+ java_sym = cplus_demangle (sym, DMGL_JAVA);
+ if (!java_sym)
+ java_sym = sym;
}
- return result;
-}
-
-static int
-lang_vers_match_lang_java (struct bfd_elf_version_expr *expr,
- const char *sym)
-{
- char *alt_sym;
- int result;
-
- if (expr->pattern[0] == '*' && expr->pattern[1] == '\0')
- return 1;
-
- alt_sym = cplus_demangle (sym, DMGL_JAVA);
- if (!alt_sym)
+ if (head->htab && (prev == NULL || prev->wildcard == 0))
{
- /* cplus_demangle (also) returns NULL when it is not a Java symbol.
- Should we early out FALSE in this case? */
- result = fnmatch (expr->pattern, sym, 0) == 0;
+ struct bfd_elf_version_expr e;
+
+ switch (prev ? prev->mask : 0)
+ {
+ case 0:
+ if (head->mask & BFD_ELF_VERSION_C_TYPE)
+ {
+ e.pattern = sym;
+ expr = htab_find (head->htab, &e);
+ while (expr && strcmp (expr->pattern, sym) == 0)
+ if (expr->mask == BFD_ELF_VERSION_C_TYPE)
+ goto out_ret;
+ else
+ expr = expr->next;
+ }
+ /* Fallthrough */
+ case BFD_ELF_VERSION_C_TYPE:
+ if (head->mask & BFD_ELF_VERSION_CXX_TYPE)
+ {
+ e.pattern = cxx_sym;
+ expr = htab_find (head->htab, &e);
+ while (expr && strcmp (expr->pattern, sym) == 0)
+ if (expr->mask == BFD_ELF_VERSION_CXX_TYPE)
+ goto out_ret;
+ else
+ expr = expr->next;
+ }
+ /* Fallthrough */
+ case BFD_ELF_VERSION_CXX_TYPE:
+ if (head->mask & BFD_ELF_VERSION_JAVA_TYPE)
+ {
+ e.pattern = java_sym;
+ expr = htab_find (head->htab, &e);
+ while (expr && strcmp (expr->pattern, sym) == 0)
+ if (expr->mask == BFD_ELF_VERSION_JAVA_TYPE)
+ goto out_ret;
+ else
+ expr = expr->next;
+ }
+ /* Fallthrough */
+ default:
+ break;
+ }
}
+
+ /* Finally, try the wildcards. */
+ if (prev == NULL || prev->wildcard == 0)
+ expr = head->remaining;
else
+ expr = prev->next;
+ while (expr)
{
- result = fnmatch (expr->pattern, alt_sym, 0) == 0;
- free (alt_sym);
+ const char *s;
+
+ if (expr->pattern[0] == '*' && expr->pattern[1] == '\0')
+ break;
+
+ if (expr->mask == BFD_ELF_VERSION_JAVA_TYPE)
+ s = java_sym;
+ else if (expr->mask == BFD_ELF_VERSION_CXX_TYPE)
+ s = cxx_sym;
+ else
+ s = sym;
+ if (fnmatch (expr->pattern, sym, 0) == 0)
+ break;
+ expr = expr->next;
}
- return result;
+out_ret:
+ if (cxx_sym != sym)
+ free ((char *) cxx_sym);
+ if (java_sym != sym)
+ free ((char *) java_sym);
+ return expr;
}
/* This is called for each variable name or match expression. */
@@ -5048,18 +5092,19 @@ lang_new_vers_pattern (struct bfd_elf_version_expr *orig,
ret->pattern = new;
ret->symver = 0;
ret->script = 0;
+ ret->wildcard = wildcardp (new);
if (lang == NULL || strcasecmp (lang, "C") == 0)
- ret->match = lang_vers_match_lang_c;
+ ret->mask = BFD_ELF_VERSION_C_TYPE;
else if (strcasecmp (lang, "C++") == 0)
- ret->match = lang_vers_match_lang_cplusplus;
+ ret->mask = BFD_ELF_VERSION_CXX_TYPE;
else if (strcasecmp (lang, "Java") == 0)
- ret->match = lang_vers_match_lang_java;
+ ret->mask = BFD_ELF_VERSION_JAVA_TYPE;
else
{
einfo (_("%X%P: unknown language `%s' in version information\n"),
lang);
- ret->match = lang_vers_match_lang_c;
+ ret->mask = BFD_ELF_VERSION_C_TYPE;
}
return ldemul_new_vers_pattern (ret);
@@ -5074,15 +5119,11 @@ lang_new_vers_node (struct bfd_elf_version_expr *globals,
{
struct bfd_elf_version_tree *ret;
- ret = xmalloc (sizeof *ret);
- ret->next = NULL;
- ret->name = NULL;
- ret->vernum = 0;
- ret->globals = globals;
- ret->locals = locals;
- ret->deps = NULL;
+ ret = xcalloc (1, sizeof *ret);
+ ret->globals.list = globals;
+ ret->locals.list = locals;
+ ret->match = lang_vers_match;
ret->name_indx = (unsigned int) -1;
- ret->used = 0;
return ret;
}
@@ -5090,6 +5131,102 @@ lang_new_vers_node (struct bfd_elf_version_expr *globals,
static int version_index;
+static hashval_t
+version_expr_head_hash (const void *p)
+{
+ const struct bfd_elf_version_expr *e = p;
+
+ return htab_hash_string (e->pattern);
+}
+
+static int
+version_expr_head_eq (const void *p1, const void *p2)
+{
+ const struct bfd_elf_version_expr *e1 = p1;
+ const struct bfd_elf_version_expr *e2 = p2;
+
+ return strcmp (e1->pattern, e2->pattern) == 0;
+}
+
+static void
+lang_finalize_version_expr_head (struct bfd_elf_version_expr_head *head)
+{
+ size_t count = 0;
+ struct bfd_elf_version_expr *e, *next;
+ struct bfd_elf_version_expr **list_loc, **remaining_loc;
+
+ for (e = head->list; e; e = e->next)
+ {
+ if (!e->wildcard)
+ count++;
+ head->mask |= e->mask;
+ }
+
+ if (count)
+ {
+ head->htab = htab_create (count * 2, version_expr_head_hash,
+ version_expr_head_eq, NULL);
+ list_loc = &head->list;
+ remaining_loc = &head->remaining;
+ for (e = head->list; e; e = next)
+ {
+ next = e->next;
+ if (e->wildcard)
+ {
+ *remaining_loc = e;
+ remaining_loc = &e->next;
+ }
+ else
+ {
+ void **loc = htab_find_slot (head->htab, e, INSERT);
+
+ if (*loc)
+ {
+ struct bfd_elf_version_expr *e1, *last;
+
+ e1 = *loc;
+ last = NULL;
+ do
+ {
+ if (e1->mask == e->mask)
+ {
+ last = NULL;
+ break;
+ }
+ last = e1;
+ e1 = e1->next;
+ }
+ while (e1 && strcmp (e1->pattern, e->pattern) == 0);
+
+ if (last == NULL)
+ {
+ /* This is a duplicate. */
+ /* FIXME: Memory leak. Sometimes pattern is not
+ xmalloced alone, but in larger chunk of memory. */
+ /* free (e->pattern); */
+ free (e);
+ }
+ else
+ {
+ e->next = last->next;
+ last->next = e;
+ }
+ }
+ else
+ {
+ *loc = e;
+ *list_loc = e;
+ list_loc = &e->next;
+ }
+ }
+ }
+ *remaining_loc = NULL;
+ *list_loc = head->remaining;
+ }
+ else
+ head->remaining = head->list;
+}
+
/* This is called when we know the name and dependencies of the
version. */
@@ -5117,32 +5254,59 @@ lang_register_vers_node (const char *name,
if (strcmp (t->name, name) == 0)
einfo (_("%X%P: duplicate version tag `%s'\n"), name);
+ lang_finalize_version_expr_head (&version->globals);
+ lang_finalize_version_expr_head (&version->locals);
+
/* Check the global and local match names, and make sure there
aren't any duplicates. */
- for (e1 = version->globals; e1 != NULL; e1 = e1->next)
+ for (e1 = version->globals.list; e1 != NULL; e1 = e1->next)
{
for (t = lang_elf_version_info; t != NULL; t = t->next)
{
struct bfd_elf_version_expr *e2;
- for (e2 = t->locals; e2 != NULL; e2 = e2->next)
- if (strcmp (e1->pattern, e2->pattern) == 0)
- einfo (_("%X%P: duplicate expression `%s' in version information\n"),
- e1->pattern);
+ if (t->locals.htab && e1->wildcard == 0)
+ {
+ e2 = htab_find (t->locals.htab, e1);
+ while (e2 && strcmp (e1->pattern, e2->pattern) == 0)
+ {
+ if (e1->mask == e2->mask)
+ einfo (_("%X%P: duplicate expression `%s' in version information\n"),
+ e1->pattern);
+ e2 = e2->next;
+ }
+ }
+ else if (e1->wildcard)
+ for (e2 = t->locals.remaining; e2 != NULL; e2 = e2->next)
+ if (strcmp (e1->pattern, e2->pattern) == 0 && e1->mask == e2->mask)
+ einfo (_("%X%P: duplicate expression `%s' in version information\n"),
+ e1->pattern);
}
}
- for (e1 = version->locals; e1 != NULL; e1 = e1->next)
+ for (e1 = version->locals.list; e1 != NULL; e1 = e1->next)
{
for (t = lang_elf_version_info; t != NULL; t = t->next)
{
struct bfd_elf_version_expr *e2;
- for (e2 = t->globals; e2 != NULL; e2 = e2->next)
- if (strcmp (e1->pattern, e2->pattern) == 0)
- einfo (_("%X%P: duplicate expression `%s' in version information\n"),
- e1->pattern);
+ if (t->globals.htab && e1->wildcard == 0)
+ {
+ e2 = htab_find (t->globals.htab, e1);
+ while (e2 && strcmp (e1->pattern, e2->pattern) == 0)
+ {
+ if (e1->mask == e2->mask)
+ einfo (_("%X%P: duplicate expression `%s' in version information\n"),
+ e1->pattern);
+ e2 = e2->next;
+ }
+ }
+ else if (e1->wildcard)
+ for (e2 = t->globals.remaining; e2 != NULL; e2 = e2->next)
+ if (strcmp (e1->pattern, e2->pattern) == 0 && e1->mask == e2->mask)
+ einfo (_("%X%P: duplicate expression `%s' in version information\n"),
+ e1->pattern);
}
}
OpenPOWER on IntegriCloud