gas/
[deliverable/binutils-gdb.git] / ld / ldlang.c
index 2d1f5d50823f1c36fc0b871c8b49fab8559ef276..b180edeb34a3be06f66fb3b0c181d5a56d6dc25d 100644 (file)
@@ -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))
@@ -60,6 +61,7 @@ static const char *current_target;
 static const char *output_target;
 static lang_statement_list_type statement_list;
 static struct lang_phdr *lang_phdr_list;
+static struct bfd_hash_table lang_definedness_table;
 
 /* Forward declarations.  */
 static void exp_init_os (etree_type *);
@@ -67,6 +69,8 @@ static bfd_boolean wildcardp (const char *);
 static lang_input_statement_type *lookup_name (const char *);
 static bfd_boolean load_symbols (lang_input_statement_type *,
                                 lang_statement_list_type *);
+static struct bfd_hash_entry *lang_definedness_newfunc
+ (struct bfd_hash_entry *, struct bfd_hash_table *, const char *);
 static void insert_undefined (const char *);
 static void print_statement (lang_statement_union_type *,
                             lang_output_section_statement_type *);
@@ -95,6 +99,7 @@ bfd_boolean delete_output_file_on_failure = FALSE;
 struct lang_nocrossrefs *nocrossref_list;
 struct unique_sections *unique_section_list;
 static bfd_boolean ldlang_sysrooted_script = FALSE;
+int lang_statement_iteration = 0;
 
 etree_type *base; /* Relocation base - or null */
 
@@ -477,6 +482,19 @@ lang_init (void)
     lang_output_section_statement_lookup (BFD_ABS_SECTION_NAME);
 
   abs_output_section->bfd_section = bfd_abs_section_ptr;
+
+  /* The value "3" is ad-hoc, somewhat related to the expected number of
+     DEFINED expressions in a linker script.  For most default linker
+     scripts, there are none.  Why a hash table then?  Well, it's somewhat
+     simpler to re-use working machinery than using a linked list in terms
+     of code-complexity here in ld, besides the initialization which just
+     looks like other code here.  */
+  if (bfd_hash_table_init_n (&lang_definedness_table,
+                            lang_definedness_newfunc, 3) != TRUE)
+    einfo (_("%P%F: out of memory during initialization"));
+
+  /* Callers of exp_fold_tree need to increment this.  */
+  lang_statement_iteration = 0;
 }
 
 /*----------------------------------------------------------------------
@@ -487,13 +505,19 @@ lang_init (void)
   We maintain a list of all the regions here.
 
   If no regions are specified in the script, then the default is used
-  which is created when looked up to be the entire data space.  */
+  which is created when looked up to be the entire data space.
+
+  If create is true we are creating a region inside a MEMORY block.
+  In this case it is probably an error to create a region that has
+  already been created.  If we are not inside a MEMORY block it is
+  dubious to use an undeclared region name (except DEFAULT_MEMORY_REGION)
+  and so we issue a warning.  */
 
 static lang_memory_region_type *lang_memory_region_list;
 static lang_memory_region_type **lang_memory_region_list_tail = &lang_memory_region_list;
 
 lang_memory_region_type *
-lang_memory_region_lookup (const char *const name)
+lang_memory_region_lookup (const char *const name, bfd_boolean create)
 {
   lang_memory_region_type *p;
   lang_memory_region_type *new;
@@ -503,10 +527,12 @@ lang_memory_region_lookup (const char *const name)
     return NULL;
 
   for (p = lang_memory_region_list; p != NULL; p = p->next)
-    {
-      if (strcmp (p->name, name) == 0)
+    if (strcmp (p->name, name) == 0)
+      {
+       if (create)
+         einfo (_("%P:%S: warning: redeclaration of memory region '%s'\n"), name);
        return p;
-    }
+      }
 
 #if 0
   /* This code used to always use the first region in the list as the
@@ -515,13 +541,16 @@ lang_memory_region_lookup (const char *const name)
      NOLOAD sections to work reasonably without requiring a region.
      People should specify what region they mean, if they really want
      a region.  */
-  if (strcmp (name, "*default*") == 0)
+  if (strcmp (name, DEFAULT_MEMORY_REGION) == 0)
     {
       if (lang_memory_region_list != NULL)
        return lang_memory_region_list;
     }
 #endif
 
+  if (!create && strcmp (name, DEFAULT_MEMORY_REGION))
+    einfo (_("%P:%S: warning: memory region %s not declared\n"), name);
+
   new = stat_alloc (sizeof (lang_memory_region_type));
 
   new->name = xstrdup (name);
@@ -558,7 +587,7 @@ lang_memory_default (asection *section)
          return p;
        }
     }
