Remove path name from test case
[binutils-gdb.git] / ld / ldlang.c
index 9dbc8752f87df6d0dbb0faa38d1bf7568abe451d..566c2b8326ffe56e30048e5e9eb764ffe6ff1b08 100644 (file)
@@ -1,5 +1,5 @@
 /* Linker command language support.
-   Copyright (C) 1991-2022 Free Software Foundation, Inc.
+   Copyright (C) 1991-2023 Free Software Foundation, Inc.
 
    This file is part of the GNU Binutils.
 
@@ -27,7 +27,6 @@
 #include "obstack.h"
 #include "bfdlink.h"
 #include "ctf-api.h"
-
 #include "ld.h"
 #include "ldmain.h"
 #include "ldexp.h"
 #include "demangle.h"
 #include "hashtab.h"
 #include "elf-bfd.h"
+#include "bfdver.h"
+
 #if BFD_SUPPORTS_PLUGINS
 #include "plugin.h"
-#endif /* BFD_SUPPORTS_PLUGINS */
+#endif
 
 #ifndef offsetof
 #define offsetof(TYPE, MEMBER) ((size_t) & (((TYPE*) 0)->MEMBER))
@@ -59,6 +60,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
@@ -78,8 +80,13 @@ static unsigned int opb_shift = 0;
 /* Forward declarations.  */
 static void exp_init_os (etree_type *);
 static lang_input_statement_type *lookup_name (const char *);
+static bool wont_add_section_p (asection *,
+                               lang_output_section_statement_type *);
 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 *,
@@ -127,6 +134,7 @@ bool lang_has_input_file = false;
 bool had_output_filename = false;
 bool lang_float_flag = false;
 bool delete_output_file_on_failure = false;
+bool enable_linker_version = false;
 struct lang_phdr *lang_phdr_list;
 struct lang_nocrossrefs *nocrossref_list;
 struct asneeded_minfo **asneeded_list_tail;
@@ -169,14 +177,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 +388,103 @@ 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
+    {
+      /* XXX Matching against non-wildcard filename in wild statements
+        was done by going through lookup_name, which uses
+        ->local_sym_name to compare against, not ->filename.  We retain
+        this behaviour even though the above code paths use filename.
+        It would be more logical to use it here as well, in which
+        case the above wildcard() arm could be folded into this by using
+        name_match.  This would also solve the worry of what to do
+        about unset local_sym_name (in which case lookup_name simply adds
+        the input file again).  */
+      const char *filename = file->local_sym_name;
+      lang_input_statement_type *arch_is;
+      if (filename && filename_cmp (filename, file_spec) == 0)
+       ;
+      /* FIXME: see also walk_wild_file_in_exclude_list for why we
+        also check parents BFD (local_sym_)name to match input statements
+        with unadorned archive names.  */
+      else if (file->the_bfd
+              && file->the_bfd->my_archive
+              && (arch_is = bfd_usrdata (file->the_bfd->my_archive))
+              && arch_is->local_sym_name
+              && filename_cmp (arch_is->local_sym_name, file_spec) == 0)
+       ;
+      else
+       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
@@ -480,7 +539,7 @@ get_init_priority (const asection *sec)
 /* Compare sections ASEC and BSEC according to SORT.  */
 
 static int
-compare_section (sort_type sort, asection *asec, asection *bsec)
+compare_section (sort_type sort, asection *asec, asection *bsec, bool reversed)
 {
   int ret;
   int a_priority, b_priority;
@@ -495,7 +554,10 @@ compare_section (sort_type sort, asection *asec, asection *bsec)
       b_priority = get_init_priority (bsec);
       if (a_priority < 0 || b_priority < 0)
        goto sort_by_name;
-      ret = a_priority - b_priority;
+      if (reversed)
+       ret = b_priority - a_priority;
+      else
+       ret = a_priority - b_priority;
       if (ret)
        break;
       else
@@ -509,11 +571,17 @@ compare_section (sort_type sort, asection *asec, asection *bsec)
 
     case by_name:
     sort_by_name:
-      ret = strcmp (bfd_section_name (asec), bfd_section_name (bsec));
+      if (reversed)
+       ret = strcmp (bfd_section_name (bsec), bfd_section_name (asec));
+      else
+       ret = strcmp (bfd_section_name (asec), bfd_section_name (bsec));
       break;
 
     case by_name_alignment:
-      ret = strcmp (bfd_section_name (asec), bfd_section_name (bsec));
+      if (reversed)
+       ret = strcmp (bfd_section_name (bsec), bfd_section_name (asec));
+      else
+       ret = strcmp (bfd_section_name (asec), bfd_section_name (bsec));
       if (ret)
        break;
       /* Fall through.  */
@@ -526,32 +594,103 @@ 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);
+
+         if (wild->filenames_reversed)
+           i = filename_cmp (ln, fn);
+         else
+           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);
+
+             if (wild->filenames_reversed)
+               i = filename_cmp (ln, fn);
+             else
+               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)
+      if (sec && sec->spec.sorted != none && sec->spec.sorted != by_none
+         && compare_section (sec->spec.sorted, section, (*tree)->section, sec->spec.reversed) < 0)
        tree = &((*tree)->left);
       else
        tree = &((*tree)->right);
@@ -560,10 +699,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,
@@ -578,15 +717,24 @@ output_section_callback_fast (lang_wild_statement_type *ptr,
   if (unique_section_p (section, os))
     return;
 
+  /* Don't add sections to the tree when we already know that
+     lang_add_section won't do anything with it.  */
+  if (wont_add_section_p (section, os))
+    return;
+
   node = (lang_section_bst_type *) xmalloc (sizeof (lang_section_bst_type));
   node->left = 0;
   node->right = 0;
   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 +747,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 +757,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)
