sim: dv-core: add hw_detach_address method [PR sim/25211]
[binutils-gdb.git] / ld / ldlang.c
index 846dcdf29184454a5bf9186acc691cdd4ed11858..7829f86dfec6fb41400a28433bfe9e7c0f08bdbb 100644 (file)
@@ -59,6 +59,7 @@
 /* Local variables.  */
 static struct obstack stat_obstack;
 static struct obstack map_obstack;
+static struct obstack pt_obstack;
 
 #define obstack_chunk_alloc xmalloc
 #define obstack_chunk_free free
@@ -80,6 +81,9 @@ static void exp_init_os (etree_type *);
 static lang_input_statement_type *lookup_name (const char *);
 static void insert_undefined (const char *);
 static bool sort_def_symbol (struct bfd_link_hash_entry *, void *);
+static lang_statement_union_type *new_statement (enum statement_enum type,
+                                               size_t size,
+                                               lang_statement_list_type *list);
 static void print_statement (lang_statement_union_type *,
                             lang_output_section_statement_type *);
 static void print_statement_list (lang_statement_union_type *,
@@ -219,23 +223,39 @@ spec_match (const struct wildcard_spec *spec, const char *name)
   size_t nl = spec->namelen;
   size_t pl = spec->prefixlen;
   size_t sl = spec->suffixlen;
+  size_t inputlen = strlen (name);
   int r;
-  if (pl && (r = memcmp (spec->name, name, pl)))
-    return r;
+
+  if (pl)
+    {
+      if (inputlen < pl)
+       return 1;
+
+      r = memcmp (spec->name, name, pl);
+      if (r)
+       return r;
+    }
+
   if (sl)
     {
-      size_t inputlen = strlen (name);
       if (inputlen < sl)
        return 1;
+
       r = memcmp (spec->name + nl - sl, name + inputlen - sl, sl);
       if (r)
        return r;
     }
+
   if (nl == pl + sl + 1 && spec->name[pl] == '*')
     return 0;
-  else if (nl > pl)
+
+  if (nl > pl)
     return fnmatch (spec->name + pl, name + pl, 0);
-  return name[nl];
+
+  if (inputlen >= nl)
+    return name[nl];
+
+  return 0;
 }
 
 static char *
@@ -364,98 +384,84 @@ walk_wild_file_in_exclude_list (struct name_list *exclude_list,
   return false;
 }
 
-/* Try processing a section against a wildcard.  This just calls
-   the callback unless the filename exclusion list is present
-   and excludes the file.  It's hardly ever present so this
-   function is very fast.  */
+/* Add SECTION (from input FILE) to the list of matching sections
+   within PTR (the matching wildcard is SEC).  */
 
 static void