-  return lang_memory_region_lookup ("*default*");
+  return lang_memory_region_lookup (DEFAULT_MEMORY_REGION, FALSE);
 }
 
 lang_output_section_statement_type *
@@ -1867,6 +1896,85 @@ lang_reasonable_defaults (void)
 #endif
 }
 
+/* Add a symbol to a hash of symbols used in DEFINED (NAME) expressions.  */
+
+void
+lang_track_definedness (const char *name)
+{
+  if (bfd_hash_lookup (&lang_definedness_table, name, TRUE, FALSE) == NULL)
+    einfo (_("%P%F: bfd_hash_lookup failed creating symbol %s\n"), name);
+}
+
+/* New-function for the definedness hash table.  */
+
+static struct bfd_hash_entry *
+lang_definedness_newfunc (struct bfd_hash_entry *entry,
+                         struct bfd_hash_table *table ATTRIBUTE_UNUSED,
+                         const char *name ATTRIBUTE_UNUSED)
+{
+  struct lang_definedness_hash_entry *ret
+    = (struct lang_definedness_hash_entry *) entry;
+
+  if (ret == NULL)
+    ret = (struct lang_definedness_hash_entry *)
+      bfd_hash_allocate (table, sizeof (struct lang_definedness_hash_entry));
+
+  if (ret == NULL)
+    einfo (_("%P%F: bfd_hash_allocate failed creating symbol %s\n"), name);
+
+  ret->iteration = -1;
+  return &ret->root;
+}
+
+/* Return the iteration when the definition of NAME was last updated.  A
+   value of -1 means that the symbol is not defined in the linker script
+   or the command line, but may be defined in the linker symbol table.  */
+
+int
+lang_symbol_definition_iteration (const char *name)
+{
+  struct lang_definedness_hash_entry *defentry
+    = (struct lang_definedness_hash_entry *)
+    bfd_hash_lookup (&lang_definedness_table, name, FALSE, FALSE);
+
+  /* We've already created this one on the presence of DEFINED in the
+     script, so it can't be NULL unless something is borked elsewhere in
+     the code.  */
+  if (defentry == NULL)
+    FAIL ();
+
+  return defentry->iteration;
+}
+
+/* Update the definedness state of NAME.  */
+
+void
+lang_update_definedness (const char *name, struct bfd_link_hash_entry *h)
+{
+  struct lang_definedness_hash_entry *defentry
+    = (struct lang_definedness_hash_entry *)
+    bfd_hash_lookup (&lang_definedness_table, name, FALSE, FALSE);
+
+  /* We don't keep track of symbols not tested with DEFINED.  */
+  if (defentry == NULL)
+    return;
+
+  /* If the symbol was already defined, and not from an earlier statement
+     iteration, don't update the definedness iteration, because that'd
+     make the symbol seem defined in the linker script at this point, and
+     it wasn't; it was defined in some object.  If we do anyway, DEFINED
+     would start to yield false before this point and the construct "sym =
+     DEFINED (sym) ? sym : X;" would change sym to X despite being defined
+     in an object.  */
+  if (h->type != bfd_link_hash_undefined
+      && h->type != bfd_link_hash_common
+      && h->type != bfd_link_hash_new
+      && defentry->iteration == -1)
+    return;
+
+  defentry->iteration = lang_statement_iteration;
+}
+
 /* Add the supplied name to the symbol table as an undefined reference.
    This is a two step process as the symbol table doesn't even exist at
    the time the ld command line is processed.  First we put the name
@@ -2793,7 +2901,7 @@ lang_size_sections_1
                        || (((bfd_get_section_flags (output_bfd, os->bfd_section)
                              & (SEC_ALLOC | SEC_LOAD)) != 0)
                            && os->region->name[0] == '*'
-                           && strcmp (os->region->name, "*default*") == 0))
+                           && strcmp (os->region->name, DEFAULT_MEMORY_REGION) == 0))
                      {
                        os->region = lang_memory_default (os->bfd_section);
                      }
@@ -2806,10 +2914,10 @@ lang_size_sections_1
                            & SEC_NEVER_LOAD) == 0
                        && ! link_info.relocatable
                        && check_regions
-                       && strcmp (os->region->name, "*default*") == 0
+                       && strcmp (os->region->name, DEFAULT_MEMORY_REGION) == 0
                        && lang_memory_region_list != NULL
                        && (strcmp (lang_memory_region_list->name,
-                                   "*default*") != 0
+                                   DEFAULT_MEMORY_REGION) != 0
                            || lang_memory_region_list->next != NULL))
                      {
                        /* By default this is an error rather than just a
@@ -3064,7 +3172,7 @@ lang_size_sections_1
                  {
                    /* If we don't have an output section, then just adjust
                       the default memory address.  */
