This is the mail archive of the binutils@sources.redhat.com mailing list for the binutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH] ld speedup 4/3 (symbol version handling)


Hi!

I was compiling a really big C++ shared library lately (2400 input objects,
100000 symbols in symbol version script) and ld spent more than 120 minutes
linking it. When -Wl,-O1 was removed, it took just 67 minutes.
This patch cuts those 67 minutes into 2 minutes.
The problem is O(nsyms^2) algorithm to assign symbol versions.
This patch adds a hashtable for the non-wildcard symbols in version script
and also demangles C++/Java syms just once for each successful match (with
the exception of 2 places all remaining elflink.c places look just for first
) instead of once for each matching attempt (I was using C version script,
not C++, as otherwise it would certainly not be one but a few more hours).
This patch passes make check and builds identical libc.so and the huge C++
library I was playing with as without the patch.
Speedup during glibc build is smaller, about 1.2 sec saved from 5.5 sec
total.

Now, when I link with -Wl,-O1, it takes an hour to link (instead of 2
before).  This is because of another O(nsyms^2) algorithm, in
compute_bucket_count.  Either we could assume optimize is not true
if nsyms is bigger than certain threshold, or it could try say at most between
3000 and 6000 attempts to find best bucket count instead of all
nsyms / 4 .. 2 * nsyms attempts unless the user really asks for quadratic
algorithm (-Wl,-O9 ?).  What do you think?

In the patch below, there are a few FIXMEs where I really don't know what is
intended (mainly, why is checking for '*' any special, there are other
wildcard characters in glob patterns).

2003-10-16  Jakub Jelinek  <jakub@redhat.com>

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.