-walk_wild_consider_section (lang_wild_statement_type *ptr,
-                           lang_input_statement_type *file,
-                           asection *s,
-                           struct wildcard_list *sec,
-                           callback_t callback,
-                           void *data)
-{
-  /* Don't process sections from files which were excluded.  */
-  if (walk_wild_file_in_exclude_list (sec->spec.exclude_name_list, file))
-    return;
-
-  (*callback) (ptr, sec, s, file, data);
+add_matching_section (lang_wild_statement_type *ptr,
+                     struct wildcard_list *sec,
+                     asection *section,
+                     lang_input_statement_type *file)
+{
+  lang_input_matcher_type *new_section;
+  /* Add a section reference to the list.  */
+  new_section = new_stat (lang_input_matcher, &ptr->matching_sections);
+  new_section->section = section;
+  new_section->pattern = sec;
+  new_section->input_stmt = file;
 }
 
-/* Lowest common denominator routine that can handle everything correctly,
-   but slowly.  */
+/* Process section S (from input file FILE) in relation to wildcard
+   statement PTR.  We already know that a prefix of the name of S matches
+   some wildcard in PTR's wildcard list.  Here we check if the filename
+   matches as well (if it's specified) and if any of the wildcards in fact
+   does match.  */
 
 static void
-walk_wild_section_general (lang_wild_statement_type *ptr,
-                          lang_input_statement_type *file,
-                          callback_t callback,
-                          void *data)
+walk_wild_section_match (lang_wild_statement_type *ptr,
+                        lang_input_statement_type *file,
+                        asection *s)
 {
-  asection *s;
   struct wildcard_list *sec;
+  const char *file_spec = ptr->filename;
+  char *p;
 
-  for (s = file->the_bfd->sections; s != NULL; s = s->next)
+  /* Check if filenames match.  */
+  if (file_spec == NULL)
+    ;
+  else if ((p = archive_path (file_spec)) != NULL)
     {
-      sec = ptr->section_list;
-      if (sec == NULL)
-       (*callback) (ptr, sec, s, file, data);
-
-      while (sec != NULL)
-       {
-         bool skip = false;
-
-         if (sec->spec.name != NULL)
-           {
-             const char *sname = bfd_section_name (s);
-
-             skip = spec_match (&sec->spec, sname) != 0;
-           }
-
-         if (!skip)
-           walk_wild_consider_section (ptr, file, s, sec, callback, data);
-
-         sec = sec->next;
-       }
+      if (!input_statement_is_archive_path (file_spec, p, file))
+       return;
     }
-}
-
-/* Routines to find a single section given its name.  If there's more
-   than one section with that name, we report that.  */
-
-typedef struct
-{
-  asection *found_section;
-  bool multiple_sections_found;
-} section_iterator_callback_data;
-
-static bool
-section_iterator_callback (bfd *abfd ATTRIBUTE_UNUSED, asection *s, void *data)
-{
-  section_iterator_callback_data *d = (section_iterator_callback_data *) data;
-
-  if (d->found_section != NULL)
+  else if (wildcardp (file_spec))
     {
-      d->multiple_sections_found = true;
-      return true;
+      if (fnmatch (file_spec, file->filename, 0) != 0)
+       return;
+    }
+  else
+    {
+      lang_input_statement_type *f;
+      /* Perform the iteration over a single file.  */
+      f = lookup_name (file_spec);
+      if (f != file)
+       return;
     }
 
-  d->found_section = s;
-  return false;
-}
+  /* If filename is excluded we're done.  */
+  if (walk_wild_file_in_exclude_list (ptr->exclude_name_list, file))
+    return;
 
-static asection *
-find_section (lang_input_statement_type *file,
-             struct wildcard_list *sec,
-             bool *multiple_sections_found)
-{
-  section_iterator_callback_data cb_data = { NULL, false };
+  /* Check section name against each wildcard spec.  If there's no
+     wildcard all sections match.  */
+  sec = ptr->section_list;
+  if (sec == NULL)
+    add_matching_section (ptr, sec, s, file);
+  else
+    {
+      const char *sname = bfd_section_name (s);
+      for (; sec != NULL; sec = sec->next)
+       {
+         if (sec->spec.name != NULL
+             && spec_match (&sec->spec, sname) != 0)
+           continue;
 
-  bfd_get_section_by_name_if (file->the_bfd, sec->spec.name,
-                             section_iterator_callback, &cb_data);
-  *multiple_sections_found = cb_data.multiple_sections_found;
-  return cb_data.found_section;
+         /* Don't process sections from files which were excluded.  */
+         if (!walk_wild_file_in_exclude_list (sec->spec.exclude_name_list,
+                                              file))
+           add_matching_section (ptr, sec, s, file);
+       }
+    }
 }
 
 /* Return the numerical value of the init_priority attribute from
@@ -705,217 +711,143 @@ output_section_callback_tree_to_list (lang_wild_statement_type *ptr,
   free (tree);
 }
 
-/* Specialized, optimized routines for handling different kinds of
-   wildcards */
-
-static void
-walk_wild_section_specs1_wild0 (lang_wild_statement_type *ptr,
-                               lang_input_statement_type *file,
-                               callback_t callback,
-                               void *data)
-{
-  /* We can just do a hash lookup for the section with the right name.
-     But if that lookup discovers more than one section with the name
-     (should be rare), we fall back to the general algorithm because
-     we would otherwise have to sort the sections to make sure they
-     get processed in the bfd's order.  */
-  bool multiple_sections_found;
-  struct wildcard_list *sec0 = ptr->handler_data[0];
-  asection *s0 = find_section (file, sec0, &multiple_sections_found);
-
-  if (multiple_sections_found)
-    walk_wild_section_general (ptr, file, callback, data);
-  else if (s0)
-    walk_wild_consider_section (ptr, file, s0, sec0, callback, data);
-}
+\f
+/* Sections are matched against wildcard statements via a prefix tree.
+   The prefix tree holds prefixes of all matching patterns (up to the first
+   wildcard character), and the wild statement from which those patterns
+   came.  When matching a section name against the tree we're walking through
+   the tree character by character.  Each statement we hit is one that
+   potentially matches.  This is checked by actually going through the
+   (glob) matching routines.
+
+   When the section name turns out to actually match we record that section
+   in the wild statements list of matching sections.  */
+
+/* A prefix can be matched by multiple statement, so we need a list of them.  */
+struct wild_stmt_list
+{
+  lang_wild_statement_type *stmt;
+  struct wild_stmt_list *next;
+};
 
-static void
-walk_wild_section_specs1_wild1 (lang_wild_statement_type *ptr,
-                               lang_input_statement_type *file,
-                               callback_t callback,
-                               void *data)
+/* The prefix tree itself.  */
+struct prefixtree
 {
-  asection *s;
-  struct wildcard_list *wildsec0 = ptr->handler_data[0];
+  /* The list of all children (linked via .next).  */
+  struct prefixtree *child;
+  struct prefixtree *next;
+  /* This tree node is responsible for the prefix of parent plus 'c'.  */
+  char c;
+  /* The statements that potentially can match this prefix.  */
+  struct wild_stmt_list *stmt;
+};
 
-  for (s = file->the_bfd->sections; s != NULL; s = s->next)
-    {
-      const char *sname = bfd_section_name (s);
-      bool skip = !match_simple_wild (wildsec0->spec.name, sname);
+/* We always have a root node in the prefix tree.  It corresponds to the
+   empty prefix.  E.g. a glob like "*" would sit in this root.  */
+static struct prefixtree the_root, *ptroot = &the_root;
 
-      if (!skip)
-       walk_wild_consider_section (ptr, file, s, wildsec0, callback, data);
-    }
-}
+/* Given a prefix tree in *TREE, corresponding to prefix P, find or
+   INSERT the tree node corresponding to prefix P+C.  */
 