+  for (l = s->matching_sections.head; l; l = l->header.next)
     {
-      /* 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
-    {
-      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);
     }
 }
 
@@ -1115,6 +1153,16 @@ new_afile (const char *name,
 
   lang_has_input_file = true;
 
+  /* PR 30632: It is OK for name to be NULL.  For example
+     see the initialization of first_file in lang_init().  */
+  if (name != NULL)
+    {
+      name = ldfile_possibly_remap_input (name);
+      /* But if a name is remapped to NULL, it should be ignored.  */
+      if (name == NULL)
+       return NULL;
+    }
+
   p = new_stat (lang_input_statement, stat_ptr);
   memset (&p->the_bfd, 0,
          sizeof (*p) - offsetof (lang_input_statement_type, the_bfd));
@@ -1125,6 +1173,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 +1340,7 @@ void
 lang_init (void)
 {
   obstack_begin (&stat_obstack, 1000);
+  obstack_init (&pt_obstack);
 
   stat_ptr = &statement_list;
 
@@ -1316,6 +1366,7 @@ void
 lang_finish (void)
 {
   output_section_statement_table_free ();
+  ldfile_remap_input_free ();
 }
 
 /*----------------------------------------------------------------------
@@ -1779,7 +1830,7 @@ output_prev_sec_find (lang_output_section_statement_type *os)
       if (lookup->constraint < 0)
        continue;
 
-      if (lookup->bfd_section != NULL && lookup->bfd_section->owner != NULL)
+      if (lookup->bfd_section != NULL)
        return lookup->bfd_section;
     }
 
@@ -1798,13 +1849,13 @@ output_prev_sec_find (lang_output_section_statement_type *os)
    image symbols.  */
 
 static lang_statement_union_type **
-insert_os_after (lang_output_section_statement_type *after)
+insert_os_after (lang_statement_union_type *after)
 {
   lang_statement_union_type **where;
   lang_statement_union_type **assign = NULL;
   bool ignore_first;
 
-  ignore_first = after == (void *) lang_os_list.head;
+  ignore_first = after == lang_os_list.head;
 
   for (where = &after->header.next;
        *where != NULL;
@@ -1857,6 +1908,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 +1944,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;
@@ -1939,7 +1992,9 @@ lang_insert_orphan (asection *s,
          if (bfd_section == NULL)
            bfd_section = output_prev_sec_find (after);
 
-         if (bfd_section != NULL && bfd_section != snew)
+         if (bfd_section != NULL
+             && bfd_section->owner != NULL
+             && bfd_section != snew)
            place->section = &bfd_section->next;
        }
 
@@ -2162,8 +2217,9 @@ lang_insert_orphan (asection *s,
          /* Place OS after AFTER if AFTER_NOTE is TRUE.  */
          if (place_after)
            {
-             lang_statement_union_type **where = insert_os_after (after);
+             lang_statement_union_type **where;
 
+             where = insert_os_after ((lang_statement_union_type *) after);
              *add.tail = *where;
              *where = add.head;
 
@@ -2220,7 +2276,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 +2286,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);
@@ -2267,6 +2319,8 @@ lang_map (void)
   lang_memory_region_type *m;
   bool dis_header_printed = false;
 
+  ldfile_print_input_remaps ();
+
   LANG_FOR_EACH_INPUT_STATEMENT (file)
     {
       asection *s;
@@ -2283,13 +2337,15 @@ lang_map (void)
            {
              if (! dis_header_printed)
                {
-                 fprintf (config.map_file, _("\nDiscarded input sections\n\n"));
+                 minfo (_("\nDiscarded input sections\n\n"));
                  dis_header_printed = true;
                }
 
              print_input_section (s, true);
            }
     }
+  if (config.print_map_discarded && ! dis_header_printed)
+    minfo (_("\nThere are no discarded input sections\n"));
 
   minfo (_("\nMemory Configuration\n\n"));
   fprintf (config.map_file, "%-16s %-18s %-18s %s\n",
@@ -2297,43 +2353,27 @@ 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);
+      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);
 
-      sprintf_vma (buf, m->origin);
-      minfo ("0x%s ", buf);
-      len = strlen (buf);
-      while (len < 16)
+      if (m->not_flags)
        {
-         print_space ();
-         ++len;
-       }
-
-      minfo ("0x%V", m->length);
-      if (m->flags || 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 ();
     }
 
-  fprintf (config.map_file, _("\nLinker script and memory map\n\n"));
+  minfo (_("\nLinker script and memory map\n\n"));
 
   if (!link_info.reduce_memory_overheads)
     {
@@ -2416,10 +2456,24 @@ init_os (lang_output_section_statement_type *s, flagword flags)
 
   /* If supplied an alignment, set it.  */
   if (s->section_alignment != NULL)
-    s->bfd_section->alignment_power = exp_get_power (s->section_alignment,
+    s->bfd_section->alignment_power = exp_get_power (s->section_alignment, s,
                                                     "section alignment");
 }
 
+static flagword
+get_os_init_flag (lang_output_section_statement_type * os)
+{
+  if (os != NULL)
+    switch (os->sectype)
+      {
+      case readonly_section: return SEC_READONLY;
+      case noload_section:   return SEC_NEVER_LOAD;
+      default: break;
+      }
+
+  return 0;
+}
+
 /* Make sure that all output sections mentioned in an expression are
    initialized.  */
 
@@ -2458,13 +2512,12 @@ exp_init_os (etree_type *exp)
        {
        case ADDR:
        case LOADADDR:
-       case SIZEOF:
          {
            lang_output_section_statement_type *os;
 
            os = lang_output_section_find (exp->name.name);
            if (os != NULL && os->bfd_section == NULL)
-             init_os (os, 0);
+             init_os (os, get_os_init_flag (os));
          }
        }
       break;
@@ -2522,30 +2575,27 @@ lang_discard_section_p (asection *section)
       && (flags & SEC_DEBUGGING) != 0)
     discard = true;
 
+  /* Discard non-alloc sections if we are stripping section headers.  */
+  else if (config.no_section_header && (flags & SEC_ALLOC) == 0)
+    discard = true;
+
   return discard;
 }
 
-/* The wild routines.
+/* Return TRUE if SECTION is never going to be added to output statement
+   OUTPUT.  lang_add_section() definitely won't do anything with SECTION
+   if this returns TRUE.  It may do something (or not) if this returns FALSE.
 
-   These expand statements like *(.text) and foo.o to a list of
-   explicit actions, like foo.o(.text), bar.o(.text) and
-   foo.o(.text, .data).  */
-
-/* Add SECTION to the output section OUTPUT.  Do this by creating a
-   lang_input_section statement which is placed at PTR.  */
+   Can be used as early-out to filter matches.  This may set
+   output_section of SECTION, if it was unset, to the abs section in case
+   we discover SECTION to be always discarded.  This may also give
+   warning messages.  */
 
-void
-lang_add_section (lang_statement_list_type *ptr,
-                 asection *section,
-                 struct wildcard_list *pattern,
-                 struct flag_info *sflag_info,
-                 lang_output_section_statement_type *output)
+static bool
+wont_add_section_p (asection *section,
+                   lang_output_section_statement_type *output)
 {
-  flagword flags = section->flags;
-
   bool discard;
-  lang_input_section_type *new_section;
-  bfd *abfd = link_info.output_bfd;
 
   /* Is this section one we know should be discarded?  */
   discard = lang_discard_section_p (section);
@@ -2559,45 +2609,39 @@ lang_add_section (lang_statement_list_type *ptr,
     {
       if (section->output_section == NULL)
        {
-         /* This prevents future calls from assigning this section.  */
+         /* This prevents future calls from assigning this section or
+            warning about it again.  */
          section->output_section = bfd_abs_section_ptr;
        }
+      else if (bfd_is_abs_section (section->output_section))
+       ;
       else if (link_info.non_contiguous_regions_warnings)
        einfo (_("%P:%pS: warning: --enable-non-contiguous-regions makes "
-                "section `%pA' from '%pB' match /DISCARD/ clause.\n"),
+                "section `%pA' from `%pB' match /DISCARD/ clause.\n"),
               NULL, section, section->owner);
 
-      return;
-    }
-
-  if (sflag_info)
-    {
-      bool keep;
-
-      keep = bfd_lookup_section_flags (&link_info, sflag_info, section);
-      if (!keep)
-       return;
+      return true;
     }
 
   if (section->output_section != NULL)
     {
       if (!link_info.non_contiguous_regions)
-       return;
+       return true;
 
       /* SECTION has already been handled in a special way
         (eg. LINK_ONCE): skip it.  */
       if (bfd_is_abs_section (section->output_section))
-       return;
+       return true;
 
       /* Already assigned to the same output section, do not process
         it again, to avoid creating loops between duplicate sections
         later.  */
       if (section->output_section == output->bfd_section)
-       return;
+       return true;
 
       if (link_info.non_contiguous_regions_warnings && output->bfd_section)
        einfo (_("%P:%pS: warning: --enable-non-contiguous-regions may "
-                "change behaviour for section `%pA' from '%pB' (assigned to "
+                "change behaviour for section `%pA' from `%pB' (assigned to "
                 "%pA, but additional match: %pA)\n"),
               NULL, section, section->owner, section->output_section,
               output->bfd_section);
@@ -2608,6 +2652,42 @@ lang_add_section (lang_statement_list_type *ptr,
         size_input_section as appropriate.  */
     }
 
+  return false;
+}
+
+/* The wild routines.
+
+   These expand statements like *(.text) and foo.o to a list of
+   explicit actions, like foo.o(.text), bar.o(.text) and
+   foo.o(.text, .data).  */
+
+/* Add SECTION to the output section OUTPUT.  Do this by creating a
+   lang_input_section statement which is placed at PTR.  */
+
+void
+lang_add_section (lang_statement_list_type *ptr,
+                 asection *section,
+                 struct wildcard_list *pattern,
+                 struct flag_info *sflag_info,
+                 lang_output_section_statement_type *output)
+{
+  flagword flags = section->flags;
+
+  lang_input_section_type *new_section;
+  bfd *abfd = link_info.output_bfd;
+
+  if (wont_add_section_p (section, output))
+    return;
+
+  if (sflag_info)
+    {
+      bool keep;
+
+      keep = bfd_lookup_section_flags (&link_info, sflag_info, section);
+      if (!keep)
+       return;
+    }
+
   /* We don't copy the SEC_NEVER_LOAD flag from an input section
      to an output section, because we want to be able to include a
      SEC_NEVER_LOAD section in the middle of an otherwise loaded
@@ -2635,10 +2715,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;
@@ -2692,145 +2774,59 @@ lang_add_section (lang_statement_list_type *ptr,
                                     &link_info);
       if ((flags & SEC_MERGE) != 0)
        output->bfd_section->entsize = section->entsize;
-    }
-
-  if ((flags & SEC_TIC54X_BLOCK) != 0
-      && bfd_get_arch (section->owner) == bfd_arch_tic54x)
-    {
-      /* FIXME: This value should really be obtained from the bfd...  */
-      output->block_value = 128;
-    }
-
-  if (section->alignment_power > output->bfd_section->alignment_power)
-    output->bfd_section->alignment_power = section->alignment_power;
-
-  section->output_section = output->bfd_section;
-
-  if (!map_head_is_link_order)
-    {
-      asection *s = output->bfd_section->map_tail.s;
-      output->bfd_section->map_tail.s = section;
-      section->map_head.s = NULL;
-      section->map_tail.s = s;
-      if (s != NULL)
-       s->map_head.s = section;
-      else
-       output->bfd_section->map_head.s = section;
-    }
-
-  /* Add a section reference to the list.  */
-  new_section = new_stat (lang_input_section, ptr);
-  new_section->section = section;
-  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 ((flags & SEC_TIC54X_BLOCK) != 0
+      && bfd_get_arch (section->owner) == bfd_arch_tic54x)
+    {
+      /* FIXME: This value should really be obtained from the bfd...  */
+      output->block_value = 128;
+    }
 
-         if (fa || la)
-           {
-             if (fa)
-               fn = file->filename;
-             if (la)
-               ln = bfd_get_filename (ls->section->owner);
+  /* When a .ctors section is placed in .init_array it must be copied
+     in reverse order.  Similarly for .dtors.  Set that up.  */
+  if (bfd_get_flavour (link_info.output_bfd) == bfd_target_elf_flavour
+      && ((startswith (section->name, ".ctors")
+          && strcmp (output->bfd_section->name, ".init_array") == 0)
+         || (startswith (section->name, ".dtors")
+             && strcmp (output->bfd_section->name, ".fini_array") == 0))
+      && (section->name[6] == 0 || section->name[6] == '.'))
+    section->flags |= SEC_ELF_REVERSE_COPY;
 
-             i = filename_cmp (fn, ln);
-             if (i > 0)
-               continue;
-             else if (i < 0)
-               break;
-           }
-       }
+  if (section->alignment_power > output->bfd_section->alignment_power)
+    output->bfd_section->alignment_power = section->alignment_power;
 
-      /* Here either the files are not sorted by name, or we are
-        looking at the sections for this file.  */
+  section->output_section = output->bfd_section;
 
-      if (sec != NULL
-         && sec->spec.sorted != none
-         && sec->spec.sorted != by_none)
-       if (compare_section (sec->spec.sorted, section, ls->section) < 0)
-         break;
+  if (!map_head_is_link_order)
+    {
+      asection *s = output->bfd_section->map_tail.s;
+      output->bfd_section->map_tail.s = section;
+      section->map_head.s = NULL;
+      section->map_tail.s = s;
+      if (s != NULL)
+       s->map_head.s = section;
+      else
+       output->bfd_section->map_head.s = section;
     }
 
-  return l;
+  /* Add a section reference to the list.  */
+  new_section = new_stat (lang_input_section, ptr);
+  new_section->section = section;
+  new_section->pattern = pattern;
 }
 
 /* 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;
@@ -2839,40 +2835,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
@@ -3044,7 +3008,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)
        {
@@ -3054,6 +3022,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
@@ -3178,23 +3147,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)
@@ -3507,6 +3475,10 @@ ldlang_open_output (lang_statement_union_type *statement)
        link_info.output_bfd->flags |= BFD_TRADITIONAL_FORMAT;
       else
        link_info.output_bfd->flags &= ~BFD_TRADITIONAL_FORMAT;
+      if (config.no_section_header)
+       link_info.output_bfd->flags |= BFD_NO_SECTION_HEADER;
+      else
+       link_info.output_bfd->flags &= ~BFD_NO_SECTION_HEADER;
       break;
 
     case lang_target_statement_enum:
@@ -3553,17 +3525,20 @@ static struct bfd_link_hash_entry *plugin_undefs = NULL;
 #endif
 
 static void
-open_input_bfds (lang_statement_union_type *s, enum open_bfd_mode mode)
+open_input_bfds (lang_statement_union_type *s,
+                lang_output_section_statement_type *os,
+                enum open_bfd_mode mode)
 {
   for (; s != NULL; s = s->header.next)
     {
       switch (s->header.type)
        {
        case lang_constructors_statement_enum:
-         open_input_bfds (constructor_list.head, mode);
+         open_input_bfds (constructor_list.head, os, mode);
          break;
        case lang_output_section_statement_enum:
-         open_input_bfds (s->output_section_statement.children.head, mode);
+         os = &s->output_section_statement;
+         open_input_bfds (os->children.head, os, mode);
          break;
        case lang_wild_statement_enum:
          /* Maybe we should load the file's symbols.  */
@@ -3572,7 +3547,7 @@ open_input_bfds (lang_statement_union_type *s, enum open_bfd_mode mode)
              && !wildcardp (s->wild_statement.filename)
              && !archive_path (s->wild_statement.filename))
            lookup_name (s->wild_statement.filename);
-         open_input_bfds (s->wild_statement.children.head, mode);
+         open_input_bfds (s->wild_statement.children.head, os, mode);
          break;
        case lang_group_statement_enum:
          {
@@ -3591,7 +3566,7 @@ open_input_bfds (lang_statement_union_type *s, enum open_bfd_mode mode)
                plugin_insert_save = plugin_insert;
 #endif
                undefs = link_info.hash->undefs_tail;
-               open_input_bfds (s->group_statement.children.head,
+               open_input_bfds (s->group_statement.children.head, os,
                                 mode | OPEN_BFD_FORCE);
              }
            while (undefs != link_info.hash->undefs_tail
@@ -3678,7 +3653,7 @@ open_input_bfds (lang_statement_union_type *s, enum open_bfd_mode mode)
          break;
        case lang_assignment_statement_enum:
          if (s->assignment_statement.exp->type.node_class != etree_assert)
-           exp_fold_tree_no_dot (s->assignment_statement.exp);
+           exp_fold_tree_no_dot (s->assignment_statement.exp, os);
          break;
        default:
          break;
@@ -4152,22 +4127,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:
@@ -4199,6 +4177,7 @@ map_input_to_output_sections
     {
       lang_output_section_statement_type *tos;
       flagword flags;
+      unsigned int type = 0;
 
       switch (s->header.type)
        {
@@ -4236,6 +4215,9 @@ map_input_to_output_sections
                                        os);
          break;
        case lang_data_statement_enum:
+         if (os == NULL)
+           /* This should never happen.  */
+           FAIL ();
          /* Make sure that any sections mentioned in the expression
             are initialized.  */
          exp_init_os (s->data_statement.exp);
@@ -4254,6 +4236,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, os);
+                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)
@@ -4266,6 +4284,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;
@@ -4277,14 +4296,16 @@ map_input_to_output_sections
          if (os != NULL && os->bfd_section == NULL)
            init_os (os, 0);
          break;
+
        case lang_assignment_statement_enum:
          if (os != NULL && os->bfd_section == NULL)
-           init_os (os, 0);
+           init_os (os, get_os_init_flag (os));
 
          /* Make sure that any sections mentioned in the assignment
             are initialized.  */
          exp_init_os (s->assignment_statement.exp);
          break;
+
        case lang_address_statement_enum:
          /* Mark the specified section with the supplied address.
             If this section was actually a segment marker, then the
@@ -4314,6 +4335,8 @@ map_input_to_output_sections
          break;
        case lang_insert_statement_enum:
          break;
+       case lang_input_matcher_enum:
+         FAIL ();
        }
     }
 }
@@ -4463,21 +4486,55 @@ process_insert_statements (lang_statement_union_type **start)
                      else
                        link_info.output_bfd->section_last = first_sec->prev;
                      /* Add back.  */
-                     last_sec->next = sec->next;
-                     if (sec->next != NULL)
-                       sec->next->prev = last_sec;
+                     if (sec->owner == NULL)
+                       /* SEC is the absolute section, from the
+                          first dummy output section statement.  Add
+                          back the sections we trimmed off to the
+                          start of the bfd sections.  */
+                       sec = NULL;
+                     if (sec != NULL)
+                       last_sec->next = sec->next;
+                     else
+                       last_sec->next = link_info.output_bfd->sections;
+                     if (last_sec->next != NULL)
+                       last_sec->next->prev = last_sec;
                      else
                        link_info.output_bfd->section_last = last_sec;
                      first_sec->prev = sec;
-                     sec->next = first_sec;
+                     if (first_sec->prev != NULL)
+                       first_sec->prev->next = first_sec;
+                     else
+                       link_info.output_bfd->sections = first_sec;
                    }
                }