--- bfd/elflink.c.jj	2003-09-29 13:10:49.000000000 +0200
+++ bfd/elflink.c	2003-10-16 15:45:21.000000000 +0200
@@ -1505,22 +1505,18 @@ _bfd_elf_export_symbol (struct elf_link_
 
       for (t = eif->verdefs; t != NULL; t = t->next)
 	{
-	  if (t->globals != NULL)
+	  if (t->globals.list != NULL)
 	    {
-	      for (d = t->globals; d != NULL; d = d->next)
-		{
-		  if ((*d->match) (d, h->root.root.string))
-		    goto doit;
-		}
+	      d = (*t->match) (&t->globals, NULL, h->root.root.string);
+	      if (d != NULL)
+		goto doit;
 	    }
 
-	  if (t->locals != NULL)
+	  if (t->locals.list != NULL)
 	    {
-	      for (d = t->locals ; d != NULL; d = d->next)
-		{
-		  if ((*d->match) (d, h->root.root.string))
-		    return TRUE;
-		}
+	      d = (*t->match) (&t->locals, NULL, h->root.root.string);
+	      if (d != NULL)
+		return TRUE;
 	    }
 	}
 
@@ -1699,31 +1695,19 @@ _bfd_elf_link_assign_sym_version (struct
 	      t->used = TRUE;
 	      d = NULL;
 
-	      if (t->globals != NULL)
-		{
-		  for (d = t->globals; d != NULL; d = d->next)
-		    if ((*d->match) (d, alc))
-		      break;
-		}
+	      if (t->globals.list != NULL)
+		d = (*t->match) (&t->globals, NULL, alc);
 
 	      /* See if there is anything to force this symbol to
 		 local scope.  */
-	      if (d == NULL && t->locals != NULL)
+	      if (d == NULL && t->locals.list != NULL)
 		{
-		  for (d = t->locals; d != NULL; d = d->next)
-		    {
-		      if ((*d->match) (d, alc))
-			{
-			  if (h->dynindx != -1
-			      && info->shared
-			      && ! info->export_dynamic)
-			    {
-			      (*bed->elf_backend_hide_symbol) (info, h, TRUE);
-			    }
-
-			  break;
-			}
-		    }
+		  d = (*t->match) (&t->locals, NULL, alc);
+		  if (d != NULL
+		      && h->dynindx != -1
+		      && info->shared
+		      && ! info->export_dynamic)
+		    (*bed->elf_backend_hide_symbol) (info, h, TRUE);
 		}
 
 	      free (alc);
@@ -1744,18 +1728,14 @@ _bfd_elf_link_assign_sym_version (struct
 	    return TRUE;
 
 	  amt = sizeof *t;
-	  t = bfd_alloc (sinfo->output_bfd, amt);
+	  t = bfd_zalloc (sinfo->output_bfd, amt);
 	  if (t == NULL)
 	    {
 	      sinfo->failed = TRUE;
 	      return FALSE;
 	    }
 
-	  t->next = NULL;
 	  t->name = p;
-	  t->globals = NULL;
-	  t->locals = NULL;
-	  t->deps = NULL;
 	  t->name_indx = (unsigned int) -1;
 	  t->used = TRUE;
 
@@ -1801,30 +1781,26 @@ _bfd_elf_link_assign_sym_version (struct
       local_ver = NULL;
       for (t = sinfo->verdefs; t != NULL; t = t->next)
 	{
-	  if (t->globals != NULL)
+	  if (t->globals.list != NULL)
 	    {
 	      bfd_boolean matched;
 
 	      matched = FALSE;
-	      for (d = t->globals; d != NULL; d = d->next)
-		{
-		  if ((*d->match) (d, h->root.root.string))
-		    {
-		      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;
-			  break;
-			}
-		    }
-		}
-
+	      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;
+		    break;
+		  }
 	      if (d != NULL)
 		break;
 	      else if (matched)
@@ -1833,19 +1809,18 @@ _bfd_elf_link_assign_sym_version (struct
 		(*bed->elf_backend_hide_symbol) (info, h, TRUE);
 	    }
 
-	  if (t->locals != NULL)
+	  if (t->locals.list != NULL)
 	    {
-	      for (d = t->locals; d != NULL; d = d->next)
+	      d = NULL;
+	      while ((d = (*t->match) (&t->locals, d,
+				       h->root.root.string)) != NULL)
 		{
+		  local_ver = t;
 		  /* If the match is "*", keep looking for a more
-		     explicit, perhaps even global, match.  */
-		  if (d->pattern[0] == '*' && d->pattern[1] == '\0')
-		    local_ver = t;
-		  else if ((*d->match) (d, h->root.root.string))
-		    {
-		      local_ver = t;
-		      break;
-		    }
+		     explicit, perhaps even global, match.
+		     XXX: Shouldn't this be !d->wildcard instead?  */
+		  if (d->pattern[0] != '*' || d->pattern[1] != '\0')
+		    break;
 		}
 
 	      if (d != NULL)
--- bfd/elflink.h.jj	2003-10-15 17:44:45.000000000 +0200
+++ bfd/elflink.h	2003-10-16 15:34:37.000000000 +0200
@@ -2058,7 +2058,9 @@ NAME(bfd_elf,size_dynamic_sections) (bfd
 
       /* Make all global versions with definiton.  */
       for (t = verdefs; t != NULL; t = t->next)
-	for (d = t->globals; d != NULL; d = d->next)
+	for (d = t->globals.list; d != NULL; d = d->next)
+	  /* FIXME: Shouldn't this be !d->symver && d->wildcard == 0
+	     instead?  */
 	  if (!d->symver && strchr (d->pattern, '*') == NULL)
 	    {
 	      const char *verstr, *name;
@@ -2124,7 +2126,7 @@ NAME(bfd_elf,size_dynamic_sections) (bfd
 	  /* Check if all global versions have a definiton.  */
 	  all_defined = TRUE;
 	  for (t = verdefs; t != NULL; t = t->next)
-	    for (d = t->globals; d != NULL; d = d->next)
+	    for (d = t->globals.list; d != NULL; d = d->next)
 	      if (!d->symver && !d->script
 		  && strchr (d->pattern, '*') == NULL)
 		{
@@ -2373,7 +2375,7 @@ NAME(bfd_elf,size_dynamic_sections) (bfd
 
 	      def.vd_version = VER_DEF_CURRENT;
 	      def.vd_flags = 0;
-	      if (t->globals == NULL && t->locals == NULL && ! t->used)
+	      if (t->globals.list == NULL && t->locals.list == NULL && ! t->used)
 		def.vd_flags |= VER_FLG_WEAK;
 	      def.vd_ndx = t->vernum + 1;
 	      def.vd_cnt = cdeps + 1;
--- include/bfdlink.h.jj	2003-08-28 08:14:34.000000000 +0200
+++ include/bfdlink.h	2003-10-16 15:13:22.000000000 +0200
@@ -617,20 +617,37 @@ extern struct bfd_link_order *bfd_new_li
    BFD, but it would be a pain.  Instead, the regular linker sets up
    these structures, and then passes them into BFD.  */
 
-/* Regular expressions for a version.  */
+/* Glob pattern for a version.  */
 
 struct bfd_elf_version_expr
 {
-  /* Next regular expression for this version.  */
+  /* Next glob pattern for this version.  */
   struct bfd_elf_version_expr *next;
-  /* Regular expression.  */
+  /* Glob pattern.  */
   const char *pattern;
-  /* Matching function.  */
-  int (*match) (struct bfd_elf_version_expr *, const char *);
   /* Defined by ".symver".  */
-  unsigned int symver: 1;
+  unsigned int symver : 1;
   /* Defined by version script.  */
   unsigned int script : 1;
+  /* Is this a wildcard?.  */
+  unsigned int wildcard : 1;
+  /* Pattern type.  */
+#define BFD_ELF_VERSION_C_TYPE		1
+#define BFD_ELF_VERSION_CXX_TYPE	2
+#define BFD_ELF_VERSION_JAVA_TYPE	4
+  unsigned int mask : 3;
+};
+
+struct bfd_elf_version_expr_head
+{
+  /* List of all patterns, both wildcards and non-wildcards.  */
+  struct bfd_elf_version_expr *list;
+  /* Hash table for non-wildcards.  */
+  void *htab;
+  /* Remaining patterns.  */
+  struct bfd_elf_version_expr *remaining;
+  /* What kind of pattern types are present in list (bitmask).  */
+  unsigned int mask;
 };
 
 /* Version dependencies.  */
@@ -654,15 +671,19 @@ struct bfd_elf_version_tree
   /* Version number.  */
   unsigned int vernum;
   /* Regular expressions for global symbols in this version.  */
-  struct bfd_elf_version_expr *globals;
+  struct bfd_elf_version_expr_head globals;
   /* Regular expressions for local symbols in this version.  */
-  struct bfd_elf_version_expr *locals;
+  struct bfd_elf_version_expr_head locals;
   /* List of versions which this version depends upon.  */
   struct bfd_elf_version_deps *deps;
   /* Index of the version name.  This is used within BFD.  */
   unsigned int name_indx;
   /* Whether this version tree was used.  This is used within BFD.  */
   int used;
+  /* Matching hook.  */
+  struct bfd_elf_version_expr *(*match)
+    (struct bfd_elf_version_expr_head *head,
+     struct bfd_elf_version_expr *prev, const char *sym);
 };
 
 #endif
--- ld/ldlang.c.jj	2003-10-15 17:45:41.000000000 +0200
+++ ld/ldlang.c	2003-10-16 15:54:29.000000000 +0200
@@ -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))
@@ -4951,65 +4952,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.  */
@@ -5026,18 +5070,19 @@ lang_new_vers_pattern (struct bfd_elf_ve
   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);
@@ -5052,15 +5097,11 @@ lang_new_vers_node (struct bfd_elf_versi
 {
   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;
 }
 
@@ -5068,6 +5109,102 @@ lang_new_vers_node (struct bfd_elf_versi
 
 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.  */
 
@@ -5095,32 +5232,59 @@ lang_register_vers_node (const char *nam
     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);
 	}
     }
 
--- ld/emultempl/ppc64elf.em.jj	2003-07-28 18:18:56.000000000 +0200
+++ ld/emultempl/ppc64elf.em	2003-10-16 21:17:58.000000000 +0200
@@ -405,46 +405,17 @@ gld${EMULATION_NAME}_new_vers_pattern (s
   unsigned int len;
   char *dot_pat;
 
-  if (!dotsyms || entry->pattern[0] == '*')
+  if (!dotsyms || entry->pattern[0] == '*' || entry->pattern[0] == '.')
     return entry;
 
-  /* Is the script adding ".foo" explicitly?  */
-  if (entry->pattern[0] == '.')
-    {
-      /* We may have added this pattern automatically.  Don't add it
-	 again.  Quadratic behaviour here is acceptable as the list
-	 may be traversed for each input bfd symbol.  */
-      for (next = entry->next; next != NULL; next = next->next)
-	{
-	  if (strcmp (next->pattern, entry->pattern) == 0
-	      && next->match == entry->match)
-	    {
-	      next = entry->next;
-	      free ((char *) entry->pattern);
-	      free (entry);
-	      return next;
-	    }
-	}
-      return entry;
-    }
-
-  /* Don't add ".foo" if the script has already done so.  */
-  for (next = entry->next; next != NULL; next = next->next)
-    {
-      if (next->pattern[0] == '.'
-	  && strcmp (next->pattern + 1, entry->pattern) == 0
-	  && next->match == entry->match)
-	return entry;
-    }
-
   dot_entry = xmalloc (sizeof *dot_entry);
+  *dot_entry = *entry;
   dot_entry->next = entry;
   len = strlen (entry->pattern) + 2;
   dot_pat = xmalloc (len);
   dot_pat[0] = '.';
   memcpy (dot_pat + 1, entry->pattern, len - 1);
   dot_entry->pattern = dot_pat;
-  dot_entry->match = entry->match;
   return dot_entry;
 }
 


	Jakub


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]