-static void
-walk_wild_section_specs2_wild1 (lang_wild_statement_type *ptr,
-                               lang_input_statement_type *file,
-                               callback_t callback,
-                               void *data)
+static struct prefixtree *
+get_prefix_tree (struct prefixtree **tree, char c, bool insert)
 {
-  asection *s;
-  struct wildcard_list *sec0 = ptr->handler_data[0];
-  struct wildcard_list *wildsec1 = ptr->handler_data[1];
-  bool multiple_sections_found;
-  asection *s0 = find_section (file, sec0, &multiple_sections_found);
-
-  if (multiple_sections_found)
-    {
-      walk_wild_section_general (ptr, file, callback, data);
-      return;
-    }
+  struct prefixtree *t;
+  for (t = *tree; t; t = t->next)
+    if (t->c == c)
+      return t;
+  if (!insert)
+    return NULL;
+  t = (struct prefixtree *) obstack_alloc (&pt_obstack, sizeof *t);
+  t->child = NULL;
+  t->next = *tree;
+  t->c = c;
+  t->stmt = NULL;
+  *tree = t;
+  return t;
+}
 
-  /* Note that if the section was not found, s0 is NULL and
-     we'll simply never succeed the s == s0 test below.  */
-  for (s = file->the_bfd->sections; s != NULL; s = s->next)
-    {
-      /* Recall that in this code path, a section cannot satisfy more
-        than one spec, so if s == s0 then it cannot match
-        wildspec1.  */
-      if (s == s0)
-       walk_wild_consider_section (ptr, file, s, sec0, callback, data);
-      else
-       {
-         const char *sname = bfd_section_name (s);
-         bool skip = !match_simple_wild (wildsec1->spec.name, sname);
+/* Add STMT to the set of statements that can be matched by the prefix
+   corresponding to prefix tree T.  */
 
-         if (!skip)
-           walk_wild_consider_section (ptr, file, s, wildsec1, callback,
-                                       data);
-       }
-    }
+static void
+pt_add_stmt (struct prefixtree *t, lang_wild_statement_type *stmt)
+{
+  struct wild_stmt_list *sl, **psl;
+  sl = (struct wild_stmt_list *) obstack_alloc (&pt_obstack, sizeof *sl);
+  sl->stmt = stmt;
+  sl->next = NULL;
+  psl = &t->stmt;
+  while (*psl)
+    psl = &(*psl)->next;
+  *psl = sl;
 }
 