-
-             first_os = NULL;
-             last_os = NULL;
            }
 
-         ptr = insert_os_after (where);
+         lang_statement_union_type *after = (void *) where;
+         if (where == &lang_os_list.head->output_section_statement
+             && where->next == first_os)
+           {
+             /* PR30155.  Handle a corner case where the statement
+                list is something like the following:
+                . LOAD t.o
+                . .data           0x0000000000000000        0x0
+                .                 [0x0000000000000000]              b = .
+                .  *(.data)
+                .  .data          0x0000000000000000        0x0 t.o
+                .                 0x0000000000000000        0x4 LONG 0x0
+                . INSERT BEFORE .text.start
+                .                 [0x0000000000000004]              a = .
+                . .text.start     0x0000000000000000        0x0
+                .                 [0x0000000000000000]              c = .
+                . OUTPUT(a.out elf64-x86-64)
+                Here we do not want to allow insert_os_after to
+                choose a point inside the list we are moving.
+                That would lose the list.  Instead, let
+                insert_os_after work from the INSERT, which in this
+                particular example will result in inserting after
+                the assignment "a = .".  */
+             after = *s;
+           }
+         ptr = insert_os_after (after);
          /* Snip everything from the start of the list, up to and
             including the insert statement we are currently processing.  */
          first = *start;
