sim: dv-core: add hw_detach_address method [PR sim/25211]
[binutils-gdb.git] / ld / ldlang.c
index 499a9c7182c6399d2a2dd37303e306d1f9e21600..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 *,
@@ -169,14 +173,91 @@ stat_alloc (size_t size)
   return obstack_alloc (&stat_obstack, size);
 }
 
+/* Code for handling simple wildcards without going through fnmatch,
+   which can be expensive because of charset translations etc.  */
+
+/* A simple wild is a literal string followed by a single '*',
+   where the literal part is at least 4 characters long.  */
+
+static bool
+is_simple_wild (const char *name)
+{
+  size_t len = strcspn (name, "*?[");
+  return len >= 4 && name[len] == '*' && name[len + 1] == '\0';
+}
+
+static bool
+match_simple_wild (const char *pattern, const char *name)
+{
+  /* The first four characters of the pattern are guaranteed valid
+     non-wildcard characters.  So we can go faster.  */
+  if (pattern[0] != name[0] || pattern[1] != name[1]
+      || pattern[2] != name[2] || pattern[3] != name[3])
+    return false;
+
+  pattern += 4;
+  name += 4;
+  while (*pattern != '*')
+    if (*name++ != *pattern++)
+      return false;
+
+  return true;
+}
+
 static int
 name_match (const char *pattern, const char *name)
 {
+  if (is_simple_wild (pattern))
+    return !match_simple_wild (pattern, name);
   if (wildcardp (pattern))
     return fnmatch (pattern, name, 0);
   return strcmp (pattern, name);
 }
 