+/* Insert STMT into the global prefix tree.  */
+
 static void
-walk_wild_section_specs3_wild2 (lang_wild_statement_type *ptr,
-                               lang_input_statement_type *file,
-                               callback_t callback,
-                               void *data)
+insert_prefix_tree (lang_wild_statement_type *stmt)
 {
-  asection *s;
-  struct wildcard_list *sec0 = ptr->handler_data[0];
-  struct wildcard_list *wildsec1 = ptr->handler_data[1];
-  struct wildcard_list *wildsec2 = ptr->handler_data[2];
-  bool multiple_sections_found;
-  asection *s0 = find_section (file, sec0, &multiple_sections_found);
+  struct wildcard_list *sec;
+  struct prefixtree *t;
 
-  if (multiple_sections_found)
+  if (!stmt->section_list)
     {
-      walk_wild_section_general (ptr, file, callback, data);
+      /* If we have no section_list (no wildcards in the wild STMT),
+        then every section name will match, so add this to the root.  */
+      pt_add_stmt (ptroot, stmt);
       return;
     }
 
-  for (s = file->the_bfd->sections; s != NULL; s = s->next)
+  for (sec = stmt->section_list; sec; sec = sec->next)
     {
-      if (s == s0)
-       walk_wild_consider_section (ptr, file, s, sec0, callback, data);
-      else
+      const char *name = sec->spec.name ? sec->spec.name : "*";
+      char c;
+      t = ptroot;
+      for (; (c = *name); name++)
        {
-         const char *sname = bfd_section_name (s);
-         bool skip = !match_simple_wild (wildsec1->spec.name, sname);
-
-         if (!skip)
-           walk_wild_consider_section (ptr, file, s, wildsec1, callback, data);
-         else
-           {
-             skip = !match_simple_wild (wildsec2->spec.name, sname);
-             if (!skip)
-               walk_wild_consider_section (ptr, file, s, wildsec2, callback,
-                                           data);
-           }
+         if (c == '*' || c == '[' || c == '?')
+           break;
+         t = get_prefix_tree (&t->child, c, true);
        }
+      /* If we hit a glob character, the matching prefix is what we saw
+        until now.  If we hit the end of pattern (hence it's no glob) then
+        we can do better: we only need to record a match when a section name
+        completely matches, not merely a prefix, so record the trailing 0
+        as well.  */
+      if (!c)
+       t = get_prefix_tree (&t->child, 0, true);
+      pt_add_stmt (t, stmt);
     }
 }
 
+/* Dump T indented by INDENT spaces.  */
+
 static void