@@ -4488,6 +4545,8 @@ process_insert_statements (lang_statement_union_type **start)
            statement_list.tail = s;
          *ptr = first;
          s = start;
+         first_os = NULL;
+         last_os = NULL;
          continue;
        }
       s = &(*s)->header.next;
@@ -4625,11 +4684,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));
 
@@ -4638,6 +4693,7 @@ print_output_section_statement
 
          if (output_section_statement->update_dot_tree != NULL)
            exp_fold_tree (output_section_statement->update_dot_tree,
+                          output_section_statement,
                           bfd_abs_section_ptr, &print_dot);
        }
 
@@ -4652,13 +4708,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)
     {
@@ -4678,10 +4732,12 @@ print_assignment (lang_assignment_statement_type *assignment,
     osec = bfd_abs_section_ptr;
 
   if (assignment->exp->type.node_class != etree_provide)
-    exp_fold_tree (tree, osec, &print_dot);
+    exp_fold_tree (tree, output_section, osec, &print_dot);
   else
     expld.result.valid_p = false;
 
+  char buf[32];
+  const char *str = buf;
   if (expld.result.valid_p)
     {
       bfd_vma value;
@@ -4695,7 +4751,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;
        }
@@ -4713,25 +4771,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 ();
 }
@@ -4755,10 +4814,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
@@ -4815,6 +4871,50 @@ print_all_symbols (asection *sec)
   obstack_free (&map_obstack, entries);
 }
 
+/* Returns TRUE if SYM is a symbol suitable for printing
+   in a linker map as a local symbol.  */
+
+static bool
+ld_is_local_symbol (asymbol * sym)
+{
+  const char * name = bfd_asymbol_name (sym);
+
+  if (name == NULL || *name == 0)
+    return false;
+
+  if (strcmp (name, "(null)") == 0)
+    return false;
+
+  /* Skip .Lxxx and such like.  */
+  if (bfd_is_local_label (link_info.output_bfd, sym))
+    return false;
+
+  /* FIXME: This is intended to skip ARM mapping symbols,
+     which for some reason are not excluded by bfd_is_local_label,
+     but maybe it is wrong for other architectures.
+     It would be better to fix bfd_is_local_label.  */  
+  if (*name == '$')
+    return false;
+
+  /* Some local symbols, eg _GLOBAL_OFFSET_TABLE_, are present
+     in the hash table, so do not print duplicates here.  */
+  struct bfd_link_hash_entry * h;
+  h = bfd_link_hash_lookup (link_info.hash, name, false /* create */, 
+                           false /* copy */, true /* follow */);
+  if (h == NULL)
+    return true;
+  
+  /* Symbols from the plugin owned BFD will not get their own
+     iteration of this function, but can be on the link_info
+     list.  So include them here.  */
+  if (h->u.def.section->owner != NULL
+      && ((bfd_get_file_flags (h->u.def.section->owner) & (BFD_LINKER_CREATED | BFD_PLUGIN))
+         == (BFD_LINKER_CREATED | BFD_PLUGIN)))
+    return true;
+
+  return false;
+}
+
 /* Print information about an input section to the map file.  */
 
 static void