-                   lang_memory_region_lookup ("*default*")->current = newdot;
+                   lang_memory_region_lookup (DEFAULT_MEMORY_REGION, FALSE)->current = newdot;
                  }
                else
                  {
@@ -3131,6 +3239,10 @@ lang_size_sections
    bfd_boolean check_regions)
 {
   bfd_vma result;
+  asection *o;
+
+  /* Callers of exp_fold_tree need to increment this.  */
+  lang_statement_iteration++;
 
   exp_data_seg.phase = exp_dataseg_none;
   result = lang_size_sections_1 (s, output_section_statement, prev, fill,
@@ -3154,11 +3266,21 @@ lang_size_sections
        }
     }
 
+  /* Some backend relaxers want to refer to the output section size.  Give
+     them a section size that does not change on the next call while they
+     relax.  We can't set this at top because lang_reset_memory_regions
+     which is called before we get here, sets _raw_size to 0 on relaxing
+     rounds.  */
+  for (o = output_bfd->sections; o != NULL; o = o->next)
+    o->_cooked_size = o->_raw_size;
+
   return result;
 }
 
-bfd_vma
-lang_do_assignments
+/* Worker function for lang_do_assignments.  Recursiveness goes here.  */
+
+static bfd_vma
+lang_do_assignments_1
   (lang_statement_union_type *s,
    lang_output_section_statement_type *output_section_statement,
    fill_type *fill,
@@ -3172,10 +3294,10 @@ lang_do_assignments
       switch (s->header.type)
        {
        case lang_constructors_statement_enum:
-         dot = lang_do_assignments (constructor_list.head,
-                                    output_section_statement,
-                                    fill,
-                                    dot);
+         dot = lang_do_assignments_1 (constructor_list.head,
+                                      output_section_statement,
+                                      fill,
+                                      dot);
          break;
 
        case lang_output_section_statement_enum:
@@ -3186,8 +3308,8 @@ lang_do_assignments
            if (os->bfd_section != NULL)
              {
                dot = os->bfd_section->vma;
-               (void) lang_do_assignments (os->children.head, os,
-                                           os->fill, dot);
+               (void) lang_do_assignments_1 (os->children.head, os,
+                                             os->fill, dot);
                dot = os->bfd_section->vma + os->bfd_section->_raw_size / opb;
 
              }
@@ -3206,9 +3328,9 @@ lang_do_assignments
          break;
        case lang_wild_statement_enum:
 
-         dot = lang_do_assignments (s->wild_statement.children.head,
-                                    output_section_statement,
-                                    fill, dot);
+         dot = lang_do_assignments_1 (s->wild_statement.children.head,
+                                      output_section_statement,
+                                      fill, dot);
 
          break;
 
@@ -3301,9 +3423,9 @@ lang_do_assignments
          break;
 
        case lang_group_statement_enum:
-         dot = lang_do_assignments (s->group_statement.children.head,
-                                    output_section_statement,
-                                    fill, dot);
+         dot = lang_do_assignments_1 (s->group_statement.children.head,
+                                      output_section_statement,
+                                      fill, dot);
 
          break;
 
@@ -3318,6 +3440,18 @@ lang_do_assignments
   return dot;
 }
 
+bfd_vma
+lang_do_assignments (lang_statement_union_type *s,
+                    lang_output_section_statement_type
+                    *output_section_statement,
+                    fill_type *fill,
+                    bfd_vma dot)
+{
+  /* Callers of exp_fold_tree need to increment this.  */
+  lang_statement_iteration++;
+  lang_do_assignments_1 (s, output_section_statement, fill, dot);
+}
+
 /* Fix any .startof. or .sizeof. symbols.  When the assemblers see the
    operator .startof. (section_name), it produces an undefined symbol
    .startof.section_name.  Similarly, when it sees
@@ -3445,6 +3579,8 @@ lang_finish (void)
            }
        }
     }
+
+  bfd_hash_table_free (&lang_definedness_table);
 }
 
 /* This is a small function used when we want to ignore errors from
@@ -4340,10 +4476,11 @@ lang_float (bfd_boolean maybe)
 /* Work out the load- and run-time regions from a script statement, and
    store them in *LMA_REGION and *REGION respectively.
 
-   MEMSPEC is the name of the run-time region, or "*default*" if the
-   statement didn't specify one.  LMA_MEMSPEC is the name of the
-   load-time region, or null if the statement didn't specify one.
-   HAVE_LMA_P is TRUE if the statement had an explicit load address.
+   MEMSPEC is the name of the run-time region, or the value of
+   DEFAULT_MEMORY_REGION if the statement didn't specify one.
+   LMA_MEMSPEC is the name of the load-time region, or null if the
+   statement didn't specify one.HAVE_LMA_P is TRUE if the statement
+   had an explicit load address.
 
    It is an error to specify both a load region and a load address.  */
 
@@ -4354,14 +4491,14 @@ lang_get_regions (struct memory_region_struct **region,
                  const char *lma_memspec,
                  int have_lma_p)
 {
-  *lma_region = lang_memory_region_lookup (lma_memspec);
+  *lma_region = lang_memory_region_lookup (lma_memspec, FALSE);
 
   /* If no runtime region has been given, but the load region has
      been, use the load region.  */
-  if (lma_memspec != 0 && strcmp (memspec, "*default*") == 0)
+  if (lma_memspec != 0 && strcmp (memspec, DEFAULT_MEMORY_REGION) == 0)
     *region = *lma_region;
   else
-    *region = lang_memory_region_lookup (memspec);
+    *region = lang_memory_region_lookup (memspec, FALSE);
 
   if (have_lma_p && lma_memspec != 0)
     einfo (_("%X%P:%S: section has both a load address and a load region\n"));
@@ -4725,10 +4862,11 @@ lang_leave_overlay_section (fill_type *fill,
 
   name = current_section->name;
 
-  /* For now, assume that "*default*" is the run-time memory region and
-     that no load-time region has been specified.  It doesn't really
-     matter what we say here, since lang_leave_overlay will override it.  */
-  lang_leave_output_section_statement (fill, "*default*", phdrs, 0);
+  /* For now, assume that DEFAULT_MEMORY_REGION is the run-time memory
+     region and that no load-time region has been specified.  It doesn't
+     really matter what we say here, since lang_leave_overlay will
+     override it.  */
+  lang_leave_output_section_statement (fill, DEFAULT_MEMORY_REGION, phdrs, 0);
 
   /* Define the magic symbols.  */
 
@@ -4836,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.  */
@@ -4911,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);
@@ -4937,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;
 }
 
@@ -4953,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.  */
 
@@ -4980,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);
        }
     }
 
This page took 0.041956 seconds and 4 git commands to generate.