-walk_wild_section_specs4_wild2 (lang_wild_statement_type *ptr,
-                               lang_input_statement_type *file,
-                               callback_t callback,
-                               void *data)
+debug_prefix_tree_rec (struct prefixtree *t, int indent)
 {
-  asection *s;
-  struct wildcard_list *sec0 = ptr->handler_data[0];
-  struct wildcard_list *sec1 = ptr->handler_data[1];
-  struct wildcard_list *wildsec2 = ptr->handler_data[2];
-  struct wildcard_list *wildsec3 = ptr->handler_data[3];
-  bool multiple_sections_found;
-  asection *s0 = find_section (file, sec0, &multiple_sections_found), *s1;
-
-  if (multiple_sections_found)
-    {
-      walk_wild_section_general (ptr, file, callback, data);
-      return;
-    }
-
-  s1 = find_section (file, sec1, &multiple_sections_found);
-  if (multiple_sections_found)
-    {
-      walk_wild_section_general (ptr, file, callback, data);
-      return;
-    }
-
-  for (s = file->the_bfd->sections; s != NULL; s = s->next)
+  for (; t; t = t->next)
     {
-      if (s == s0)
-       walk_wild_consider_section (ptr, file, s, sec0, callback, data);
-      else
-       if (s == s1)
-         walk_wild_consider_section (ptr, file, s, sec1, callback, data);
-       else
-         {
-           const char *sname = bfd_section_name (s);
-           bool skip = !match_simple_wild (wildsec2->spec.name, sname);
-
-           if (!skip)
-             walk_wild_consider_section (ptr, file, s, wildsec2, callback,
-                                         data);
-           else
-             {
-               skip = !match_simple_wild (wildsec3->spec.name, sname);
-               if (!skip)
-                 walk_wild_consider_section (ptr, file, s, wildsec3,
-                                             callback, data);
-             }
-         }
+      struct wild_stmt_list *sl;
+      printf ("%*s %c", indent, "", t->c);
+      for (sl = t->stmt; sl; sl = sl->next)
+       {
+         struct wildcard_list *curr;
+         printf (" %p ", sl->stmt);
+         for (curr = sl->stmt->section_list; curr; curr = curr->next)
+           printf ("%s ", curr->spec.name ? curr->spec.name : "*");
+       }
+      printf ("\n");
+      debug_prefix_tree_rec (t->child, indent + 2);
     }
 }
 
-static void
-walk_wild_section (lang_wild_statement_type *ptr,
-                  lang_input_statement_type *file,
-                  callback_t callback,
-                  void *data)
-{
-  if (file->flags.just_syms)
-    return;
-
-  (*ptr->walk_wild_section_handler) (ptr, file, callback, data);
-}
-
-/* Returns TRUE when name1 is a wildcard spec that might match
-   something name2 can match.  We're conservative: we return FALSE
-   only if the prefixes of name1 and name2 are different up to the
-   first wildcard character.  */
+/* Dump the global prefix tree.  */
 
-static bool
-wild_spec_can_overlap (const char *name1, const char *name2)
+static void
+debug_prefix_tree (void)
 {
-  size_t prefix1_len = strcspn (name1, "?*[");
-  size_t prefix2_len = strcspn (name2, "?*[");
-  size_t min_prefix_len;
-
-  /* Note that if there is no wildcard character, then we treat the
-     terminating 0 as part of the prefix.  Thus ".text" won't match
-     ".text." or ".text.*", for example.  */
-  if (name1[prefix1_len] == '\0')
-    prefix1_len++;
-  if (name2[prefix2_len] == '\0')
-    prefix2_len++;
-
-  min_prefix_len = prefix1_len < prefix2_len ? prefix1_len : prefix2_len;
-
-  return memcmp (name1, name2, min_prefix_len) == 0;
+  debug_prefix_tree_rec (ptroot, 2);
 }
 
 /* Like strcspn() but start to look from the end to beginning of
@@ -936,23 +868,14 @@ rstrcspn (const char *s, const char *reject)
   return sufflen;
 }
 
-/* Select specialized code to handle various kinds of wildcard
-   statements.  */
+/* Analyze the wildcards in wild statement PTR to setup various
+   things for quick matching.  */
 
 static void
 analyze_walk_wild_section_handler (lang_wild_statement_type *ptr)
 {
-  int sec_count = 0;
-  int wild_name_count = 0;
   struct wildcard_list *sec;
-  int signature;
-  int data_counter;
-
-  ptr->walk_wild_section_handler = walk_wild_section_general;
-  ptr->handler_data[0] = NULL;
-  ptr->handler_data[1] = NULL;
-  ptr->handler_data[2] = NULL;
-  ptr->handler_data[3] = NULL;
+
   ptr->tree = NULL;
   ptr->rightmost = &ptr->tree;
 
@@ -969,233 +892,93 @@ analyze_walk_wild_section_handler (lang_wild_statement_type *ptr)
        sec->spec.namelen = sec->spec.prefixlen = sec->spec.suffixlen = 0;
     }
 