@@ -4826,8 +4926,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)
@@ -4835,11 +4934,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)
@@ -4851,22 +4946,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));
     }
 
@@ -4883,6 +4970,44 @@ print_input_section (asection *i, bool is_discarded)
         later overlay is shorter than an earier one.  */
       if (addr + TO_ADDR (size) > print_dot)
        print_dot = addr + TO_ADDR (size);
+
+      if (config.print_map_locals)
+       {
+         long  storage_needed;
+
+         /* FIXME: It would be better to cache this table, rather
+            than recreating it for each output section.  */
+         /* FIXME: This call is not working for non-ELF based targets.
+            Find out why.  */
+         storage_needed = bfd_get_symtab_upper_bound (link_info.output_bfd);
+         if (storage_needed > 0)
+           {
+             asymbol **  symbol_table;
+             long        number_of_symbols;
+             long        j;
+
+             symbol_table = xmalloc (storage_needed);
+             number_of_symbols = bfd_canonicalize_symtab (link_info.output_bfd, symbol_table);
+
+             for (j = 0; j < number_of_symbols; j++)
+               {
+                 asymbol *     sym = symbol_table[j];
+                 bfd_vma       sym_addr = sym->value + i->output_section->vma;
+                 
+                 if (sym->section == i->output_section
+                     && (sym->flags & BSF_LOCAL) != 0
+                     && sym_addr >= addr
+                     && sym_addr < print_dot
+                     && ld_is_local_symbol (sym))
+                   {
+                     print_spaces (SECTION_NAME_MAP_LENGTH);
+                     minfo ("0x%V        (local) %s\n", sym_addr, bfd_asymbol_name (sym));
+                   }
+               }
+
+             free (symbol_table);
+           }
+       }
     }
 }
 
@@ -4900,14 +5025,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)
@@ -4970,13 +5093,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)
@@ -5008,11 +5129,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)
@@ -5051,10 +5168,14 @@ print_wild_statement (lang_wild_statement_type *w,
 
   if (w->filenames_sorted)
     minfo ("SORT_BY_NAME(");
+  if (w->filenames_reversed)
+    minfo ("REVERSE(");
   if (w->filename != NULL)
     minfo ("%s", w->filename);
   else
     minfo ("*");
+  if (w->filenames_reversed)
+    minfo (")");
   if (w->filenames_sorted)
     minfo (")");
 
@@ -5099,6 +5220,12 @@ print_wild_statement (lang_wild_statement_type *w,
          break;
        }
 
+      if (sec->spec.reversed)
+       {
+         minfo ("REVERSE(");
+         closing_paren++;
+       }
+
       if (sec->spec.exclude_name_list != NULL)
        {
          name_list *tmp;
@@ -5346,6 +5473,7 @@ size_input_section
       if (output_section_statement->subsection_alignment != NULL)
        i->alignment_power
          = exp_get_power (output_section_statement->subsection_alignment,
+                          output_section_statement,
                           "subsection alignment");
 
       if (o->alignment_power < i->alignment_power)
@@ -5371,15 +5499,15 @@ size_input_section
              if (dot + TO_ADDR (i->size) > end)
                {
                  if (i->flags & SEC_LINKER_CREATED)
-                   einfo (_("%F%P: Output section '%s' not large enough for the "
-                            "linker-created stubs section '%s'.\n"),
-                          i->output_section->name, i->name);
+                   einfo (_("%F%P: Output section `%pA' not large enough for "
+                            "the linker-created stubs section `%pA'.\n"),
+                          i->output_section, i);
 
                  if (i->rawsize && i->rawsize != i->size)
                    einfo (_("%F%P: Relaxation not supported with "
-                            "--enable-non-contiguous-regions (section '%s' "
-                            "would overflow '%s' after it changed size).\n"),
-                          i->name, i->output_section->name);
+                            "--enable-non-contiguous-regions (section `%pA' "
+                            "would overflow `%pA' after it changed size).\n"),
+                          i, i->output_section);
 
                  *removed = 1;
                  dot = end;
@@ -5655,9 +5783,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)
@@ -5683,7 +5812,7 @@ ldlang_check_relro_region (lang_statement_union_type *s,
 static bfd_vma
 lang_size_sections_1
   (lang_statement_union_type **prev,
-   lang_output_section_statement_type *output_section_statement,
+   lang_output_section_statement_type *current_os,
    fill_type *fill,
    bfd_vma dot,
    bool *relax,
@@ -5692,6 +5821,7 @@ lang_size_sections_1
   lang_statement_union_type *s;
   lang_statement_union_type *prev_s = NULL;
   bool removed_prev_s = false;
+  lang_output_section_statement_type *os = current_os;
 
   /* Size up the sections from their constituent parts.  */
   for (s = *prev; s != NULL; prev_s = s, s = s->header.next)
@@ -5703,7 +5833,6 @@ lang_size_sections_1
        case lang_output_section_statement_enum:
          {
            bfd_vma newdot, after, dotdelta;
-           lang_output_section_statement_type *os;
            lang_memory_region_type *r;
            int section_alignment = 0;
 
@@ -5722,8 +5851,7 @@ 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);
+               exp_fold_tree (os->addr_tree, os, bfd_abs_section_ptr, &dot);
 
                if (expld.result.valid_p)
                  {
@@ -5828,7 +5956,7 @@ lang_size_sections_1
                    section_alignment = os->bfd_section->alignment_power;
                  }
                else
-                 section_alignment = exp_get_power (os->section_alignment,
+                 section_alignment = exp_get_power (os->section_alignment, os,
                                                     "section alignment");
 
                /* Align to what the section needs.  */
@@ -5916,6 +6044,7 @@ lang_size_sections_1
                       statement.  */
                    if (os->lma_region != os->region)
                      section_alignment = exp_get_power (os->section_alignment,
+                                                        os,
                                                         "section alignment");
                    if (section_alignment > 0)
                      lma = align_power (lma, section_alignment);
@@ -6005,7 +6134,7 @@ lang_size_sections_1
            dot += dotdelta;
 
            if (os->update_dot_tree != 0)
-             exp_fold_tree (os->update_dot_tree, bfd_abs_section_ptr, &dot);
+             exp_fold_tree (os->update_dot_tree, os, bfd_abs_section_ptr, &dot);
 
            /* Update dot in the region ?
               We only do this if the section is going to be allocated,
@@ -6036,8 +6165,7 @@ lang_size_sections_1
          break;
 
        case lang_constructors_statement_enum:
-         dot = lang_size_sections_1 (&constructor_list.head,
-                                     output_section_statement,
+         dot = lang_size_sections_1 (&constructor_list.head, current_os,
                                      fill, dot, relax, check_regions);
          break;
 
@@ -6045,14 +6173,13 @@ lang_size_sections_1
          {
            unsigned int size = 0;
 
-           s->data_statement.output_offset =
-             dot - output_section_statement->bfd_section->vma;
-           s->data_statement.output_section =
-             output_section_statement->bfd_section;
+           s->data_statement.output_offset = dot - current_os->bfd_section->vma;
+           s->data_statement.output_section = current_os->bfd_section;
 
            /* We might refer to provided symbols in the expression, and
               need to mark them as needed.  */
-           exp_fold_tree (s->data_statement.exp, bfd_abs_section_ptr, &dot);
+           exp_fold_tree (s->data_statement.exp, os,
+                          bfd_abs_section_ptr, &dot);
 
            switch (s->data_statement.type)
              {
@@ -6075,10 +6202,9 @@ lang_size_sections_1
            if (size < TO_SIZE ((unsigned) 1))
              size = TO_SIZE ((unsigned) 1);
            dot += TO_ADDR (size);
-           if (!(output_section_statement->bfd_section->flags
-                 & SEC_FIXED_SIZE))
-             output_section_statement->bfd_section->size
-               = TO_SIZE (dot - output_section_statement->bfd_section->vma);
+           if (!(current_os->bfd_section->flags & SEC_FIXED_SIZE))
+             current_os->bfd_section->size
+               = TO_SIZE (dot - current_os->bfd_section->vma);
 
          }
          break;
@@ -6087,29 +6213,27 @@ lang_size_sections_1
          {
            int size;
 
-           s->reloc_statement.output_offset =
-             dot - output_section_statement->bfd_section->vma;
-           s->reloc_statement.output_section =
-             output_section_statement->bfd_section;
+           s->reloc_statement.output_offset
+             = dot - current_os->bfd_section->vma;
+           s->reloc_statement.output_section
+             = current_os->bfd_section;
            size = bfd_get_reloc_size (s->reloc_statement.howto);
            dot += TO_ADDR (size);
-           if (!(output_section_statement->bfd_section->flags
-                 & SEC_FIXED_SIZE))
-             output_section_statement->bfd_section->size
-               = TO_SIZE (dot - output_section_statement->bfd_section->vma);
+           if (!(current_os->bfd_section->flags & SEC_FIXED_SIZE))
+             current_os->bfd_section->size
+               = TO_SIZE (dot - current_os->bfd_section->vma);
          }
          break;
 
        case lang_wild_statement_enum:
          dot = lang_size_sections_1 (&s->wild_statement.children.head,
-                                     output_section_statement,
-                                     fill, dot, relax, check_regions);
+                                     current_os, fill, dot, relax,
+                                     check_regions);
          break;
 
        case lang_object_symbols_statement_enum:
-         link_info.create_object_symbols_section
-           = output_section_statement->bfd_section;
-         output_section_statement->bfd_section->flags |= SEC_KEEP;
+         link_info.create_object_symbols_section = current_os->bfd_section;
+         current_os->bfd_section->flags |= SEC_KEEP;
          break;
 
        case lang_output_statement_enum:
@@ -6130,8 +6254,7 @@ lang_size_sections_1
                if (again)
                  *relax = true;
              }
-           dot = size_input_section (prev, output_section_statement,
-                                     fill, &removed, dot);
+           dot = size_input_section (prev, current_os, fill, &removed, dot);
          }
          break;
 