+/* Given an analyzed wildcard_spec SPEC, match it against NAME,
+   returns zero on a match, non-zero if there's no match.  */
+
+static int
+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)
+    {
+      if (inputlen < pl)
+       return 1;
+
+      r = memcmp (spec->name, name, pl);
+      if (r)
+       return r;
+    }
+
+  if (sl)
+    {
+      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;
+
+  if (nl > pl)
+    return fnmatch (spec->name + pl, name + pl, 0);
+
+  if (inputlen >= nl)
+    return name[nl];
+
+  return 0;
+}
+
 static char *
 ldirname (const char *name)
 {
@@ -303,129 +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 = name_match (sec->spec.name, 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;
-}
-
-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 };
-
-  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;
-}
-
-/* Code for handling simple wildcards without going through fnmatch,
-   which can be expensive because of charset translations etc.  */
-
-/* A simple wild is a literal string followed by a single '*',
-   where the literal part is at least 4 characters long.  */
-
-static bool
-is_simple_wild (const char *name)
-{
-  size_t len = strcspn (name, "*?[");
-  return len >= 4 && name[len] == '*' && name[len + 1] == '\0';
-}
-
-static bool
-match_simple_wild (const char *pattern, const char *name)
-{
-  /* The first four characters of the pattern are guaranteed valid
-     non-wildcard characters.  So we can go faster.  */
-  if (pattern[0] != name[0] || pattern[1] != name[1]
-      || pattern[2] != name[2] || pattern[3] != name[3])
-    return false;
+  /* If filename is excluded we're done.  */
+  if (walk_wild_file_in_exclude_list (ptr->exclude_name_list, file))
+    return;
 
-  pattern += 4;
-  name += 4;
-  while (*pattern != '*')
-    if (*name++ != *pattern++)
-      return 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;
 
-  return true;
+         /* 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
@@ -526,30 +562,92 @@ compare_section (sort_type sort, asection *asec, asection *bsec)
   return ret;
 }
 
-/* Build a Binary Search Tree to sort sections, unlike insertion sort
-   used in wild_sort(). BST is considerably faster if the number of
-   of sections are large.  */
+/* PE puts the sort key in the input statement.  */
+
+static const char *
+sort_filename (bfd *abfd)
+{
+  lang_input_statement_type *is = bfd_usrdata (abfd);
+  if (is->sort_key)
+    return is->sort_key;
+  return bfd_get_filename (abfd);
+}
+
+/* Handle wildcard sorting.  This returns the place in a binary search tree
+   where this FILE:SECTION should be inserted for wild statement WILD where
+   the spec SEC was the matching one.  The tree is later linearized.  */
 
 static lang_section_bst_type **
-wild_sort_fast (lang_wild_statement_type *wild,
-               struct wildcard_list *sec,
-               lang_input_statement_type *file ATTRIBUTE_UNUSED,
-               asection *section)
+wild_sort (lang_wild_statement_type *wild,
+          struct wildcard_list *sec,
+          lang_input_statement_type *file,
+          asection *section)
 {
   lang_section_bst_type **tree;
 
-  tree = &wild->tree;
   if (!wild->filenames_sorted
-      && (sec == NULL || sec->spec.sorted == none))
+      && (sec == NULL || sec->spec.sorted == none
+         || sec->spec.sorted == by_none))
     {
-      /* Append at the right end of tree.  */
-      while (*tree)
-       tree = &((*tree)->right);
-      return tree;
+      /* We might be called even if _this_ spec doesn't need sorting,
+         in which case we simply append at the right end of tree.  */
+      return wild->rightmost;
     }
 
+  tree = &wild->tree;
   while (*tree)
     {
+      /* Sorting by filename takes precedence over sorting by section
+        name.  */
+
+      if (wild->filenames_sorted)
+       {
+         const char *fn, *ln;
+         bool fa, la;
+         int i;
+         asection *lsec = (*tree)->section;
+
+         /* The PE support for the .idata section as generated by
+            dlltool assumes that files will be sorted by the name of
+            the archive and then the name of the file within the
+            archive.  */
+
+         fa = file->the_bfd->my_archive != NULL;
+         if (fa)
+           fn = sort_filename (file->the_bfd->my_archive);
+         else
+           fn = sort_filename (file->the_bfd);
+
+         la = lsec->owner->my_archive != NULL;
+         if (la)
+           ln = sort_filename (lsec->owner->my_archive);
+         else
+           ln = sort_filename (lsec->owner);
+
+         i = filename_cmp (fn, ln);
+         if (i > 0)
+           { tree = &((*tree)->right); continue; }
+         else if (i < 0)
+           { tree = &((*tree)->left); continue; }
+
+         if (fa || la)
+           {
+             if (fa)
+               fn = sort_filename (file->the_bfd);
+             if (la)
+               ln = sort_filename (lsec->owner);
+
+             i = filename_cmp (fn, ln);
+             if (i > 0)
+               { tree = &((*tree)->right); continue; }
+             else if (i < 0)
+               { tree = &((*tree)->left); continue; }
+           }
+       }
+
+      /* Here either the files are not sorted by name, or we are
+        looking at the sections for this file.  */
+
       /* Find the correct node to append this section.  */
       if (compare_section (sec->spec.sorted, section, (*tree)->section) < 0)
        tree = &((*tree)->left);
@@ -560,10 +658,10 @@ wild_sort_fast (lang_wild_statement_type *wild,
   return tree;
 }
 
-/* Use wild_sort_fast to build a BST to sort sections.  */
+/* Use wild_sort to build a BST to sort sections.  */
 
 static void
-output_section_callback_fast (lang_wild_statement_type *ptr,
+output_section_callback_sort (lang_wild_statement_type *ptr,
                              struct wildcard_list *sec,
                              asection *section,
                              lang_input_statement_type *file,
@@ -584,9 +682,13 @@ output_section_callback_fast (lang_wild_statement_type *ptr,
   node->section = section;
   node->pattern = ptr->section_list;
 
-  tree = wild_sort_fast (ptr, sec, file, section);
+  tree = wild_sort (ptr, sec, file, section);
   if (tree != NULL)
-    *tree = node;
+    {
+      *tree = node;
+      if (tree == ptr->rightmost)
+       ptr->rightmost = &node->right;
+    }
 }
 
 /* Convert a sorted sections' BST back to list form.  */
@@ -599,7 +701,8 @@ output_section_callback_tree_to_list (lang_wild_statement_type *ptr,
   if (tree->left)
     output_section_callback_tree_to_list (ptr, tree->left, output);
 
-  lang_add_section (&ptr->children, tree->section, tree->pattern, NULL,
+  lang_add_section (&ptr->children, tree->section, tree->pattern,
+                   ptr->section_flag_list,
                    (lang_output_section_statement_type *) output);
 
   if (tree->right)
@@ -608,384 +711,273 @@ 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)
+  for (; t; t = t->next)
     {
-      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)
-    {
-      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);
     }
 }
 
+/* Dump the global prefix tree.  */
+
 static void
-walk_wild_section (lang_wild_statement_type *ptr,
-                  lang_input_statement_type *file,
-                  callback_t callback,
-                  void *data)
+debug_prefix_tree (void)
 {
-  if (file->flags.just_syms)
-    return;
-
-  (*ptr->walk_wild_section_handler) (ptr, file, callback, data);
+  debug_prefix_tree_rec (ptroot, 2);
 }
 
-/* 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.  */
+/* Like strcspn() but start to look from the end to beginning of
+   S.  Returns the length of the suffix of S consisting entirely
+   of characters not in REJECT.  */
 
-static bool
-wild_spec_can_overlap (const char *name1, const char *name2)
+static size_t
+rstrcspn (const char *s, const char *reject)
 {
-  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;
+  size_t len = strlen (s), sufflen = 0;
+  while (len--)
+    {
+      char c = s[len];
+      if (strchr (reject, c) != 0)
+       break;
+      sufflen++;
+    }
+  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;
 
-  /* 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))
+      if (sec->spec.name)
        {
-         ++wild_name_count;
-         if (!is_simple_wild (sec->spec.name))
-           return;
+         sec->spec.namelen = strlen (sec->spec.name);
+         sec->spec.prefixlen = strcspn (sec->spec.name, "?*[");
+         sec->spec.suffixlen = rstrcspn (sec->spec.name + sec->spec.prefixlen,
+                                         "?*]");
        }
+      else
+       sec->spec.namelen = sec->spec.prefixlen = sec->spec.suffixlen = 0;
     }
 
-  /* 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)
+  insert_prefix_tree (ptr);
+}
+
+/* Match all sections from FILE against the global prefix tree,
+   and record them into each wild statement that has a match.  */
+
+static void
+resolve_wild_sections (lang_input_statement_type *file)
+{
+  asection *s;
+
+  if (file->flags.just_syms)
     return;
 
-  /* Check that no two specs can match the same section.  */
-  for (sec = ptr->section_list; sec != NULL; sec = sec->next)
+  for (s = file->the_bfd->sections; s != NULL; s = s->next)
     {
-      struct wildcard_list *sec2;
-      for (sec2 = sec->next; sec2 != NULL; sec2 = sec2->next)
+      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
        {
-         if (wild_spec_can_overlap (sec->spec.name, sec2->spec.name))
-           return;
+         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);
     }
-
-  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;
 }
 
-/* Handle a wild statement for a single file F.  */
+/* Match all sections from all input files against the global prefix tree.  */
 
 static void
-walk_wild_file (lang_wild_statement_type *s,
-               lang_input_statement_type *f,
-               callback_t callback,
-               void *data)
+resolve_wilds (void)
 {
-  if (walk_wild_file_in_exclude_list (s->exclude_name_list, f))
-    return;
-
-  if (f->the_bfd == NULL
-      || !bfd_check_format (f->the_bfd, bfd_archive))
-    walk_wild_section (s, f, callback, data);
-  else
+  LANG_FOR_EACH_INPUT_STATEMENT (f)
     {
-      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)
+      //printf("XXX   %s\n", f->filename);
+      if (f->the_bfd == NULL
+         || !bfd_check_format (f->the_bfd, bfd_archive))
+       resolve_wild_sections (f);
+      else
        {
-         /* 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);
+         bfd *member;
 
-         member = bfd_openr_next_archived_file (f->the_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)
+           {
+             /* 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 (file_spec == NULL)
-    {
-      /* Perform the iteration over all files in the list.  */
-      LANG_FOR_EACH_INPUT_STATEMENT (f)
-       {
-         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
+  for (l = s->matching_sections.head; l; l = l->header.next)
     {
-      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);
+      (*callback) (s, l->input_matcher.pattern, l->input_matcher.section,
+                  l->input_matcher.input_stmt, data);
     }
 }
 
@@ -1125,6 +1117,7 @@ new_afile (const char *name,
   p->flags.add_DT_NEEDED_for_regular = input_flags.add_DT_NEEDED_for_regular;
   p->flags.whole_archive = input_flags.whole_archive;
   p->flags.sysrooted = input_flags.sysrooted;
+  p->sort_key = NULL;
 
   switch (file_type)
     {
@@ -1291,6 +1284,7 @@ void
 lang_init (void)
 {
   obstack_begin (&stat_obstack, 1000);
+  obstack_init (&pt_obstack);
 
   stat_ptr = &statement_list;
 
@@ -1857,6 +1851,8 @@ insert_os_after (lang_output_section_statement_type *after)
        case lang_group_statement_enum:
        case lang_insert_statement_enum:
          continue;
+       case lang_input_matcher_enum:
+         FAIL ();
        }
       break;
     }
@@ -1891,8 +1887,8 @@ lang_insert_orphan (asection *s,
     address = exp_intop (0);
 
   os_tail = (lang_output_section_statement_type **) lang_os_list.tail;
-  os = lang_enter_output_section_statement (secname, address, normal_section,
-                                           NULL, NULL, NULL, constraint, 0);
+  os = lang_enter_output_section_statement (
+      secname, address, normal_section, 0, NULL, NULL, NULL, constraint, 0);
 
   if (add_child == NULL)
     add_child = &os->children;
@@ -2220,7 +2216,7 @@ lang_print_asneeded (void)
 
   for (m = asneeded_list_head; m != NULL; m = m->next)
     {
-      size_t len;
+      int len;
 
       minfo ("%s", m->soname);
       len = strlen (m->soname);
@@ -2230,11 +2226,7 @@ lang_print_asneeded (void)
          print_nl ();
          len = 0;
        }
-      while (len < 30)
-       {
-         print_space ();
-         ++len;
-       }
+      print_spaces (30 - len);
 
       if (m->ref != NULL)
        minfo ("%pB ", m->ref);
@@ -2297,37 +2289,21 @@ lang_map (void)
 
   for (m = lang_memory_region_list; m != NULL; m = m->next)
     {
-      char buf[100];
-      int len;
-
-      fprintf (config.map_file, "%-16s ", m->name_list.name);
+      fprintf (config.map_file, "%-16s", m->name_list.name);
 
-      sprintf_vma (buf, m->origin);
-      minfo ("0x%s ", buf);
-      len = strlen (buf);
-      while (len < 16)
-       {
-         print_space ();
-         ++len;
-       }
+      char buf[32];
+      bfd_sprintf_vma (link_info.output_bfd, buf, m->origin);
+      fprintf (config.map_file, " 0x%-16s", buf);
+      bfd_sprintf_vma (link_info.output_bfd, buf, m->length);
+      fprintf (config.map_file,
+              " 0x%*s", m->flags || m->not_flags ? -17 : 0, buf);
+      if (m->flags)
+       lang_map_flags (m->flags);
 
-      minfo ("0x%V", m->length);
-      if (m->flags || m->not_flags)
+      if (m->not_flags)
        {
-#ifndef BFD64
-         minfo ("        ");
-#endif
-         if (m->flags)
-           {
-             print_space ();
-             lang_map_flags (m->flags);
-           }
-
-         if (m->not_flags)
-           {
-             minfo (" !");
-             lang_map_flags (m->not_flags);
-           }
+         minfo ("!");
+         lang_map_flags (m->not_flags);
        }
 
       print_nl ();
@@ -2458,7 +2434,6 @@ exp_init_os (etree_type *exp)
        {
        case ADDR:
        case LOADADDR:
-       case SIZEOF:
          {
            lang_output_section_statement_type *os;
 
@@ -2635,10 +2610,12 @@ lang_add_section (lang_statement_list_type *ptr,
     case normal_section:
     case overlay_section:
     case first_overlay_section:
+    case type_section:
       break;
     case noalloc_section:
       flags &= ~SEC_ALLOC;
       break;
+    case typed_readonly_section:
     case readonly_section:
       flags |= SEC_READONLY;
       break;
@@ -2734,113 +2711,17 @@ lang_add_section (lang_statement_list_type *ptr,
   new_section->pattern = pattern;
 }
 
-/* Handle wildcard sorting.  This returns the lang_input_section which
-   should follow the one we are going to create for SECTION and FILE,
-   based on the sorting requirements of WILD.  It returns NULL if the
-   new section should just go at the end of the current list.  */
-
-static lang_statement_union_type *
-wild_sort (lang_wild_statement_type *wild,
-          struct wildcard_list *sec,
-          lang_input_statement_type *file,
-          asection *section)
-{
-  lang_statement_union_type *l;
-
-  if (!wild->filenames_sorted
-      && (sec == NULL || sec->spec.sorted == none))
-    return NULL;
-
-  for (l = wild->children.head; l != NULL; l = l->header.next)
-    {
-      lang_input_section_type *ls;
-
-      if (l->header.type != lang_input_section_enum)
-       continue;
-      ls = &l->input_section;
-
-      /* Sorting by filename takes precedence over sorting by section
-        name.  */
-
-      if (wild->filenames_sorted)
-       {
-         const char *fn, *ln;
-         bool fa, la;
-         int i;
-
-         /* The PE support for the .idata section as generated by
-            dlltool assumes that files will be sorted by the name of
-            the archive and then the name of the file within the
-            archive.  */
-
-         if (file->the_bfd != NULL
-             && file->the_bfd->my_archive != NULL)
-           {
-             fn = bfd_get_filename (file->the_bfd->my_archive);
-             fa = true;
-           }
-         else
-           {
-             fn = file->filename;
-             fa = false;
-           }
-
-         if (ls->section->owner->my_archive != NULL)
-           {
-             ln = bfd_get_filename (ls->section->owner->my_archive);
-             la = true;
-           }
-         else
-           {
-             ln = bfd_get_filename (ls->section->owner);
-             la = false;
-           }
-
-         i = filename_cmp (fn, ln);
-         if (i > 0)
-           continue;
-         else if (i < 0)
-           break;
-
-         if (fa || la)
-           {
-             if (fa)
-               fn = file->filename;
-             if (la)
-               ln = bfd_get_filename (ls->section->owner);
-
-             i = filename_cmp (fn, ln);
-             if (i > 0)
-               continue;
-             else if (i < 0)
-               break;
-           }
-       }
-
-      /* Here either the files are not sorted by name, or we are
-        looking at the sections for this file.  */
-
-      if (sec != NULL
-         && sec->spec.sorted != none
-         && sec->spec.sorted != by_none)
-       if (compare_section (sec->spec.sorted, section, ls->section) < 0)
-         break;
-    }
-
-  return l;
-}
-
 /* Expand a wild statement for a particular FILE.  SECTION may be
-   NULL, in which case it is a wild card.  */
+   NULL, in which case it is a wild card.  This assumes that the
+   wild statement doesn't need any sorting (of filenames or sections).  */
 
 static void
-output_section_callback (lang_wild_statement_type *ptr,
-                        struct wildcard_list *sec,
-                        asection *section,
-                        lang_input_statement_type *file,
-                        void *output)
+output_section_callback_nosort (lang_wild_statement_type *ptr,
+                       struct wildcard_list *sec ATTRIBUTE_UNUSED,
+                       asection *section,
+                       lang_input_statement_type *file ATTRIBUTE_UNUSED,
+                       void *output)
 {
-  lang_statement_union_type *before;
   lang_output_section_statement_type *os;
 
   os = (lang_output_section_statement_type *) output;
@@ -2849,40 +2730,8 @@ output_section_callback (lang_wild_statement_type *ptr,
   if (unique_section_p (section, os))
     return;
 
-  before = wild_sort (ptr, sec, file, section);
-
-  /* Here BEFORE points to the lang_input_section which
-     should follow the one we are about to add.  If BEFORE
-     is NULL, then the section should just go at the end
-     of the current list.  */
-
-  if (before == NULL)
-    lang_add_section (&ptr->children, section, ptr->section_list,
-                     ptr->section_flag_list, os);
-  else
-    {
-      lang_statement_list_type list;
-      lang_statement_union_type **pp;
-
-      lang_list_init (&list);
-      lang_add_section (&list, section, ptr->section_list,
-                       ptr->section_flag_list, os);
-
-      /* If we are discarding the section, LIST.HEAD will
-        be NULL.  */
-      if (list.head != NULL)
-       {
-         ASSERT (list.head->header.next == NULL);
-
-         for (pp = &ptr->children.head;
-              *pp != before;
-              pp = &(*pp)->header.next)
-           ASSERT (*pp != NULL);
-
-         list.head->header.next = *pp;
-         *pp = list.head;
-       }
-    }
+  lang_add_section (&ptr->children, section, ptr->section_list,
+                   ptr->section_flag_list, os);
 }
 
 /* Check if all sections in a wild statement for a particular FILE
@@ -3054,7 +2903,11 @@ load_symbols (lang_input_statement_type *entry,
 
       /* See if the emulation has some special knowledge.  */
       if (ldemul_unrecognized_file (entry))
-       return true;
+       {
+         if (err == bfd_error_file_ambiguously_recognized)
+           free (matching);
+         return true;
+       }
 
       if (err == bfd_error_file_ambiguously_recognized)
        {
@@ -3064,6 +2917,7 @@ load_symbols (lang_input_statement_type *entry,
                   " matching formats:"), entry->the_bfd);
          for (p = matching; *p != NULL; p++)
            einfo (" %s", *p);
+         free (matching);
          einfo ("%F\n");
        }
       else if (err != bfd_error_file_not_recognized
@@ -3188,23 +3042,22 @@ wild (lang_wild_statement_type *s,
 {
   struct wildcard_list *sec;
 
-  if (s->handler_data[0]
-      && s->handler_data[0]->spec.sorted == by_name
-      && !s->filenames_sorted)
+  if (s->filenames_sorted || s->any_specs_sorted)
     {
       lang_section_bst_type *tree;
 
-      walk_wild (s, output_section_callback_fast, output);
+      walk_wild (s, output_section_callback_sort, output);
 
       tree = s->tree;
       if (tree)
        {
          output_section_callback_tree_to_list (s, tree, output);
          s->tree = NULL;
+         s->rightmost = &s->tree;
        }
     }
   else
-    walk_wild (s, output_section_callback, output);
+    walk_wild (s, output_section_callback_nosort, output);
 
   if (default_common_section == NULL)
     for (sec = s->section_list; sec != NULL; sec = sec->next)
@@ -4162,22 +4015,25 @@ update_wild_statements (lang_statement_union_type *s)
                /* Don't sort .init/.fini sections.  */
                if (strcmp (sec->spec.name, ".init") != 0
                    && strcmp (sec->spec.name, ".fini") != 0)
-                 switch (sec->spec.sorted)
-                   {
-                   case none:
-                     sec->spec.sorted = sort_section;
-                     break;
-                   case by_name:
-                     if (sort_section == by_alignment)
-                       sec->spec.sorted = by_name_alignment;
-                     break;
-                   case by_alignment:
-                     if (sort_section == by_name)
-                       sec->spec.sorted = by_alignment_name;
-                     break;
-                   default:
-                     break;
-                   }
+                 {
+                   switch (sec->spec.sorted)
+                     {
+                       case none:
+                           sec->spec.sorted = sort_section;
+                           break;
+                       case by_name:
+                           if (sort_section == by_alignment)
+                             sec->spec.sorted = by_name_alignment;
+                           break;
+                       case by_alignment:
+                           if (sort_section == by_name)
+                             sec->spec.sorted = by_alignment_name;
+                           break;
+                       default:
+                           break;
+                     }
+                   s->wild_statement.any_specs_sorted = true;
+                 }
              break;
 
            case lang_constructors_statement_enum:
@@ -4209,6 +4065,7 @@ map_input_to_output_sections
     {
       lang_output_section_statement_type *tos;
       flagword flags;
+      unsigned int type = 0;
 
       switch (s->header.type)
        {
@@ -4264,6 +4121,42 @@ map_input_to_output_sections
            case readonly_section:
              flags |= SEC_READONLY;
              break;
+           case typed_readonly_section:
+             flags |= SEC_READONLY;
+             /* Fall through.  */
+           case type_section:
+             if (os->sectype_value->type.node_class == etree_name
+                 && os->sectype_value->type.node_code == NAME)
+               {
+                 const char *name = os->sectype_value->name.name;
+                 if (strcmp (name, "SHT_PROGBITS") == 0)
+                   type = SHT_PROGBITS;
+                 else if (strcmp (name, "SHT_STRTAB") == 0)
+                   type = SHT_STRTAB;
+                 else if (strcmp (name, "SHT_NOTE") == 0)
+                   type = SHT_NOTE;
+                 else if (strcmp (name, "SHT_NOBITS") == 0)
+                   type = SHT_NOBITS;
+                 else if (strcmp (name, "SHT_INIT_ARRAY") == 0)
+                   type = SHT_INIT_ARRAY;
+                 else if (strcmp (name, "SHT_FINI_ARRAY") == 0)
+                   type = SHT_FINI_ARRAY;
+                 else if (strcmp (name, "SHT_PREINIT_ARRAY") == 0)
+                   type = SHT_PREINIT_ARRAY;
+                 else
+                   einfo (_ ("%F%P: invalid type for output section `%s'\n"),
+                          os->name);
+               }
+            else
+              {
+                exp_fold_tree_no_dot (os->sectype_value);
+                if (expld.result.valid_p)
+                  type = expld.result.value;
+                else
+                  einfo (_ ("%F%P: invalid type for output section `%s'\n"),
+                         os->name);
+              }
+             break;
            case noload_section:
              if (bfd_get_flavour (link_info.output_bfd)
                  == bfd_target_elf_flavour)
@@ -4276,6 +4169,7 @@ map_input_to_output_sections
            init_os (os, flags | SEC_READONLY);
          else
            os->bfd_section->flags |= flags;
+         os->bfd_section->type = type;
          break;
        case lang_input_section_enum:
          break;
@@ -4324,6 +4218,8 @@ map_input_to_output_sections
          break;
        case lang_insert_statement_enum:
          break;
+       case lang_input_matcher_enum:
+         FAIL ();
        }
     }
 }
@@ -4635,11 +4531,7 @@ print_output_section_statement
              print_nl ();
              len = 0;
            }
-         while (len < SECTION_NAME_MAP_LENGTH)
-           {
-             print_space ();
-             ++len;
-           }
+         print_spaces (SECTION_NAME_MAP_LENGTH - len);
 
          minfo ("0x%V %W", section->vma, TO_ADDR (section->size));
 
@@ -4662,13 +4554,11 @@ static void
 print_assignment (lang_assignment_statement_type *assignment,
                  lang_output_section_statement_type *output_section)
 {
-  unsigned int i;
   bool is_dot;
   etree_type *tree;
   asection *osec;
 
-  for (i = 0; i < SECTION_NAME_MAP_LENGTH; i++)
-    print_space ();
+  print_spaces (SECTION_NAME_MAP_LENGTH);
 
   if (assignment->exp->type.node_class == etree_assert)
     {
@@ -4692,6 +4582,8 @@ print_assignment (lang_assignment_statement_type *assignment,
   else
     expld.result.valid_p = false;
 
+  char buf[32];
+  const char *str = buf;
   if (expld.result.valid_p)
     {
       bfd_vma value;
@@ -4705,7 +4597,9 @@ print_assignment (lang_assignment_statement_type *assignment,
          if (expld.result.section != NULL)
            value += expld.result.section->vma;
 
-         minfo ("0x%V", value);
+         buf[0] = '0';
+         buf[1] = 'x';
+         bfd_sprintf_vma (link_info.output_bfd, buf + 2, value);
          if (is_dot)
            print_dot = value;
        }
@@ -4723,25 +4617,26 @@ print_assignment (lang_assignment_statement_type *assignment,
              value += h->u.def.section->output_section->vma;
              value += h->u.def.section->output_offset;
 
-             minfo ("[0x%V]", value);
+             buf[0] = '[';
+             buf[1] = '0';
+             buf[2] = 'x';
+             bfd_sprintf_vma (link_info.output_bfd, buf + 3, value);
+             strcat (buf, "]");
            }
          else
-           minfo ("[unresolved]");
+           str = "[unresolved]";
        }
     }
   else
     {
       if (assignment->exp->type.node_class == etree_provide)
-       minfo ("[!provide]");
+       str = "[!provide]";
       else
-       minfo ("*undef*   ");
-#ifdef BFD64
-      minfo ("        ");
-#endif
+       str = "*undef*";
     }
   expld.assign_name = NULL;
 
-  minfo ("                ");
+  fprintf (config.map_file, "%-34s", str);
   exp_print_tree (assignment->exp);
   print_nl ();
 }
@@ -4765,10 +4660,7 @@ print_one_symbol (struct bfd_link_hash_entry *hash_entry, void *ptr)
        || hash_entry->type == bfd_link_hash_defweak)
       && sec == hash_entry->u.def.section)
     {
-      int i;
-
-      for (i = 0; i < SECTION_NAME_MAP_LENGTH; i++)
-       print_space ();
+      print_spaces (SECTION_NAME_MAP_LENGTH);
       minfo ("0x%V   ",
             (hash_entry->u.def.value
              + hash_entry->u.def.section->output_offset
@@ -4836,8 +4728,7 @@ print_input_section (asection *i, bool is_discarded)
 
   init_opb (i);
 
-  print_space ();
-  minfo ("%s", i->name);
+  minfo (" %s", i->name);
 
   len = 1 + strlen (i->name);
   if (len >= SECTION_NAME_MAP_LENGTH - 1)
@@ -4845,11 +4736,7 @@ print_input_section (asection *i, bool is_discarded)
       print_nl ();
       len = 0;
     }
-  while (len < SECTION_NAME_MAP_LENGTH)
-    {
-      print_space ();
-      ++len;
-    }
+  print_spaces (SECTION_NAME_MAP_LENGTH - len);
 
   if (i->output_section != NULL
       && i->output_section->owner == link_info.output_bfd)
@@ -4861,22 +4748,14 @@ print_input_section (asection *i, bool is_discarded)
        size = 0;
     }
 
-  minfo ("0x%V %W %pB\n", addr, TO_ADDR (size), i->owner);
+  char buf[32];
+  bfd_sprintf_vma (link_info.output_bfd, buf, addr);
+  minfo ("0x%s %W %pB\n", buf, TO_ADDR (size), i->owner);
 
   if (size != i->rawsize && i->rawsize != 0)
     {
-      len = SECTION_NAME_MAP_LENGTH + 3;
-#ifdef BFD64
-      len += 16;
-#else
-      len += 8;
-#endif
-      while (len > 0)
-       {
-         print_space ();
-         --len;
-       }
-
+      len = SECTION_NAME_MAP_LENGTH + 3 + strlen (buf);
+      print_spaces (len);
       minfo (_("%W (size before relaxing)\n"), TO_ADDR (i->rawsize));
     }
 
@@ -4910,14 +4789,12 @@ print_fill_statement (lang_fill_statement_type *fill)
 static void
 print_data_statement (lang_data_statement_type *data)
 {
-  int i;
   bfd_vma addr;
   bfd_size_type size;
   const char *name;
 
   init_opb (data->output_section);
-  for (i = 0; i < SECTION_NAME_MAP_LENGTH; i++)
-    print_space ();
+  print_spaces (SECTION_NAME_MAP_LENGTH);
 
   addr = data->output_offset;
   if (data->output_section != NULL)
@@ -4980,13 +4857,11 @@ print_address_statement (lang_address_statement_type *address)
 static void
 print_reloc_statement (lang_reloc_statement_type *reloc)
 {
-  int i;
   bfd_vma addr;
   bfd_size_type size;
 
   init_opb (reloc->output_section);
-  for (i = 0; i < SECTION_NAME_MAP_LENGTH; i++)
-    print_space ();
+  print_spaces (SECTION_NAME_MAP_LENGTH);
 
   addr = reloc->output_offset;
   if (reloc->output_section != NULL)
@@ -5018,11 +4893,7 @@ print_padding_statement (lang_padding_statement_type *s)
   minfo (" *fill*");
 
   len = sizeof " *fill*" - 1;
-  while (len < SECTION_NAME_MAP_LENGTH)
-    {
-      print_space ();
-      ++len;
-    }
+  print_spaces (SECTION_NAME_MAP_LENGTH - len);
 
   addr = s->output_offset;
   if (s->output_section != NULL)
@@ -5665,9 +5536,10 @@ os_region_check (lang_output_section_statement_type *os,
 }
 
 static void
-ldlang_check_relro_region (lang_statement_union_type *s,
-                          seg_align_type *seg)
+ldlang_check_relro_region (lang_statement_union_type *s)
 {
+  seg_align_type *seg = &expld.dataseg;
+
   if (seg->relro == exp_seg_relro_start)
     {
       if (!seg->relro_start_stat)
@@ -5732,7 +5604,6 @@ lang_size_sections_1
              os->addr_tree = exp_intop (0);
            if (os->addr_tree != NULL)
              {
-               os->processed_vma = false;
                exp_fold_tree (os->addr_tree, bfd_abs_section_ptr, &dot);
 
                if (expld.result.valid_p)
@@ -6166,7 +6037,7 @@ lang_size_sections_1
                           output_section_statement->bfd_section,
                           &newdot);
 
-           ldlang_check_relro_region (s, &expld.dataseg);
+           ldlang_check_relro_region (s);
 
            expld.dataseg.relro = exp_seg_relro_none;
 
@@ -6346,18 +6217,19 @@ one_lang_size_sections_pass (bool *relax, bool check_regions)
 }
 
 static bool
-lang_size_segment (seg_align_type *seg)
+lang_size_segment (void)
 {
   /* If XXX_SEGMENT_ALIGN XXX_SEGMENT_END pair was seen, check whether
      a page could be saved in the data segment.  */
+  seg_align_type *seg = &expld.dataseg;
   bfd_vma first, last;
 
-  first = -seg->base & (seg->pagesize - 1);
-  last = seg->end & (seg->pagesize - 1);
+  first = -seg->base & (seg->commonpagesize - 1);
+  last = seg->end & (seg->commonpagesize - 1);
   if (first && last
-      && ((seg->base & ~(seg->pagesize - 1))
-         != (seg->end & ~(seg->pagesize - 1)))
-      && first + last <= seg->pagesize)
+      && ((seg->base & ~(seg->commonpagesize - 1))
+         != (seg->end & ~(seg->commonpagesize - 1)))
+      && first + last <= seg->commonpagesize)
     {
       seg->phase = exp_seg_adjust;
       return true;
@@ -6368,95 +6240,42 @@ lang_size_segment (seg_align_type *seg)
 }
 
 static bfd_vma
-lang_size_relro_segment_1 (seg_align_type *seg)
+lang_size_relro_segment_1 (void)
 {
+  seg_align_type *seg = &expld.dataseg;
   bfd_vma relro_end, desired_end;
-  asection *sec, *prev_sec = NULL;
-  bool remove_page_gap = false;
-  unsigned int max_alignment_power = 0;
+  asection *sec;
 
   /* Compute the expected PT_GNU_RELRO/PT_LOAD segment end.  */
-  relro_end = ((seg->relro_end + seg->pagesize - 1)
-              & ~(seg->pagesize - 1));
+  relro_end = (seg->relro_end + seg->relropagesize - 1) & -seg->relropagesize;
 
   /* Adjust by the offset arg of XXX_SEGMENT_RELRO_END.  */
   desired_end = relro_end - seg->relro_offset;
 
   /* For sections in the relro segment..  */
   for (sec = link_info.output_bfd->section_last; sec; sec = sec->prev)
-    if ((sec->flags & SEC_ALLOC) != 0)
+    if ((sec->flags & SEC_ALLOC) != 0
+       && sec->vma >= seg->base
+       && sec->vma < seg->relro_end - seg->relro_offset)
       {
-       if (sec->alignment_power > max_alignment_power)
-         max_alignment_power = sec->alignment_power;
-
-       if (sec->vma >= seg->base
-           && sec->vma < seg->relro_end - seg->relro_offset)
-         {
-           /* Where do we want to put this section so that it ends as
-              desired?  */
-           bfd_vma start, end, bump;
-
-           end = start = sec->vma;
-           if (!IS_TBSS (sec))
-             end += TO_ADDR (sec->size);
-           bump = desired_end - end;
-           /* We'd like to increase START by BUMP, but we must heed
-              alignment so the increase might be less than optimum.  */
-           start += bump;
-           start &= ~(((bfd_vma) 1 << sec->alignment_power) - 1);
-           /* This is now the desired end for the previous section.  */
-           desired_end = start;
-           prev_sec = sec->prev;
-         }
+       /* Where do we want to put this section so that it ends as
+          desired?  */
+       bfd_vma start, end, bump;
+
+       end = start = sec->vma;
+       if (!IS_TBSS (sec))
+         end += TO_ADDR (sec->size);
+       bump = desired_end - end;
+       /* We'd like to increase START by BUMP, but we must heed
+          alignment so the increase might be less than optimum.  */
+       start += bump;
+       start &= ~(((bfd_vma) 1 << sec->alignment_power) - 1);
+       /* This is now the desired end for the previous section.  */
+       desired_end = start;
       }
 
   seg->phase = exp_seg_relro_adjust;
   ASSERT (desired_end >= seg->base);
-
-  for (; prev_sec; prev_sec = prev_sec->prev)
-    if ((prev_sec->flags & SEC_ALLOC) != 0)
-      {
-       if (prev_sec->alignment_power > max_alignment_power)
-         max_alignment_power = prev_sec->alignment_power;
-
-       if (prev_sec->size != 0)
-         {
-           /* The 1-page gap before the RELRO segment may be removed.  */
-           remove_page_gap = ((prev_sec->vma + prev_sec->size
-                               + seg->maxpagesize) < desired_end);
-
-           break;
-         }
-      }
-
-  if (remove_page_gap)
-    {
-      /* Find the maximum section alignment.  */
-      for (sec = prev_sec; sec; sec = sec->prev)
-       if ((sec->flags & SEC_ALLOC) != 0
-           && sec->alignment_power > max_alignment_power)
-         max_alignment_power = sec->alignment_power;
-
-      /* Remove the 1-page gap before the RELRO segment only if the
-        maximum page size >= the maximum section alignment.  */
-      if (seg->maxpagesize >= (1U << max_alignment_power))
-       {
-         /* If the preceding section size is greater than the maximum
-            page size, subtract the maximum page size.  Otherwise,
-            align the RELRO segment to the maximum page size.  */
-         if (prev_sec->size > seg->maxpagesize)
-           {
-             desired_end -= seg->maxpagesize;
-             relro_end -= seg->maxpagesize;
-           }
-         else
-           {
-             desired_end &= ~(seg->maxpagesize - 1);
-             relro_end &= ~(seg->maxpagesize - 1);
-           }
-         }
-      }
-
   seg->base = desired_end;
   return relro_end;
 }
@@ -6465,36 +6284,24 @@ static bool
 lang_size_relro_segment (bool *relax, bool check_regions)
 {
   bool do_reset = false;
-  bool do_data_relro;
-  bfd_vma data_initial_base, data_relro_end;
 
   if (link_info.relro && expld.dataseg.relro_end)
     {
-      do_data_relro = true;
-      data_initial_base = expld.dataseg.base;
-      data_relro_end = lang_size_relro_segment_1 (&expld.dataseg);
-    }
-  else
-    {
-      do_data_relro = false;
-      data_initial_base = data_relro_end = 0;
-    }
+      bfd_vma data_initial_base = expld.dataseg.base;
+      bfd_vma data_relro_end = lang_size_relro_segment_1 ();
 
-  if (do_data_relro)
-    {
       lang_reset_memory_regions ();
       one_lang_size_sections_pass (relax, check_regions);
 
       /* Assignments to dot, or to output section address in a user
         script have increased padding over the original.  Revert.  */
-      if (do_data_relro && expld.dataseg.relro_end > data_relro_end)
+      if (expld.dataseg.relro_end > data_relro_end)
        {
-         expld.dataseg.base = data_initial_base;;
+         expld.dataseg.base = data_initial_base;
          do_reset = true;
        }
     }
-
-  if (!do_data_relro && lang_size_segment (&expld.dataseg))
+  else if (lang_size_segment ())
     do_reset = true;
 
   return do_reset;
@@ -6749,7 +6556,7 @@ section_for_dot (void)
        if (stmt->header.type == lang_output_section_statement_enum)
          break;
 
-      os = &stmt->output_section_statement;
+      os = stmt ? &stmt->output_section_statement : NULL;
       while (os != NULL
             && !os->after_end
             && (os->bfd_section == NULL
@@ -7027,6 +6834,7 @@ lang_symbol_tweaks (void)
            h->other = (h->other & ~ELF_ST_VISIBILITY (-1)) | STV_HIDDEN;
          h->def_regular = 1;
          h->root.linker_def = 1;
+         h->root.rel_from_abs = 1;
        }
     }
 }
@@ -7301,7 +7109,7 @@ lang_one_common (struct bfd_link_hash_entry *h, void *info)
       static bool header_printed;
       int len;
       char *name;
-      char buf[50];
+      char buf[32];
 
       if (!header_printed)
        {
@@ -7329,25 +7137,9 @@ lang_one_common (struct bfd_link_hash_entry *h, void *info)
          print_nl ();
          len = 0;
        }
-      while (len < 20)
-       {
-         print_space ();
-         ++len;
-       }
 
-      minfo ("0x");
-      if (size <= 0xffffffff)
-       sprintf (buf, "%lx", (unsigned long) size);
-      else
-       sprintf_vma (buf, size);
-      minfo ("%s", buf);
-      len = strlen (buf);
-
-      while (len < 16)
-       {
-         print_space ();
-         ++len;
-       }
+      sprintf (buf, "%" PRIx64, (uint64_t) size);
+      fprintf (config.map_file, "%*s0x%-16s", 20 - len, "", buf);
 
       minfo ("%pB\n", section->owner);
     }
@@ -7568,6 +7360,7 @@ lang_output_section_statement_type *
 lang_enter_output_section_statement (const char *output_section_statement_name,
                                     etree_type *address_exp,
                                     enum section_type sectype,
+                                    etree_type *sectype_value,
                                     etree_type *align,
                                     etree_type *subalign,
                                     etree_type *ebase,
@@ -7585,10 +7378,12 @@ lang_enter_output_section_statement (const char *output_section_statement_name,
       os->addr_tree = address_exp;
     }
   os->sectype = sectype;
-  if (sectype != noload_section)
-    os->flags = SEC_NO_FLAGS;
-  else
+  if (sectype == type_section || sectype == typed_readonly_section)
+    os->sectype_value = sectype_value;
+  else if (sectype == noload_section)
     os->flags = SEC_NEVER_LOAD;
+  else
+    os->flags = SEC_NO_FLAGS;
   os->block_value = 1;
 
   /* Make next things chain into subchain of this.  */
@@ -7744,7 +7539,6 @@ find_relro_section_callback (lang_wild_statement_type *ptr ATTRIBUTE_UNUSED,
 
 static void
 lang_find_relro_sections_1 (lang_statement_union_type *s,
-                           seg_align_type *seg,
                            bool *has_relro_section)
 {
   if (*has_relro_section)
@@ -7752,7 +7546,7 @@ lang_find_relro_sections_1 (lang_statement_union_type *s,
 
   for (; s != NULL; s = s->header.next)
     {
-      if (s == seg->relro_end_stat)
+      if (s == expld.dataseg.relro_end_stat)
        break;
 
       switch (s->header.type)
@@ -7764,15 +7558,15 @@ lang_find_relro_sections_1 (lang_statement_union_type *s,
          break;
        case lang_constructors_statement_enum:
          lang_find_relro_sections_1 (constructor_list.head,
-                                     seg, has_relro_section);
+                                     has_relro_section);
          break;
        case lang_output_section_statement_enum:
          lang_find_relro_sections_1 (s->output_section_statement.children.head,
-                                     seg, has_relro_section);
+                                     has_relro_section);
          break;
        case lang_group_statement_enum:
          lang_find_relro_sections_1 (s->group_statement.children.head,
-                                     seg, has_relro_section);
+                                     has_relro_section);
          break;
        default:
          break;
@@ -7788,7 +7582,7 @@ lang_find_relro_sections (void)
   /* Check all sections in the link script.  */
 
   lang_find_relro_sections_1 (expld.dataseg.relro_start_stat,
-                             &expld.dataseg, &has_relro_section);
+                             &has_relro_section);
 
   if (!has_relro_section)
     link_info.relro = false;
@@ -8056,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)
 {
@@ -8100,6 +7910,8 @@ lang_process (void)
       lang_statement_list_type added;
       lang_statement_list_type files, inputfiles;
 
+      ldemul_before_plugin_all_symbols_read ();
+
       /* Now all files are read, let the plugin(s) decide if there
         are any more to be added to the link before we call the
         emulation's after_open hook.  We create a private list of
@@ -8257,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 ();
 
@@ -8267,7 +8084,15 @@ lang_process (void)
 
   ldemul_after_check_relocs ();
 
-  /* Update wild statements.  */
+  /* 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.  */
   update_wild_statements (statement_list.head);
 
   /* Run through the contours of the script and attach input sections
@@ -8381,12 +8206,15 @@ lang_add_wild (struct wildcard_spec *filespec,
 {
   struct wildcard_list *curr, *next;
   lang_wild_statement_type *new_stmt;
+  bool any_specs_sorted = false;
 
   /* Reverse the list as the parser puts it back to front.  */
   for (curr = section_list, section_list = NULL;
        curr != NULL;
        section_list = curr, curr = next)
     {
+      if (curr->spec.sorted != none && curr->spec.sorted != by_none)
+       any_specs_sorted = true;
       next = curr->next;
       curr->next = section_list;
     }
@@ -8402,6 +8230,7 @@ lang_add_wild (struct wildcard_spec *filespec,
   new_stmt = new_stat (lang_wild_statement, stat_ptr);
   new_stmt->filename = NULL;
   new_stmt->filenames_sorted = false;
+  new_stmt->any_specs_sorted = any_specs_sorted;
   new_stmt->section_flag_list = NULL;
   new_stmt->exclude_name_list = NULL;
   if (filespec != NULL)
@@ -8414,7 +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);
+  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
@@ -8905,7 +8742,7 @@ lang_enter_overlay_section (const char *name)
   etree_type *size;
 
   lang_enter_output_section_statement (name, overlay_vma, overlay_section,
-                                      0, overlay_subalign, 0, 0, 0);
+                                      0, 0, overlay_subalign, 0, 0, 0);
 
   /* If this is the first section, then base the VMA of future
      sections on this one.  This will work correctly even if `.' is
@@ -9707,16 +9544,16 @@ lang_ld_feature (char *str)
 /* Pretty print memory amount.  */
 
 static void
-lang_print_memory_size (bfd_vma sz)
+lang_print_memory_size (uint64_t sz)
 {
   if ((sz & 0x3fffffff) == 0)
-    printf ("%10" BFD_VMA_FMT "u GB", sz >> 30);
+    printf ("%10" PRIu64 " GB", sz >> 30);
   else if ((sz & 0xfffff) == 0)
-    printf ("%10" BFD_VMA_FMT "u MB", sz >> 20);
+    printf ("%10" PRIu64 " MB", sz >> 20);
   else if ((sz & 0x3ff) == 0)
-    printf ("%10" BFD_VMA_FMT "u KB", sz >> 10);
+    printf ("%10" PRIu64 " KB", sz >> 10);
   else
-    printf (" %10" BFD_VMA_FMT "u B", sz);
+    printf (" %10" PRIu64 " B", sz);
 }
 
 /* Implement --print-memory-usage: disply per region memory usage.  */
@@ -9733,7 +9570,7 @@ lang_print_memory_usage (void)
 
       printf ("%16s: ",r->name_list.name);
       lang_print_memory_size (used_length);
-      lang_print_memory_size ((bfd_vma) r->length);
+      lang_print_memory_size (r->length);
 
       if (r->length != 0)
        {