-  /* Count how many wildcard_specs there are, and how many of those
-     actually use wildcards in the name.  Also, bail out if any of the
-     wildcard names are NULL. (Can this actually happen?
-     walk_wild_section used to test for it.)  And bail out if any
-     of the wildcards are more complex than a simple string
-     ending in a single '*'.  */
-  for (sec = ptr->section_list; sec != NULL; sec = sec->next)
-    {
-      ++sec_count;
-      if (sec->spec.name == NULL)
-       return;
-      if (wildcardp (sec->spec.name))
-       {
-         ++wild_name_count;
-         if (!is_simple_wild (sec->spec.name))
-           return;
-       }
-    }
-
-  /* The zero-spec case would be easy to optimize but it doesn't
-     happen in practice.  Likewise, more than 4 specs doesn't
-     happen in practice.  */
-  if (sec_count == 0 || sec_count > 4)
-    return;
-
-  /* Check that no two specs can match the same section.  */
-  for (sec = ptr->section_list; sec != NULL; sec = sec->next)
-    {
-      struct wildcard_list *sec2;
-      for (sec2 = sec->next; sec2 != NULL; sec2 = sec2->next)
-       {
-         if (wild_spec_can_overlap (sec->spec.name, sec2->spec.name))
-           return;
-       }
-    }
-
-  signature = (sec_count << 8) + wild_name_count;
-  switch (signature)
-    {
-    case 0x0100:
-      ptr->walk_wild_section_handler = walk_wild_section_specs1_wild0;
-      break;
-    case 0x0101:
-      ptr->walk_wild_section_handler = walk_wild_section_specs1_wild1;
-      break;
-    case 0x0201:
-      ptr->walk_wild_section_handler = walk_wild_section_specs2_wild1;
-      break;
-    case 0x0302:
-      ptr->walk_wild_section_handler = walk_wild_section_specs3_wild2;
-      break;
-    case 0x0402:
-      ptr->walk_wild_section_handler = walk_wild_section_specs4_wild2;
-      break;
-    default:
-      return;
-    }
-
-  /* Now fill the data array with pointers to the specs, first the
-     specs with non-wildcard names, then the specs with wildcard
-     names.  It's OK to process the specs in different order from the
-     given order, because we've already determined that no section
-     will match more than one spec.  */
-  data_counter = 0;
-  for (sec = ptr->section_list; sec != NULL; sec = sec->next)
-    if (!wildcardp (sec->spec.name))
-      ptr->handler_data[data_counter++] = sec;
-  for (sec = ptr->section_list; sec != NULL; sec = sec->next)
-    if (wildcardp (sec->spec.name))
-      ptr->handler_data[data_counter++] = sec;
+  insert_prefix_tree (ptr);
 }
 
-/* Handle a wild statement for a single file F.  */
+/* Match all sections from FILE against the global prefix tree,
+   and record them into each wild statement that has a match.  */
 
 static void
-walk_wild_file (lang_wild_statement_type *s,
-               lang_input_statement_type *f,
-               callback_t callback,
-               void *data)
+resolve_wild_sections (lang_input_statement_type *file)
 {
-  if (walk_wild_file_in_exclude_list (s->exclude_name_list, f))
+  asection *s;
+
+  if (file->flags.just_syms)
     return;
 
-  if (f->the_bfd == NULL
-      || !bfd_check_format (f->the_bfd, bfd_archive))
-    walk_wild_section (s, f, callback, data);
-  else
+  for (s = file->the_bfd->sections; s != NULL; s = s->next)
     {
-      bfd *member;
-
-      /* This is an archive file.  We must map each member of the
-        archive separately.  */
-      member = bfd_openr_next_archived_file (f->the_bfd, NULL);
-      while (member != NULL)
+      const char *sname = bfd_section_name (s);
+      char c = 1;
+      struct prefixtree *t = ptroot;
+      //printf (" YYY consider %s of %s\n", sname, file->the_bfd->filename);
+      do
        {
-         /* When lookup_name is called, it will call the add_symbols
-            entry point for the archive.  For each element of the
-            archive which is included, BFD will call ldlang_add_file,
-            which will set the usrdata field of the member to the
-            lang_input_statement.  */
-         if (bfd_usrdata (member) != NULL)
-           walk_wild_section (s, bfd_usrdata (member), callback, data);
-
-         member = bfd_openr_next_archived_file (f->the_bfd, member);
+         if (t->stmt)
+           {
+             struct wild_stmt_list *sl;
+             for (sl = t->stmt; sl; sl = sl->next)
+               {
+                 walk_wild_section_match (sl->stmt, file, s);
+                 //printf ("   ZZZ maybe place into %p\n", sl->stmt);
+               }
+           }
+         if (!c)
+           break;
+         c = *sname++;
+         t = get_prefix_tree (&t->child, c, false);
        }
+      while (t);
     }
 }
 