@@ -6139,8 +6262,7 @@ lang_size_sections_1
          break;
 
        case lang_fill_statement_enum:
-         s->fill_statement.output_section =
-           output_section_statement->bfd_section;
+         s->fill_statement.output_section = current_os->bfd_section;
 
          fill = s->fill_statement.fill;
          break;
@@ -6152,11 +6274,9 @@ lang_size_sections_1
 
            expld.dataseg.relro = exp_seg_relro_none;
 
-           exp_fold_tree (tree,
-                          output_section_statement->bfd_section,
-                          &newdot);
+           exp_fold_tree (tree, os, current_os->bfd_section, &newdot);
 
-           ldlang_check_relro_region (s, &expld.dataseg);
+           ldlang_check_relro_region (s);
 
            expld.dataseg.relro = exp_seg_relro_none;
 
@@ -6165,11 +6285,11 @@ lang_size_sections_1
                 || tree->type.node_class == etree_assign)
                && (tree->assign.dst [0] != '.'
                    || tree->assign.dst [1] != '\0'))
-             output_section_statement->update_dot = 1;
+             current_os->update_dot = 1;
 
-           if (!output_section_statement->ignored)
+           if (!current_os->ignored)
              {
-               if (output_section_statement == abs_output_section)
+               if (current_os == abs_output_section)
                  {
                    /* If we don't have an output section, then just adjust
                       the default memory address.  */
@@ -6182,7 +6302,7 @@ lang_size_sections_1
                       put the pad before when relaxing, in case the
                       assignment references dot.  */
                    insert_pad (&s->header.next, fill, TO_SIZE (newdot - dot),
-                               output_section_statement->bfd_section, dot);
+                               current_os->bfd_section, dot);
 
                    /* Don't neuter the pad below when relaxing.  */
                    s = s->header.next;
@@ -6191,11 +6311,11 @@ lang_size_sections_1
                       should have space allocated to it, unless the
                       user has explicitly stated that the section
                       should not be allocated.  */
-                   if (output_section_statement->sectype != noalloc_section
-                       && (output_section_statement->sectype != noload_section
+                   if (current_os->sectype != noalloc_section
+                       && (current_os->sectype != noload_section
                            || (bfd_get_flavour (link_info.output_bfd)
                                == bfd_target_elf_flavour)))
-                     output_section_statement->bfd_section->flags |= SEC_ALLOC;
+                     current_os->bfd_section->flags |= SEC_ALLOC;
                  }
                dot = newdot;
              }
@@ -6216,13 +6336,13 @@ lang_size_sections_1
             section.  bfd_set_section_contents will complain even for
             a pad size of zero.  */
          s->padding_statement.output_offset
-           = dot - output_section_statement->bfd_section->vma;
+           = dot - current_os->bfd_section->vma;
          break;
 
        case lang_group_statement_enum:
          dot = lang_size_sections_1 (&s->group_statement.children.head,
-                                     output_section_statement,
-                                     fill, dot, relax, check_regions);
+                                     current_os, fill, dot, relax,
+                                     check_regions);
          break;
 
        case lang_insert_statement_enum:
@@ -6336,18 +6456,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;
@@ -6358,14 +6479,14 @@ 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;
 
   /* 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;
@@ -6402,36 +6523,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;
@@ -6480,6 +6589,8 @@ lang_do_assignments_1 (lang_statement_union_type *s,
                       bfd_vma dot,
                       bool *found_end)
 {
+  lang_output_section_statement_type *os = current_os;
+
   for (; s != NULL; s = s->header.next)
     {
       switch (s->header.type)
@@ -6491,10 +6602,9 @@ lang_do_assignments_1 (lang_statement_union_type *s,
 
        case lang_output_section_statement_enum:
          {
-           lang_output_section_statement_type *os;
            bfd_vma newdot;
 
-           os = &(s->output_section_statement);
+           os = &s->output_section_statement;
            os->after_end = *found_end;
            init_opb (os->bfd_section);
            newdot = dot;
@@ -6521,7 +6631,7 @@ lang_do_assignments_1 (lang_statement_union_type *s,
                      newdot += TO_ADDR (os->bfd_section->size);
 
                    if (os->update_dot_tree != NULL)
-                     exp_fold_tree (os->update_dot_tree,
+                     exp_fold_tree (os->update_dot_tree, os,
                                     bfd_abs_section_ptr, &newdot);
                  }
                dot = newdot;
@@ -6541,7 +6651,7 @@ lang_do_assignments_1 (lang_statement_union_type *s,
          break;
 
        case lang_data_statement_enum:
-         exp_fold_tree (s->data_statement.exp, bfd_abs_section_ptr, &dot);
+         exp_fold_tree (s->data_statement.exp, os, bfd_abs_section_ptr, &dot);
          if (expld.result.valid_p)
            {
              s->data_statement.value = expld.result.value;
@@ -6577,7 +6687,7 @@ lang_do_assignments_1 (lang_statement_union_type *s,
          break;
 
        case lang_reloc_statement_enum:
-         exp_fold_tree (s->reloc_statement.addend_exp,
+         exp_fold_tree (s->reloc_statement.addend_exp, os,
                         bfd_abs_section_ptr, &dot);
          if (expld.result.valid_p)
            s->reloc_statement.addend_value = expld.result.value;
@@ -6616,7 +6726,7 @@ lang_do_assignments_1 (lang_statement_union_type *s,
              if (strcmp (p, "end") == 0)
                *found_end = true;
            }
-         exp_fold_tree (s->assignment_statement.exp,
+         exp_fold_tree (s->assignment_statement.exp, os,
                         (current_os->bfd_section != NULL
                          ? current_os->bfd_section : bfd_und_section_ptr),
                         &dot);
@@ -6686,7 +6796,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
@@ -6931,6 +7041,44 @@ lang_finalize_start_stop (void)
   foreach_start_stop (set_start_stop);
 }
 
+static void
+lang_symbol_tweaks (void)
+{
+  /* Give initial values for __start and __stop symbols, so that  ELF
+     gc_sections will keep sections referenced by these symbols.  Must
+     be done before lang_do_assignments.  */
+  if (config.build_constructors)
+    lang_init_start_stop ();
+
+  /* Make __ehdr_start hidden, and set def_regular even though it is
+     likely undefined at this stage.  For lang_check_relocs.  */
+  if (is_elf_hash_table (link_info.hash)
+      && !bfd_link_relocatable (&link_info))
+    {
+      struct elf_link_hash_entry *h = (struct elf_link_hash_entry *)
+       bfd_link_hash_lookup (link_info.hash, "__ehdr_start",
+                             false, false, true);
+
+      /* Only adjust the export class if the symbol was referenced
+        and not defined, otherwise leave it alone.  */
+      if (h != NULL
+         && (h->root.type == bfd_link_hash_new
+             || h->root.type == bfd_link_hash_undefined
+             || h->root.type == bfd_link_hash_undefweak
+             || h->root.type == bfd_link_hash_common))
+       {
+         const struct elf_backend_data *bed;
+         bed = get_elf_backend_data (link_info.output_bfd);
+         (*bed->elf_backend_hide_symbol) (&link_info, h, true);
+         if (ELF_ST_VISIBILITY (h->other) != STV_INTERNAL)
+           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;
+       }
+    }
+}
+
 static void
 lang_end (void)
 {
@@ -7201,7 +7349,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)
        {
@@ -7229,25 +7377,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);
     }
@@ -7468,6 +7600,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,
@@ -7485,10 +7618,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.  */
@@ -7644,7 +7779,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)
@@ -7652,7 +7786,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)
@@ -7664,15 +7798,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;
@@ -7688,7 +7822,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;
@@ -7699,7 +7833,8 @@ lang_find_relro_sections (void)
 void
 lang_relax_sections (bool need_layout)
 {
-  if (RELAXATION_ENABLED)
+  /* NB: Also enable relaxation to layout sections for DT_RELR.  */
+  if (RELAXATION_ENABLED || link_info.enable_dt_relr)
     {
       /* We may need more than one relaxation pass.  */
       int i = link_info.relax_pass;
@@ -7955,6 +8090,40 @@ lang_propagate_lma_regions (void)
     }
 }
 