-static lang_statement_union_type *
-new_statement (enum statement_enum type,
-              size_t size,
-              lang_statement_list_type *list);
-static void
-add_matching_callback (lang_wild_statement_type *ptr,
-                      struct wildcard_list *sec,
-                      asection *section,
-                      lang_input_statement_type *file,
-                      void *data ATTRIBUTE_UNUSED)
-{
-  lang_input_matcher_type *new_section;
-  /* Add a section reference to the list.  */
-  new_section = new_stat (lang_input_matcher, &ptr->matching_sections);
-  new_section->section = section;
-  new_section->pattern = sec;
-  new_section->input_stmt = file;
-}
+/* Match all sections from all input files against the global prefix tree.  */
 
 static void
-walk_wild_resolve (lang_wild_statement_type *s)
+resolve_wilds (void)
 {
-  const char *file_spec = s->filename;
-  char *p;
-
-  if (file_spec == NULL)
-    {
-      /* Perform the iteration over all files in the list.  */
-      LANG_FOR_EACH_INPUT_STATEMENT (f)
-       {
-         //printf("XXX   %s\n", f->filename);
-         walk_wild_file (s, f, add_matching_callback, NULL);
-       }
-    }
-  else if ((p = archive_path (file_spec)) != NULL)
-    {
-      LANG_FOR_EACH_INPUT_STATEMENT (f)
-       {
-         if (input_statement_is_archive_path (file_spec, p, f))
-           walk_wild_file (s, f, add_matching_callback, NULL);
-       }
-    }
-  else if (wildcardp (file_spec))
+  LANG_FOR_EACH_INPUT_STATEMENT (f)
     {
-      LANG_FOR_EACH_INPUT_STATEMENT (f)
+      //printf("XXX   %s\n", f->filename);
+      if (f->the_bfd == NULL
+         || !bfd_check_format (f->the_bfd, bfd_archive))
+       resolve_wild_sections (f);
+      else
        {
-         if (fnmatch (file_spec, f->filename, 0) == 0)
-           walk_wild_file (s, f, add_matching_callback, NULL);
-       }
-    }
-  else
-    {
-      lang_input_statement_type *f;
+         bfd *member;
 
-      /* Perform the iteration over a single file.  */
-      f = lookup_name (file_spec);
-      if (f)
-       walk_wild_file (s, f, add_matching_callback, NULL);
+         /* This is an archive file.  We must map each member of the
+            archive separately.  */
+         member = bfd_openr_next_archived_file (f->the_bfd, NULL);
+         while (member != NULL)
+           {
+             /* When lookup_name is called, it will call the add_symbols
+                entry point for the archive.  For each element of the
+                archive which is included, BFD will call ldlang_add_file,
+                which will set the usrdata field of the member to the
+                lang_input_statement.  */
+             if (bfd_usrdata (member) != NULL)
+               resolve_wild_sections (bfd_usrdata (member));
+
+             member = bfd_openr_next_archived_file (f->the_bfd, member);
+           }
+       }
     }
 }
 