+static void
+warn_non_contiguous_discards (void)
+{
+  LANG_FOR_EACH_INPUT_STATEMENT (file)
+    {
+      if ((file->the_bfd->flags & (BFD_LINKER_CREATED | DYNAMIC)) != 0
+         || file->flags.just_syms)
+       continue;
+
+      for (asection *s = file->the_bfd->sections; s != NULL; s = s->next)
+       if (s->output_section == NULL
+           && (s->flags & SEC_LINKER_CREATED) == 0)
+         einfo (_("%P: warning: --enable-non-contiguous-regions "
+                  "discards section `%pA' from `%pB'\n"),
+                s, file->the_bfd);
+    }
+}
+
+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)
 {
@@ -7987,12 +8156,14 @@ lang_process (void)
   /* Create a bfd for each input file.  */
   current_target = default_target;
   lang_statement_iteration++;
-  open_input_bfds (statement_list.head, OPEN_BFD_NORMAL);
+  open_input_bfds (statement_list.head, NULL, OPEN_BFD_NORMAL);
 
   /* Now that open_input_bfds has processed assignments and provide
      statements we can give values to symbolic origin/length now.  */
   lang_do_memory_regions (true);
 
+  ldemul_before_plugin_all_symbols_read ();
+
 #if BFD_SUPPORTS_PLUGINS
   if (link_info.lto_plugin_active)
     {
@@ -8015,7 +8186,12 @@ lang_process (void)
       link_info.lto_all_symbols_read = true;
       /* Open any newly added files, updating the file chains.  */
       plugin_undefs = link_info.hash->undefs_tail;
-      open_input_bfds (*added.tail, OPEN_BFD_NORMAL);
+      lang_output_section_statement_type *last_os = NULL;
+      if (lang_os_list.head != NULL)
+       last_os = ((lang_output_section_statement_type *)
+                  ((char *) lang_os_list.tail
+                   - offsetof (lang_output_section_statement_type, next)));
+      open_input_bfds (*added.tail, last_os, OPEN_BFD_NORMAL);
       if (plugin_undefs == link_info.hash->undefs_tail)
        plugin_undefs = NULL;
       /* Restore the global list pointer now they have all been added.  */
@@ -8066,7 +8242,7 @@ lang_process (void)
          /* Rescan archives in case new undefined symbols have appeared.  */
          files = file_chain;
          lang_statement_iteration++;
-         open_input_bfds (statement_list.head, OPEN_BFD_RESCAN);
+         open_input_bfds (statement_list.head, NULL, OPEN_BFD_RESCAN);
          lang_list_remove_tail (&file_chain, &files);
          while (files.head != NULL)
            {
@@ -8086,6 +8262,8 @@ lang_process (void)
              *insert = &files.head->input_statement;
              files.head = (lang_statement_union_type *) *iter;
              *iter = temp;
+             if (file_chain.tail == (lang_statement_union_type **) insert)
+               file_chain.tail = (lang_statement_union_type **) iter;
              if (my_arch != NULL)
                {
                  lang_input_statement_type *parent = bfd_usrdata (my_arch);
@@ -8099,17 +8277,17 @@ lang_process (void)
     }
 #endif /* BFD_SUPPORTS_PLUGINS */
 
-  /* Make sure that nobody has tried to add a symbol to this list
-     before now.  */
-  ASSERT (link_info.gc_sym_list == NULL);
+  struct bfd_sym_chain **sym = &link_info.gc_sym_list;
+  while (*sym)
+    sym = &(*sym)->next;
 
-  link_info.gc_sym_list = &entry_symbol;
+  *sym = &entry_symbol;
 
   if (entry_symbol.name == NULL)
     {
-      link_info.gc_sym_list = ldlang_undef_chain_list_head;
+      *sym = ldlang_undef_chain_list_head;
 
-      /* entry_symbol is normally initialied by a ENTRY definition in the
+      /* entry_symbol is normally initialised by an ENTRY definition in the
         linker script or the -e command line option.  But if neither of
         these have been used, the target specific backend may still have
         provided an entry symbol via a call to lang_default_entry().
@@ -8146,11 +8324,7 @@ lang_process (void)
      files.  */
   ldctor_build_sets ();
 
-  /* Give initial values for __start and __stop symbols, so that  ELF
-     gc_sections will keep sections referenced by these symbols.  Must
-     be done before lang_do_assignments below.  */
-  if (config.build_constructors)
-    lang_init_start_stop ();
+  lang_symbol_tweaks ();
 
   /* PR 13683: We must rerun the assignments prior to running garbage
      collection in order to make sure that all symbol aliases are resolved.  */
@@ -8160,6 +8334,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 ();
 
@@ -8170,7 +8349,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
@@ -8269,12 +8456,38 @@ lang_process (void)
   if (command_line.check_section_addresses)
     lang_check_section_addresses ();
 
+  if (link_info.non_contiguous_regions
+      && link_info.non_contiguous_regions_warnings)
+    warn_non_contiguous_discards ();
+
   /* Check any required symbols are known.  */
   ldlang_check_require_defined_symbols ();
 
   lang_end ();
 }
 
+void
+lang_add_version_string (void)
+{
+  if (! enable_linker_version)
+    return;
+
+  const char * str = "GNU ld ";
+  int len = strlen (str);
+  int i;
+
+  for (i = 0 ; i < len ; i++)
+    lang_add_data (BYTE, exp_intop (str[i]));
+
+  str = BFD_VERSION_STRING;
+  len = strlen (str);
+
+  for (i = 0 ; i < len ; i++)
+    lang_add_data (BYTE, exp_intop (str[i]));
+
+  lang_add_data (BYTE, exp_intop ('\0'));
+}
+
 /* EXPORTED TO YACC */
 
 void
@@ -8284,12 +8497,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;
     }
@@ -8305,19 +8521,29 @@ 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)
     {
       new_stmt->filename = filespec->name;
-      new_stmt->filenames_sorted = filespec->sorted == by_name;
+      new_stmt->filenames_sorted = (filespec->sorted == by_name || filespec->reversed);
       new_stmt->section_flag_list = filespec->section_flag_list;
       new_stmt->exclude_name_list = filespec->exclude_name_list;
+      new_stmt->filenames_reversed = filespec->reversed;
     }
   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
@@ -8402,6 +8628,89 @@ lang_add_data (int type, union etree_union *exp)
   new_stmt->type = type;
 }
 
+void
+lang_add_string (const char *s)
+{
+  bfd_vma  len = strlen (s);
+  bfd_vma  i;
+  bool     escape = false;
+
+  /* Add byte expressions until end of string.  */
+  for (i = 0 ; i < len; i++)
+    {
+      char c = *s++;
+
+      if (escape)
+       {
+         switch (c)
+           {
+           default:
+             /* Ignore the escape.  */
+             break;
+
+           case 'n': c = '\n'; break;
+           case 'r': c = '\r'; break;
+           case 't': c = '\t'; break;
+         
+           case '0':
+           case '1':
+           case '2':
+           case '3':
+           case '4':
+           case '5':
+           case '6':
+           case '7':
+             /* We have an octal number.  */
+             {
+               unsigned int value = c - '0';
+
+               c = *s;
+               if ((c >= '0') && (c <= '7'))
+                 {
+                   value <<= 3;
+                   value += (c - '0');
+                   i++;
+                   s++;
+
+                   c = *s;
+                   if ((c >= '0') && (c <= '7'))
+                     {
+                       value <<= 3;
+                       value += (c - '0');
+                       i++;
+                       s++;
+                     }
+                 }
+
+               if (value > 0xff)
+                 {
+                   /* octal: \777 is treated as '\077' + '7' */
+                   value >>= 3;
+                   i--;
+                   s--;
+                 }
+
+               c = value;
+             }
+             break;
+           }
+
+         lang_add_data (BYTE, exp_intop (c));
+         escape = false;
+       }
+      else
+       {
+         if (c == '\\')
+           escape = true;
+         else
+           lang_add_data (BYTE, exp_intop (c));
+       }
+    }
+
+  /* Remeber to terminate the string.  */
+  lang_add_data (BYTE, exp_intop (0));
+}
+
 /* Create a new reloc statement.  RELOC is the BFD relocation type to
    generate.  HOWTO is the corresponding howto structure (we could
    look this up, but the caller has already done so).  SECTION is the
@@ -8589,7 +8898,7 @@ lang_new_phdr (const char *name,
   n = stat_alloc (sizeof (struct lang_phdr));
   n->next = NULL;
   n->name = name;
-  n->type = exp_get_vma (type, 0, "program header type");
+  n->type = exp_get_vma (type, NULL, 0, "program header type");
   n->filehdr = filehdr;
   n->phdrs = phdrs;
   n->at = at;
@@ -8703,12 +9012,12 @@ lang_record_phdrs (void)
       if (l->flags == NULL)
        flags = 0;
       else
-       flags = exp_get_vma (l->flags, 0, "phdr flags");
+       flags = exp_get_vma (l->flags, NULL, 0, "phdr flags");
 
       if (l->at == NULL)
        at = 0;
       else
-       at = exp_get_vma (l->at, 0, "phdr load address");
+       at = exp_get_vma (l->at, NULL, 0, "phdr load address");
 
       if (!bfd_record_phdr (link_info.output_bfd, l->type,
                            l->flags != NULL, flags, l->at != NULL,
@@ -8808,7 +9117,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
@@ -9468,7 +9777,7 @@ lang_do_memory_regions (bool update_regions_p)
     {
       if (r->origin_exp)
        {
-         exp_fold_tree_no_dot (r->origin_exp);
+         exp_fold_tree_no_dot (r->origin_exp, NULL);
           if (update_regions_p)
             {
               if (expld.result.valid_p)
@@ -9483,7 +9792,7 @@ lang_do_memory_regions (bool update_regions_p)
        }
       if (r->length_exp)
        {
-         exp_fold_tree_no_dot (r->length_exp);
+         exp_fold_tree_no_dot (r->length_exp, NULL);
           if (update_regions_p)
             {
               if (expld.result.valid_p)
@@ -9610,16 +9919,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.  */
@@ -9636,7 +9945,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)
        {