+/* For each input section that matches wild statement S calls
+   CALLBACK with DATA.  */
+
 static void
 walk_wild (lang_wild_statement_type *s, callback_t callback, void *data)
 {
-  const char *file_spec = s->filename;
-  //char *p;
+  lang_statement_union_type *l;
 
-  if (!s->resolved)
+  for (l = s->matching_sections.head; l; l = l->header.next)
     {
-      //printf("XXX %s\n", file_spec ? file_spec : "<null>");
-      walk_wild_resolve (s);
-      s->resolved = true;
-    }
-
-    {
-      lang_statement_union_type *l;
-      for (l = s->matching_sections.head; l; l = l->header.next)
-       {
-         (*callback) (s, l->input_matcher.pattern, l->input_matcher.section, l->input_matcher.input_stmt, data);
-       }
-      return;
+      (*callback) (s, l->input_matcher.pattern, l->input_matcher.section,
+                  l->input_matcher.input_stmt, data);
     }
-
-#if 0
-  if (file_spec == NULL)
-    {
-      /* Perform the iteration over all files in the list.  */
-      LANG_FOR_EACH_INPUT_STATEMENT (f)
-       {
-         printf("XXX   %s\n", f->filename);
-         walk_wild_file (s, f, callback, data);
-       }
-    }
-  else if ((p = archive_path (file_spec)) != NULL)
-    {
-      LANG_FOR_EACH_INPUT_STATEMENT (f)
-       {
-         if (input_statement_is_archive_path (file_spec, p, f))
-           walk_wild_file (s, f, callback, data);
-       }
-    }
-  else if (wildcardp (file_spec))
-    {
-      LANG_FOR_EACH_INPUT_STATEMENT (f)
-       {
-         if (fnmatch (file_spec, f->filename, 0) == 0)
-           walk_wild_file (s, f, callback, data);
-       }
-    }
-  else
-    {
-      lang_input_statement_type *f;
-
-      /* Perform the iteration over a single file.  */
-      f = lookup_name (file_spec);
-      if (f)
-       walk_wild_file (s, f, callback, data);
-    }
-#endif
 }
 
 /* lang_for_each_statement walks the parse tree and calls the provided
@@ -1501,6 +1284,7 @@ void
 lang_init (void)
 {
   obstack_begin (&stat_obstack, 1000);
+  obstack_init (&pt_obstack);
 
   stat_ptr = &statement_list;
 
@@ -8066,6 +7850,22 @@ lang_propagate_lma_regions (void)
     }
 }
 
+static void
+reset_one_wild (lang_statement_union_type *statement)
+{
+  if (statement->header.type == lang_wild_statement_enum)
+    {
+      lang_wild_statement_type *stmt = &statement->wild_statement;
+      lang_list_init (&stmt->matching_sections);
+    }
+}
+
+static void
+reset_resolved_wilds (void)
+{
+  lang_for_each_statement (reset_one_wild);
+}
+
 void
 lang_process (void)
 {
@@ -8269,6 +8069,11 @@ lang_process (void)
   /* Size up the common data.  */
   lang_common ();
 
+  if (0)
+    debug_prefix_tree ();
+
+  resolve_wilds ();
+
   /* Remove unreferenced sections if asked to.  */
   lang_gc_sections ();
 
@@ -8279,6 +8084,12 @@ lang_process (void)
 
   ldemul_after_check_relocs ();
 
+  /* There might have been new sections created (e.g. as result of
+     checking relocs to need a .got, or suchlike), so to properly order
+     them into our lists of matching sections reset them here.  */
+  reset_resolved_wilds ();
+  resolve_wilds ();
+
   /* Update wild statements in case the user gave --sort-section.
      Note how the option might have come after the linker script and
      so couldn't have been set when the wild statements were created.  */
@@ -8432,9 +8243,15 @@ lang_add_wild (struct wildcard_spec *filespec,
   new_stmt->section_list = section_list;
   new_stmt->keep_sections = keep_sections;
   lang_list_init (&new_stmt->children);
-  new_stmt->resolved = false;
   lang_list_init (&new_stmt->matching_sections);
   analyze_walk_wild_section_handler (new_stmt);
+  if (0)
+    {
+      printf ("wild %s(", new_stmt->filename ? new_stmt->filename : "*");
+      for (curr = new_stmt->section_list; curr; curr = curr->next)
+       printf ("%s ", curr->spec.name ? curr->spec.name : "*");
+      printf (")\n");
+    }
 }
 
 void