]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blobdiff - ld/ldlang.c
Update year range in copyright notice of binutils files
[thirdparty/binutils-gdb.git] / ld / ldlang.c
index 3ec534e1fc191be0710e7f7249e5c086b64d11c7..32450fbbcba09b71334fad22fb11537fd5a2f64b 100644 (file)
@@ -1,5 +1,5 @@
 /* Linker command language support.
-   Copyright (C) 1991-2019 Free Software Foundation, Inc.
+   Copyright (C) 1991-2021 Free Software Foundation, Inc.
 
    This file is part of the GNU Binutils.
 
    MA 02110-1301, USA.  */
 
 #include "sysdep.h"
+#include <limits.h>
 #include "bfd.h"
 #include "libiberty.h"
 #include "filenames.h"
 #include "safe-ctype.h"
 #include "obstack.h"
 #include "bfdlink.h"
+#include "ctf-api.h"
 
 #include "ld.h"
 #include "ldmain.h"
@@ -40,9 +42,9 @@
 #include "demangle.h"
 #include "hashtab.h"
 #include "elf-bfd.h"
-#ifdef ENABLE_PLUGINS
+#if BFD_SUPPORTS_PLUGINS
 #include "plugin.h"
-#endif /* ENABLE_PLUGINS */
+#endif /* BFD_SUPPORTS_PLUGINS */
 
 #ifndef offsetof
 #define offsetof(TYPE, MEMBER) ((size_t) & (((TYPE*) 0)->MEMBER))
@@ -96,7 +98,7 @@ static void lang_record_phdrs (void);
 static void lang_do_version_exports_section (void);
 static void lang_finalize_version_expr_head
   (struct bfd_elf_version_expr_head *);
-static void lang_do_memory_regions (void);
+static void lang_do_memory_regions (bfd_boolean);
 
 /* Exported variables.  */
 const char *output_target;
@@ -115,11 +117,12 @@ lang_statement_list_type file_chain = { NULL, NULL };
    lang_input_statement_type statement (reached via input_statement field in a
    lang_statement_union).  */
 lang_statement_list_type input_file_chain;
+static const char *current_input_file;
+struct bfd_elf_dynamic_list **current_dynamic_list_p;
 struct bfd_sym_chain entry_symbol = { NULL, NULL };
 const char *entry_section = ".text";
 struct lang_input_statement_flags input_flags;
 bfd_boolean entry_from_cmdline;
-bfd_boolean undef_from_cmdline;
 bfd_boolean lang_has_input_file = FALSE;
 bfd_boolean had_output_filename = FALSE;
 bfd_boolean lang_float_flag = FALSE;
@@ -127,11 +130,17 @@ bfd_boolean delete_output_file_on_failure = FALSE;
 struct lang_phdr *lang_phdr_list;
 struct lang_nocrossrefs *nocrossref_list;
 struct asneeded_minfo **asneeded_list_tail;
+#ifdef ENABLE_LIBCTF
+static ctf_dict_t *ctf_output;
+#endif
 
- /* Functions that traverse the linker script and might evaluate
-    DEFINED() need to increment this at the start of the traversal.  */
+/* Functions that traverse the linker script and might evaluate
+   DEFINED() need to increment this at the start of the traversal.  */
 int lang_statement_iteration = 0;
 
+/* Count times through one_lang_size_sections_pass after mark phase.  */
+static int lang_sizing_iteration = 0;
+
 /* Return TRUE if the PATTERN argument is a wildcard pattern.
    Although backslashes are treated specially if a pattern contains
    wildcards, we do not consider the mere presence of a backslash to
@@ -148,7 +157,11 @@ int lang_statement_iteration = 0;
 #define outside_symbol_address(q) \
   ((q)->value + outside_section_address (q->section))
 
-#define SECTION_NAME_MAP_LENGTH (16)
+/* CTF sections smaller than this are not compressed: compression of
+   dictionaries this small doesn't gain much, and this lets consumers mmap the
+   sections directly out of the ELF file and use them with no decompression
+   overhead if they want to.  */
+#define CTF_COMPRESSION_THRESHOLD 4096
 
 void *
 stat_alloc (size_t size)
@@ -164,6 +177,21 @@ name_match (const char *pattern, const char *name)
   return strcmp (pattern, name);
 }
 
+static char *
+ldirname (const char *name)
+{
+  const char *base = lbasename (name);
+  char *dirname;
+
+  while (base > name && IS_DIR_SEPARATOR (base[-1]))
+    --base;
+  if (base == name)
+    return strdup (".");
+  dirname = strdup (name);
+  dirname[base - name] = '\0';
+  return dirname;
+}
+
 /* If PATTERN is of the form archive:file, return a pointer to the
    separator.  If not, return NULL.  */
 
@@ -206,7 +234,7 @@ input_statement_is_archive_path (const char *file_spec, char *sep,
 
       if (sep != file_spec)
        {
-         const char *aname = f->the_bfd->my_archive->filename;
+         const char *aname = bfd_get_filename (f->the_bfd->my_archive);
          *sep = 0;
          match = name_match (file_spec, aname) == 0;
          *sep = link_info.path_separator;
@@ -268,7 +296,7 @@ walk_wild_file_in_exclude_list (struct name_list *exclude_list,
       else if (file->the_bfd != NULL
               && file->the_bfd->my_archive != NULL
               && name_match (list_tmp->name,
-                             file->the_bfd->my_archive->filename) == 0)
+                             bfd_get_filename (file->the_bfd->my_archive)) == 0)
        return TRUE;
     }
 
@@ -319,7 +347,7 @@ walk_wild_section_general (lang_wild_statement_type *ptr,
 
          if (sec->spec.name != NULL)
            {
-             const char *sname = bfd_get_section_name (file->the_bfd, s);
+             const char *sname = bfd_section_name (s);
 
              skip = name_match (sec->spec.name, sname) != 0;
            }
@@ -403,39 +431,50 @@ match_simple_wild (const char *pattern, const char *name)
 /* Return the numerical value of the init_priority attribute from
    section name NAME.  */
 
-static unsigned long
-get_init_priority (const char *name)
+static int
+get_init_priority (const asection *sec)
 {
-  char *end;
-  unsigned long init_priority;
+  const char *name = bfd_section_name (sec);
+  const char *dot;
 
   /* GCC uses the following section names for the init_priority
-     attribute with numerical values 101 and 65535 inclusive. A
+     attribute with numerical values 101 to 65535 inclusive. A
      lower value means a higher priority.
 
-     1: .init_array.NNNN/.fini_array.NNNN: Where NNNN is the
+     1: .init_array.NNNNN/.fini_array.NNNNN: Where NNNNN is the
        decimal numerical value of the init_priority attribute.
        The order of execution in .init_array is forward and
        .fini_array is backward.
-     2: .ctors.NNNN/.dtors.NNNN: Where NNNN is 65535 minus the
+     2: .ctors.NNNNN/.dtors.NNNNN: Where NNNNN is 65535 minus the
        decimal numerical value of the init_priority attribute.
        The order of execution in .ctors is backward and .dtors
        is forward.
-   */
-  if (strncmp (name, ".init_array.", 12) == 0
-      || strncmp (name, ".fini_array.", 12) == 0)
-    {
-      init_priority = strtoul (name + 12, &end, 10);
-      return *end ? 0 : init_priority;
-    }
-  else if (strncmp (name, ".ctors.", 7) == 0
-          || strncmp (name, ".dtors.", 7) == 0)
-    {
-      init_priority = strtoul (name + 7, &end, 10);
-      return *end ? 0 : 65535 - init_priority;
-    }
 
-  return 0;
+     .init_array.NNNNN sections would normally be placed in an output
+     .init_array section, .fini_array.NNNNN in .fini_array,
+     .ctors.NNNNN in .ctors, and .dtors.NNNNN in .dtors.  This means
+     we should sort by increasing number (and could just use
+     SORT_BY_NAME in scripts).  However if .ctors.NNNNN sections are
+     being placed in .init_array (which may also contain
+     .init_array.NNNNN sections) or .dtors.NNNNN sections are being
+     placed in .fini_array then we need to extract the init_priority
+     attribute and sort on that.  */
+  dot = strrchr (name, '.');
+  if (dot != NULL && ISDIGIT (dot[1]))
+    {
+      char *end;
+      unsigned long init_priority = strtoul (dot + 1, &end, 10);
+      if (*end == 0)
+       {
+         if (dot == name + 6
+             && (strncmp (name, ".ctors", 6) == 0
+                 || strncmp (name, ".dtors", 6) == 0))
+           init_priority = 65535 - init_priority;
+         if (init_priority <= INT_MAX)
+           return init_priority;
+       }
+    }
+  return -1;
 }
 
 /* Compare sections ASEC and BSEC according to SORT.  */
@@ -444,7 +483,7 @@ static int
 compare_section (sort_type sort, asection *asec, asection *bsec)
 {
   int ret;
-  unsigned long ainit_priority, binit_priority;
+  int a_priority, b_priority;
 
   switch (sort)
     {
@@ -452,41 +491,35 @@ compare_section (sort_type sort, asection *asec, asection *bsec)
       abort ();
 
     case by_init_priority:
-      ainit_priority
-       = get_init_priority (bfd_get_section_name (asec->owner, asec));
-      binit_priority
-       = get_init_priority (bfd_get_section_name (bsec->owner, bsec));
-      if (ainit_priority == 0 || binit_priority == 0)
+      a_priority = get_init_priority (asec);
+      b_priority = get_init_priority (bsec);
+      if (a_priority < 0 || b_priority < 0)
        goto sort_by_name;
-      ret = ainit_priority - binit_priority;
+      ret = a_priority - b_priority;
       if (ret)
        break;
       else
        goto sort_by_name;
 
     case by_alignment_name:
-      ret = (bfd_section_alignment (bsec->owner, bsec)
-            - bfd_section_alignment (asec->owner, asec));
+      ret = bfd_section_alignment (bsec) - bfd_section_alignment (asec);
       if (ret)
        break;
       /* Fall through.  */
 
     case by_name:
-sort_by_name:
-      ret = strcmp (bfd_get_section_name (asec->owner, asec),
-                   bfd_get_section_name (bsec->owner, bsec));
+    sort_by_name:
+      ret = strcmp (bfd_section_name (asec), bfd_section_name (bsec));
       break;
 
     case by_name_alignment:
-      ret = strcmp (bfd_get_section_name (asec->owner, asec),
-                   bfd_get_section_name (bsec->owner, bsec));
+      ret = strcmp (bfd_section_name (asec), bfd_section_name (bsec));
       if (ret)
        break;
       /* Fall through.  */
 
     case by_alignment:
-      ret = (bfd_section_alignment (bsec->owner, bsec)
-            - bfd_section_alignment (asec->owner, asec));
+      ret = bfd_section_alignment (bsec) - bfd_section_alignment (asec);
       break;
     }
 
@@ -610,7 +643,7 @@ walk_wild_section_specs1_wild1 (lang_wild_statement_type *ptr,
 
   for (s = file->the_bfd->sections; s != NULL; s = s->next)
     {
-      const char *sname = bfd_get_section_name (file->the_bfd, s);
+      const char *sname = bfd_section_name (s);
       bfd_boolean skip = !match_simple_wild (wildsec0->spec.name, sname);
 
       if (!skip)
@@ -647,7 +680,7 @@ walk_wild_section_specs2_wild1 (lang_wild_statement_type *ptr,
        walk_wild_consider_section (ptr, file, s, sec0, callback, data);
       else
        {
-         const char *sname = bfd_get_section_name (file->the_bfd, s);
+         const char *sname = bfd_section_name (s);
          bfd_boolean skip = !match_simple_wild (wildsec1->spec.name, sname);
 
          if (!skip)
@@ -682,7 +715,7 @@ walk_wild_section_specs3_wild2 (lang_wild_statement_type *ptr,
        walk_wild_consider_section (ptr, file, s, sec0, callback, data);
       else
        {
-         const char *sname = bfd_get_section_name (file->the_bfd, s);
+         const char *sname = bfd_section_name (s);
          bfd_boolean skip = !match_simple_wild (wildsec1->spec.name, sname);
 
          if (!skip)
@@ -734,7 +767,7 @@ walk_wild_section_specs4_wild2 (lang_wild_statement_type *ptr,
          walk_wild_consider_section (ptr, file, s, sec1, callback, data);
        else
          {
-           const char *sname = bfd_get_section_name (file->the_bfd, s);
+           const char *sname = bfd_section_name (s);
            bfd_boolean skip = !match_simple_wild (wildsec2->spec.name,
                                                   sname);
 
@@ -908,12 +941,8 @@ walk_wild_file (lang_wild_statement_type *s,
             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 (member->usrdata != NULL)
-           {
-             walk_wild_section (s,
-                                (lang_input_statement_type *) member->usrdata,
-                                callback, data);
-           }
+         if (bfd_usrdata (member) != NULL)
+           walk_wild_section (s, bfd_usrdata (member), callback, data);
 
          member = bfd_openr_next_archived_file (f->the_bfd, member);
        }
@@ -1061,7 +1090,7 @@ new_statement (enum statement_enum type,
 {
   lang_statement_union_type *new_stmt;
 
-  new_stmt = (lang_statement_union_type *) stat_alloc (size);
+  new_stmt = stat_alloc (size);
   new_stmt->header.type = type;
   new_stmt->header.next = NULL;
   lang_statement_append (list, new_stmt, &new_stmt->header.next);
@@ -1081,24 +1110,16 @@ static lang_input_statement_type *
 new_afile (const char *name,
           lang_input_file_enum_type file_type,
           const char *target,
-          bfd_boolean add_to_list)
+          const char *from_filename)
 {
   lang_input_statement_type *p;
 
   lang_has_input_file = TRUE;
 
-  if (add_to_list)
-    p = (lang_input_statement_type *) new_stat (lang_input_statement, stat_ptr);
-  else
-    {
-      p = (lang_input_statement_type *)
-         stat_alloc (sizeof (lang_input_statement_type));
-      p->header.type = lang_input_statement_enum;
-      p->header.next = NULL;
-    }
-
+  p = new_stat (lang_input_statement, stat_ptr);
   memset (&p->the_bfd, 0,
          sizeof (*p) - offsetof (lang_input_statement_type, the_bfd));
+  p->extra_search_path = NULL;
   p->target = target;
   p->flags.dynamic = input_flags.dynamic;
   p->flags.add_DT_NEEDED_for_dynamic = input_flags.add_DT_NEEDED_for_dynamic;
@@ -1139,6 +1160,10 @@ new_afile (const char *name,
     case lang_input_file_is_search_file_enum:
       p->filename = name;
       p->local_sym_name = name;
+      /* If name is a relative path, search the directory of the current linker
+         script first. */
+      if (from_filename && !IS_ABSOLUTE_PATH (name))
+        p->extra_search_path = ldirname (from_filename);
       p->flags.real = TRUE;
       p->flags.search_dirs = TRUE;
       break;
@@ -1178,12 +1203,12 @@ lang_add_input_file (const char *name,
         within the sysroot subdirectory.)  */
       unsigned int outer_sysrooted = input_flags.sysrooted;
       input_flags.sysrooted = 0;
-      ret = new_afile (sysrooted_name, file_type, target, TRUE);
+      ret = new_afile (sysrooted_name, file_type, target, NULL);
       input_flags.sysrooted = outer_sysrooted;
       return ret;
     }
 
-  return new_afile (name, file_type, target, TRUE);
+  return new_afile (name, file_type, target, current_input_file);
 }
 
 struct out_section_hash_entry
@@ -1280,7 +1305,7 @@ lang_init (void)
   first_file = lang_add_input_file (NULL, lang_input_file_is_marker_enum,
                                    NULL);
   abs_output_section =
-    lang_output_section_statement_lookup (BFD_ABS_SECTION_NAME, 0, TRUE);
+    lang_output_section_statement_lookup (BFD_ABS_SECTION_NAME, 0, 1);
 
   abs_output_section->bfd_section = bfd_abs_section_ptr;
 
@@ -1345,8 +1370,7 @@ lang_memory_region_lookup (const char *const name, bfd_boolean create)
     einfo (_("%P:%pS: warning: memory region `%s' not declared\n"),
           NULL, name);
 
-  new_region = (lang_memory_region_type *)
-      stat_alloc (sizeof (lang_memory_region_type));
+  new_region = stat_alloc (sizeof (lang_memory_region_type));
 
   new_region->name_list.name = xstrdup (name);
   new_region->name_list.next = NULL;
@@ -1402,7 +1426,7 @@ lang_memory_region_alias (const char *alias, const char *region_name)
           NULL, region_name, alias);
 
   /* Add alias to region name list.  */
-  n = (lang_memory_region_name *) stat_alloc (sizeof (lang_memory_region_name));
+  n = stat_alloc (sizeof (lang_memory_region_name));
   n->name = xstrdup (alias);
   n->next = region->name_list.next;
   region->name_list.next = n;
@@ -1435,24 +1459,26 @@ lang_memory_default (asection *section)
 lang_output_section_statement_type *
 lang_output_section_get (const asection *output_section)
 {
-  return get_userdata (output_section);
+  return bfd_section_userdata (output_section);
 }
 
 /* Find or create an output_section_statement with the given NAME.
    If CONSTRAINT is non-zero match one with that constraint, otherwise
-   match any non-negative constraint.  If CREATE, always make a
-   new output_section_statement for SPECIAL CONSTRAINT.  */
+   match any non-negative constraint.  If CREATE is 0 return NULL when
+   no match exists.  If CREATE is 1, create an output_section_statement
+   when no match exists or if CONSTRAINT is SPECIAL.  If CREATE is 2,
+   always make a new output_section_statement.  */
 
 lang_output_section_statement_type *
 lang_output_section_statement_lookup (const char *name,
                                      int constraint,
-                                     bfd_boolean create)
+                                     int create)
 {
   struct out_section_hash_entry *entry;
 
   entry = ((struct out_section_hash_entry *)
           bfd_hash_lookup (&output_section_statement_table, name,
-                           create, FALSE));
+                           create != 0, FALSE));
   if (entry == NULL)
     {
       if (create)
@@ -1467,23 +1493,19 @@ lang_output_section_statement_lookup (const char *name,
       struct out_section_hash_entry *last_ent;
 
       name = entry->s.output_section_statement.name;
-      if (create && constraint == SPECIAL)
-       /* Not traversing to the end reverses the order of the second
-          and subsequent SPECIAL sections in the hash table chain,
-          but that shouldn't matter.  */
-       last_ent = entry;
-      else
-       do
-         {
-           if (constraint == entry->s.output_section_statement.constraint
-               || (constraint == 0
-                   && entry->s.output_section_statement.constraint >= 0))
-             return &entry->s.output_section_statement;
-           last_ent = entry;
-           entry = (struct out_section_hash_entry *) entry->root.next;
-         }
-       while (entry != NULL
-              && name == entry->s.output_section_statement.name);
+      do
+       {
+         if (create != 2
+             && !(create && constraint == SPECIAL)
+             && (constraint == entry->s.output_section_statement.constraint
+                 || (constraint == 0
+                     && entry->s.output_section_statement.constraint >= 0)))
+           return &entry->s.output_section_statement;
+         last_ent = entry;
+         entry = (struct out_section_hash_entry *) entry->root.next;
+       }
+      while (entry != NULL
+            && name == entry->s.output_section_statement.name);
 
       if (!create)
        return NULL;
@@ -1504,6 +1526,8 @@ lang_output_section_statement_lookup (const char *name,
 
   entry->s.output_section_statement.name = name;
   entry->s.output_section_statement.constraint = constraint;
+  entry->s.output_section_statement.dup_output = (create == 2
+                                                 || constraint == SPECIAL);
   return &entry->s.output_section_statement;
 }
 
@@ -1553,7 +1577,7 @@ lang_output_section_find_by_flags (const asection *sec,
 
   /* We know the first statement on this list is *ABS*.  May as well
      skip it.  */
-  first = &lang_os_list.head->output_section_statement;
+  first = (void *) lang_os_list.head;
   first = first->next;
 
   /* First try for an exact match.  */
@@ -1781,7 +1805,7 @@ insert_os_after (lang_output_section_statement_type *after)
   lang_statement_union_type **assign = NULL;
   bfd_boolean ignore_first;
 
-  ignore_first = after == &lang_os_list.head->output_section_statement;
+  ignore_first = after == (void *) lang_os_list.head;
 
   for (where = &after->header.next;
        *where != NULL;
@@ -1905,7 +1929,7 @@ lang_insert_orphan (asection *s,
       /* Shuffle the bfd section list to make the output file look
         neater.  This is really only cosmetic.  */
       if (place->section == NULL
-         && after != &lang_os_list.head->output_section_statement)
+         && after != (void *) lang_os_list.head)
        {
          asection *bfd_section = after->bfd_section;
 
@@ -2337,12 +2361,11 @@ sort_def_symbol (struct bfd_link_hash_entry *hash_entry,
       input_section_userdata_type *ud;
       struct map_symbol_def *def;
 
-      ud = ((input_section_userdata_type *)
-           get_userdata (hash_entry->u.def.section));
+      ud = bfd_section_userdata (hash_entry->u.def.section);
       if (!ud)
        {
-         ud = (input_section_userdata_type *) stat_alloc (sizeof (*ud));
-         get_userdata (hash_entry->u.def.section) = ud;
+         ud = stat_alloc (sizeof (*ud));
+         bfd_set_section_userdata (hash_entry->u.def.section, ud);
          ud->map_symbol_def_tail = &ud->map_symbol_def_head;
          ud->map_symbol_def_count = 0;
        }
@@ -2366,7 +2389,7 @@ init_os (lang_output_section_statement_type *s, flagword flags)
   if (strcmp (s->name, DISCARD_SECTION_NAME) == 0)
     einfo (_("%F%P: illegal use of `%s' section\n"), DISCARD_SECTION_NAME);
 
-  if (s->constraint != SPECIAL)
+  if (!s->dup_output)
     s->bfd_section = bfd_get_section_by_name (link_info.output_bfd, s->name);
   if (s->bfd_section == NULL)
     s->bfd_section = bfd_make_section_anyway_with_flags (link_info.output_bfd,
@@ -2382,7 +2405,7 @@ init_os (lang_output_section_statement_type *s, flagword flags)
 
   /* Set the userdata of the output section to the output section
      statement to avoid lookup.  */
-  get_userdata (s->bfd_section) = s;
+  bfd_set_section_userdata (s->bfd_section, s);
 
   /* If there is a base address, make sure that any sections it might
      mention are initialized.  */
@@ -2539,6 +2562,11 @@ lang_add_section (lang_statement_list_type *ptr,
          /* This prevents future calls from assigning this section.  */
          section->output_section = bfd_abs_section_ptr;
        }
+      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"),
+              NULL, section, section->owner);
+
       return;
     }
 
@@ -2552,7 +2580,33 @@ lang_add_section (lang_statement_list_type *ptr,
     }
 
   if (section->output_section != NULL)
-    return;
+    {
+      if (!link_info.non_contiguous_regions)
+       return;
+
+      /* SECTION has already been handled in a special way
+        (eg. LINK_ONCE): skip it.  */
+      if (bfd_is_abs_section (section->output_section))
+       return;
+
+      /* 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;
+
+      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 "
+                "%pA, but additional match: %pA)\n"),
+              NULL, section, section->owner, section->output_section,
+              output->bfd_section);
+
+      /* SECTION has already been assigned to an output section, but
+        the user allows it to be mapped to another one in case it
+        overflows. We'll later update the actual output section in
+        size_input_section as appropriate.  */
+    }
 
   /* 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
@@ -2724,7 +2778,7 @@ wild_sort (lang_wild_statement_type *wild,
            }
          else
            {
-             ln = ls->section->owner->filename;
+             ln = bfd_get_filename (ls->section->owner);
              la = FALSE;
            }
 
@@ -2739,7 +2793,7 @@ wild_sort (lang_wild_statement_type *wild,
              if (fa)
                fn = file->filename;
              if (la)
-               ln = ls->section->owner->filename;
+               ln = bfd_get_filename (ls->section->owner);
 
              i = filename_cmp (fn, ln);
              if (i > 0)
@@ -2848,7 +2902,7 @@ lookup_name (const char *name)
 {
   lang_input_statement_type *search;
 
-  for (search = &input_file_chain.head->input_statement;
+  for (search = (void *) input_file_chain.head;
        search != NULL;
        search = search->next_real_file)
     {
@@ -2863,8 +2917,25 @@ lookup_name (const char *name)
     }
 
   if (search == NULL)
-    search = new_afile (name, lang_input_file_is_search_file_enum,
-                       default_target, FALSE);
+    {
+      /* Arrange to splice the input statement added by new_afile into
+        statement_list after the current input_file_chain tail.
+        We know input_file_chain is not an empty list, and that
+        lookup_name was called via open_input_bfds.  Later calls to
+        lookup_name should always match an existing input_statement.  */
+      lang_statement_union_type **tail = stat_ptr->tail;
+      lang_statement_union_type **after
+       = (void *) ((char *) input_file_chain.tail
+                   - offsetof (lang_input_statement_type, next_real_file)
+                   + offsetof (lang_input_statement_type, header.next));
+      lang_statement_union_type *rest = *after;
+      stat_ptr->tail = after;
+      search = new_afile (name, lang_input_file_is_search_file_enum,
+                         default_target, NULL);
+      *stat_ptr->tail = rest;
+      if (*tail == NULL)
+       stat_ptr->tail = tail;
+    }
 
   /* If we have already added this file, or this file is not real
      don't add this file.  */
@@ -2917,7 +2988,7 @@ check_excluded_libs (bfd *abfd)
   while (lib)
     {
       int len = strlen (lib->name);
-      const char *filename = lbasename (abfd->filename);
+      const char *filename = lbasename (bfd_get_filename (abfd));
 
       if (strcmp (lib->name, "ALL") == 0)
        {
@@ -3002,7 +3073,9 @@ load_symbols (lang_input_statement_type *entry,
 
       ldfile_assumed_script = TRUE;
       parser_input = input_script;
+      current_input_file = entry->filename;
       yyparse ();
+      current_input_file = NULL;
       ldfile_assumed_script = FALSE;
 
       /* missing_file is sticky.  sysrooted will already have been
@@ -3038,7 +3111,7 @@ load_symbols (lang_input_statement_type *entry,
     case bfd_archive:
       check_excluded_libs (entry->the_bfd);
 
-      entry->the_bfd->usrdata = entry;
+      bfd_set_usrdata (entry->the_bfd, entry);
       if (entry->flags.whole_archive)
        {
          bfd *member = NULL;
@@ -3143,7 +3216,7 @@ get_target (const bfd_target *target, void *data)
 /* Like strcpy() but convert to lower case as well.  */
 
 static void
-stricpy (char *dest, char *src)
+stricpy (char *dest, const char *src)
 {
   char c;
 
@@ -3157,7 +3230,7 @@ stricpy (char *dest, char *src)
    from haystack.  */
 
 static void
-strcut (char *haystack, char *needle)
+strcut (char *haystack, const char *needle)
 {
   haystack = strstr (haystack, needle);
 
@@ -3176,7 +3249,7 @@ strcut (char *haystack, char *needle)
    Return a value indicating how "similar" they are.  */
 
 static int
-name_compare (char *first, char *second)
+name_compare (const char *first, const char *second)
 {
   char *copy1;
   char *copy2;
@@ -3261,10 +3334,10 @@ closest_target_match (const bfd_target *target, void *data)
 
 /* Return the BFD target format of the first input file.  */
 
-static char *
+static const char *
 get_first_input_target (void)
 {
-  char *target = NULL;
+  const char *target = NULL;
 
   LANG_FOR_EACH_INPUT_STATEMENT (s)
     {
@@ -3425,11 +3498,18 @@ ldlang_open_output (lang_statement_union_type *statement)
 }
 
 static void
-init_opb (void)
+init_opb (asection *s)
 {
-  unsigned x = bfd_arch_mach_octets_per_byte (ldfile_output_architecture,
-                                             ldfile_output_machine);
+  unsigned int x;
+
   opb_shift = 0;
+  if (bfd_get_flavour (link_info.output_bfd) == bfd_target_elf_flavour
+      && s != NULL
+      && (s->flags & SEC_ELF_OCTETS) != 0)
+    return;
+
+  x = bfd_arch_mach_octets_per_byte (ldfile_output_architecture,
+                                    ldfile_output_machine);
   if (x > 1)
     while ((x & 1) == 0)
       {
@@ -3447,7 +3527,7 @@ enum open_bfd_mode
     OPEN_BFD_FORCE = 1,
     OPEN_BFD_RESCAN = 2
   };
-#ifdef ENABLE_PLUGINS
+#if BFD_SUPPORTS_PLUGINS
 static lang_input_statement_type *plugin_insert = NULL;
 static struct bfd_link_hash_entry *plugin_undefs = NULL;
 #endif
@@ -3477,7 +3557,7 @@ open_input_bfds (lang_statement_union_type *s, enum open_bfd_mode mode)
        case lang_group_statement_enum:
          {
            struct bfd_link_hash_entry *undefs;
-#ifdef ENABLE_PLUGINS
+#if BFD_SUPPORTS_PLUGINS
            lang_input_statement_type *plugin_insert_save;
 #endif
 
@@ -3487,7 +3567,7 @@ open_input_bfds (lang_statement_union_type *s, enum open_bfd_mode mode)
 
            do
              {
-#ifdef ENABLE_PLUGINS
+#if BFD_SUPPORTS_PLUGINS
                plugin_insert_save = plugin_insert;
 #endif
                undefs = link_info.hash->undefs_tail;
@@ -3495,7 +3575,7 @@ open_input_bfds (lang_statement_union_type *s, enum open_bfd_mode mode)
                                 mode | OPEN_BFD_FORCE);
              }
            while (undefs != link_info.hash->undefs_tail
-#ifdef ENABLE_PLUGINS
+#if BFD_SUPPORTS_PLUGINS
                   /* Objects inserted by a plugin, which are loaded
                      before we hit this loop, may have added new
                      undefs.  */
@@ -3522,7 +3602,7 @@ open_input_bfds (lang_statement_union_type *s, enum open_bfd_mode mode)
                 has been loaded already.  Do the same for a rescan.
                 Likewise reload --as-needed shared libs.  */
              if (mode != OPEN_BFD_NORMAL
-#ifdef ENABLE_PLUGINS
+#if BFD_SUPPORTS_PLUGINS
                  && ((mode & OPEN_BFD_RESCAN) == 0
                      || plugin_insert == NULL)
 #endif
@@ -3569,7 +3649,7 @@ open_input_bfds (lang_statement_union_type *s, enum open_bfd_mode mode)
                    }
                }
            }
-#ifdef ENABLE_PLUGINS
+#if BFD_SUPPORTS_PLUGINS
          /* If we have found the point at which a plugin added new
             files, clear plugin_insert to enable archive rescan.  */
          if (&s->input_statement == plugin_insert)
@@ -3590,6 +3670,278 @@ open_input_bfds (lang_statement_union_type *s, enum open_bfd_mode mode)
     einfo ("%F");
 }
 
+#ifdef ENABLE_LIBCTF
+/* Emit CTF errors and warnings.  fp can be NULL to report errors/warnings
+   that happened specifically at CTF open time.  */
+static void
+lang_ctf_errs_warnings (ctf_dict_t *fp)
+{
+  ctf_next_t *i = NULL;
+  char *text;
+  int is_warning;
+  int err;
+
+  while ((text = ctf_errwarning_next (fp, &i, &is_warning, &err)) != NULL)
+    {
+      einfo (_("%s: %s\n"), is_warning ? _("CTF warning"): _("CTF error"),
+            text);
+      free (text);
+    }
+  if (err != ECTF_NEXT_END)
+    {
+      einfo (_("CTF error: cannot get CTF errors: `%s'\n"),
+            ctf_errmsg (err));
+    }
+
+  /* `err' returns errors from the error/warning iterator in particular.
+     These never assert.  But if we have an fp, that could have recorded
+     an assertion failure: assert if it has done so.  */
+  ASSERT (!fp || ctf_errno (fp) != ECTF_INTERNAL);
+}
+
+/* Open the CTF sections in the input files with libctf: if any were opened,
+   create a fake input file that we'll write the merged CTF data to later
+   on.  */
+
+static void
+ldlang_open_ctf (void)
+{
+  int any_ctf = 0;
+  int err;
+
+  LANG_FOR_EACH_INPUT_STATEMENT (file)
+    {
+      asection *sect;
+
+      /* Incoming files from the compiler have a single ctf_dict_t in them
+        (which is presented to us by the libctf API in a ctf_archive_t
+        wrapper): files derived from a previous relocatable link have a CTF
+        archive containing possibly many CTF files.  */
+
+      if ((file->the_ctf = ctf_bfdopen (file->the_bfd, &err)) == NULL)
+       {
+         if (err != ECTF_NOCTFDATA)
+           {
+             lang_ctf_errs_warnings (NULL);
+             einfo (_("%P: warning: CTF section in %pB not loaded; "
+                      "its types will be discarded: %s\n"), file->the_bfd,
+                    ctf_errmsg (err));
+           }
+         continue;
+       }
+
+      /* Prevent the contents of this section from being written, while
+        requiring the section itself to be duplicated in the output, but only
+        once.  */
+      /* This section must exist if ctf_bfdopen() succeeded.  */
+      sect = bfd_get_section_by_name (file->the_bfd, ".ctf");
+      sect->size = 0;
+      sect->flags |= SEC_NEVER_LOAD | SEC_HAS_CONTENTS | SEC_LINKER_CREATED;
+
+      if (any_ctf)
+       sect->flags |= SEC_EXCLUDE;
+      any_ctf = 1;
+    }
+
+  if (!any_ctf)
+    {
+      ctf_output = NULL;
+      return;
+    }
+
+  if ((ctf_output = ctf_create (&err)) != NULL)
+    return;
+
+  einfo (_("%P: warning: CTF output not created: `%s'\n"),
+        ctf_errmsg (err));
+
+  LANG_FOR_EACH_INPUT_STATEMENT (errfile)
+    ctf_close (errfile->the_ctf);
+}
+
+/* Merge together CTF sections.  After this, only the symtab-dependent
+   function and data object sections need adjustment.  */
+
+static void
+lang_merge_ctf (void)
+{
+  asection *output_sect;
+  int flags = 0;
+
+  if (!ctf_output)
+    return;
+
+  output_sect = bfd_get_section_by_name (link_info.output_bfd, ".ctf");
+
+  /* If the section was discarded, don't waste time merging.  */
+  if (output_sect == NULL)
+    {
+      ctf_dict_close (ctf_output);
+      ctf_output = NULL;
+
+      LANG_FOR_EACH_INPUT_STATEMENT (file)
+       {
+         ctf_close (file->the_ctf);
+         file->the_ctf = NULL;
+       }
+      return;
+    }
+
+  LANG_FOR_EACH_INPUT_STATEMENT (file)
+    {
+      if (!file->the_ctf)
+       continue;
+
+      /* Takes ownership of file->the_ctf.  */
+      if (ctf_link_add_ctf (ctf_output, file->the_ctf, file->filename) < 0)
+       {
+         einfo (_("%P: warning: CTF section in %pB cannot be linked: `%s'\n"),
+                file->the_bfd, ctf_errmsg (ctf_errno (ctf_output)));
+         ctf_close (file->the_ctf);
+         file->the_ctf = NULL;
+         continue;
+       }
+    }
+
+  if (!config.ctf_share_duplicated)
+    flags = CTF_LINK_SHARE_UNCONFLICTED;
+  else
+    flags = CTF_LINK_SHARE_DUPLICATED;
+  if (!config.ctf_variables)
+    flags |= CTF_LINK_OMIT_VARIABLES_SECTION;
+
+  if (ctf_link (ctf_output, flags) < 0)
+    {
+      lang_ctf_errs_warnings (ctf_output);
+      einfo (_("%P: warning: CTF linking failed; "
+              "output will have no CTF section: %s\n"),
+            ctf_errmsg (ctf_errno (ctf_output)));
+      if (output_sect)
+       {
+         output_sect->size = 0;
+         output_sect->flags |= SEC_EXCLUDE;
+       }
+    }
+  /* Output any lingering errors that didn't come from ctf_link.  */
+  lang_ctf_errs_warnings (ctf_output);
+}
+
+/* Let the emulation acquire strings from the dynamic strtab to help it optimize
+   the CTF, if supported.  */
+
+void
+ldlang_ctf_acquire_strings (struct elf_strtab_hash *dynstrtab)
+{
+  ldemul_acquire_strings_for_ctf (ctf_output, dynstrtab);
+}
+
+/* Inform the emulation about the addition of a new dynamic symbol, in BFD
+   internal format.  */
+void ldlang_ctf_new_dynsym (int symidx, struct elf_internal_sym *sym)
+{
+  ldemul_new_dynsym_for_ctf (ctf_output, symidx, sym);
+}
+
+/* Write out the CTF section.  Called early, if the emulation isn't going to
+   need to dedup against the strtab and symtab, then possibly called from the
+   target linker code if the dedup has happened.  */
+static void
+lang_write_ctf (int late)
+{
+  size_t output_size;
+  asection *output_sect;
+
+  if (!ctf_output)
+    return;
+
+  if (late)
+    {
+      /* Emit CTF late if this emulation says it can do so.  */
+      if (ldemul_emit_ctf_early ())
+       return;
+    }
+  else
+    {
+      if (!ldemul_emit_ctf_early ())
+       return;
+    }
+
+  /* Inform the emulation that all the symbols that will be received have
+     been.  */
+
+  ldemul_new_dynsym_for_ctf (ctf_output, 0, NULL);
+
+  /* Emit CTF.  */
+
+  output_sect = bfd_get_section_by_name (link_info.output_bfd, ".ctf");
+  if (output_sect)
+    {
+      output_sect->contents = ctf_link_write (ctf_output, &output_size,
+                                             CTF_COMPRESSION_THRESHOLD);
+      output_sect->size = output_size;
+      output_sect->flags |= SEC_IN_MEMORY | SEC_KEEP;
+
+      lang_ctf_errs_warnings (ctf_output);
+      if (!output_sect->contents)
+       {
+         einfo (_("%P: warning: CTF section emission failed; "
+                  "output will have no CTF section: %s\n"),
+                ctf_errmsg (ctf_errno (ctf_output)));
+         output_sect->size = 0;
+         output_sect->flags |= SEC_EXCLUDE;
+       }
+    }
+
+  /* This also closes every CTF input file used in the link.  */
+  ctf_dict_close (ctf_output);
+  ctf_output = NULL;
+
+  LANG_FOR_EACH_INPUT_STATEMENT (file)
+    file->the_ctf = NULL;
+}
+
+/* Write out the CTF section late, if the emulation needs that.  */
+
+void
+ldlang_write_ctf_late (void)
+{
+  /* Trigger a "late call", if the emulation needs one.  */
+
+  lang_write_ctf (1);
+}
+#else
+static void
+ldlang_open_ctf (void)
+{
+  LANG_FOR_EACH_INPUT_STATEMENT (file)
+    {
+      asection *sect;
+
+      /* If built without CTF, warn and delete all CTF sections from the output.
+        (The alternative would be to simply concatenate them, which does not
+        yield a valid CTF section.)  */
+
+      if ((sect = bfd_get_section_by_name (file->the_bfd, ".ctf")) != NULL)
+       {
+           einfo (_("%P: warning: CTF section in %pB not linkable: "
+                    "%P was built without support for CTF\n"), file->the_bfd);
+           sect->size = 0;
+           sect->flags |= SEC_EXCLUDE;
+       }
+    }
+}
+
+static void lang_merge_ctf (void) {}
+void
+ldlang_ctf_acquire_strings (struct elf_strtab_hash *dynstrtab
+                           ATTRIBUTE_UNUSED) {}
+void
+ldlang_ctf_new_dynsym (int symidx ATTRIBUTE_UNUSED,
+                      struct elf_internal_sym *sym ATTRIBUTE_UNUSED) {}
+static void lang_write_ctf (int late ATTRIBUTE_UNUSED) {}
+void ldlang_write_ctf_late (void) {}
+#endif
+
 /* Add the supplied name to the symbol table as an undefined reference.
    This is a two step process as the symbol table doesn't even exist at
    the time the ld command line is processed.  First we put the name
@@ -3601,12 +3953,11 @@ typedef struct bfd_sym_chain ldlang_undef_chain_list_type;
 #define ldlang_undef_chain_list_head entry_symbol.next
 
 void
-ldlang_add_undef (const char *const name, bfd_boolean cmdline)
+ldlang_add_undef (const char *const name, bfd_boolean cmdline ATTRIBUTE_UNUSED)
 {
   ldlang_undef_chain_list_type *new_undef;
 
-  undef_from_cmdline = undef_from_cmdline || cmdline;
-  new_undef = (ldlang_undef_chain_list_type *) stat_alloc (sizeof (*new_undef));
+  new_undef = stat_alloc (sizeof (*new_undef));
   new_undef->next = ldlang_undef_chain_list_head;
   ldlang_undef_chain_list_head = new_undef;
 
@@ -3672,7 +4023,7 @@ ldlang_add_require_defined (const char *const name)
   struct require_defined_symbol *ptr;
 
   ldlang_add_undef (name, TRUE);
-  ptr = (struct require_defined_symbol *) stat_alloc (sizeof (*ptr));
+  ptr = stat_alloc (sizeof (*ptr));
   ptr->next = require_defined_symbol_list;
   ptr->name = strdup (name);
   require_defined_symbol_list = ptr;
@@ -3706,7 +4057,7 @@ check_input_sections
   (lang_statement_union_type *s,
    lang_output_section_statement_type *output_section_statement)
 {
-  for (; s != (lang_statement_union_type *) NULL; s = s->header.next)
+  for (; s != NULL; s = s->header.next)
     {
       switch (s->header.type)
        {
@@ -3824,22 +4175,18 @@ map_input_to_output_sections
          break;
        case lang_output_section_statement_enum:
          tos = &s->output_section_statement;
-         if (tos->constraint != 0)
+         if (tos->constraint == ONLY_IF_RW
+             || tos->constraint == ONLY_IF_RO)
            {
-             if (tos->constraint != ONLY_IF_RW
-                 && tos->constraint != ONLY_IF_RO)
-               break;
              tos->all_input_readonly = TRUE;
              check_input_sections (tos->children.head, tos);
              if (tos->all_input_readonly != (tos->constraint == ONLY_IF_RO))
-               {
-                 tos->constraint = -1;
-                 break;
-               }
+               tos->constraint = -1;
            }
-         map_input_to_output_sections (tos->children.head,
-                                       target,
-                                       tos);
+         if (tos->constraint >= 0)
+           map_input_to_output_sections (tos->children.head,
+                                         target,
+                                         tos);
          break;
        case lang_output_statement_enum:
          break;
@@ -3919,7 +4266,7 @@ map_input_to_output_sections
                 place them in amongst other sections then the address
                 will affect following script sections, which is
                 likely to surprise naive users.  */
-             tos = lang_output_section_statement_lookup (name, 0, TRUE);
+             tos = lang_output_section_statement_lookup (name, 0, 1);
              tos->addr_tree = s->address_statement.address;
              if (tos->bfd_section == NULL)
                init_os (tos, 0);
@@ -3992,6 +4339,12 @@ process_insert_statements (lang_statement_union_type **start)
          lang_statement_union_type **ptr;
          lang_statement_union_type *first;
 
+         if (link_info.non_contiguous_regions)
+           {
+             einfo (_("warning: INSERT statement in linker script is "
+                      "incompatible with --enable-non-contiguous-regions.\n"));
+           }
+
          where = lang_output_section_find (i->where);
          if (where != NULL && i->is_before)
            {
@@ -4127,7 +4480,7 @@ strip_excluded_output_sections (void)
       lang_reset_memory_regions ();
     }
 
-  for (os = &lang_os_list.head->output_section_statement;
+  for (os = (void *) lang_os_list.head;
        os != NULL;
        os = os->next)
     {
@@ -4188,7 +4541,7 @@ lang_clear_os_map (void)
   if (map_head_is_link_order)
     return;
 
-  for (os = &lang_os_list.head->output_section_statement;
+  for (os = (void *) lang_os_list.head;
        os != NULL;
        os = os->next)
     {
@@ -4346,16 +4699,14 @@ print_assignment (lang_assignment_statement_type *assignment,
 static void
 print_input_statement (lang_input_statement_type *statm)
 {
-  if (statm->filename != NULL
-      && (statm->the_bfd == NULL
-         || (statm->the_bfd->flags & BFD_LINKER_CREATED) == 0))
+  if (statm->filename != NULL)
     fprintf (config.map_file, "LOAD %s\n", statm->filename);
 }
 
 /* Print all symbols defined in a particular section.  This is called
    via bfd_link_hash_traverse, or by print_all_symbols.  */
 
-static bfd_boolean
+bfd_boolean
 print_one_symbol (struct bfd_link_hash_entry *hash_entry, void *ptr)
 {
   asection *sec = (asection *) ptr;
@@ -4396,8 +4747,7 @@ hash_entry_addr_cmp (const void *a, const void *b)
 static void
 print_all_symbols (asection *sec)
 {
-  input_section_userdata_type *ud
-    = (input_section_userdata_type *) get_userdata (sec);
+  input_section_userdata_type *ud = bfd_section_userdata (sec);
   struct map_symbol_def *def;
   struct bfd_link_hash_entry **entries;
   unsigned int i;
@@ -4420,7 +4770,7 @@ print_all_symbols (asection *sec)
 
   /* Print the symbols.  */
   for (i = 0; i < ud->map_symbol_def_count; i++)
-    print_one_symbol (entries[i], sec);
+    ldemul_print_symbol (entries[i], sec);
 
   obstack_free (&map_obstack, entries);
 }
@@ -4434,7 +4784,7 @@ print_input_section (asection *i, bfd_boolean is_discarded)
   int len;
   bfd_vma addr;
 
-  init_opb ();
+  init_opb (i);
 
   print_space ();
   minfo ("%s", i->name);
@@ -4461,7 +4811,7 @@ print_input_section (asection *i, bfd_boolean is_discarded)
        size = 0;
     }
 
-  minfo ("0x%V %W %pB\n", addr, size, i->owner);
+  minfo ("0x%V %W %pB\n", addr, TO_ADDR (size), i->owner);
 
   if (size != i->rawsize && i->rawsize != 0)
     {
@@ -4477,14 +4827,14 @@ print_input_section (asection *i, bfd_boolean is_discarded)
          --len;
        }
 
-      minfo (_("%W (size before relaxing)\n"), i->rawsize);
+      minfo (_("%W (size before relaxing)\n"), TO_ADDR (i->rawsize));
     }
 
   if (i->output_section != NULL
       && i->output_section->owner == link_info.output_bfd)
     {
       if (link_info.reduce_memory_overheads)
-       bfd_link_hash_traverse (link_info.hash, print_one_symbol, i);
+       bfd_link_hash_traverse (link_info.hash, ldemul_print_symbol, i);
       else
        print_all_symbols (i);
 
@@ -4515,7 +4865,7 @@ print_data_statement (lang_data_statement_type *data)
   bfd_size_type size;
   const char *name;
 
-  init_opb ();
+  init_opb (data->output_section);
   for (i = 0; i < SECTION_NAME_MAP_LENGTH; i++)
     print_space ();
 
@@ -4584,7 +4934,7 @@ print_reloc_statement (lang_reloc_statement_type *reloc)
   bfd_vma addr;
   bfd_size_type size;
 
-  init_opb ();
+  init_opb (reloc->output_section);
   for (i = 0; i < SECTION_NAME_MAP_LENGTH; i++)
     print_space ();
 
@@ -4614,7 +4964,7 @@ print_padding_statement (lang_padding_statement_type *s)
   int len;
   bfd_vma addr;
 
-  init_opb ();
+  init_opb (s->output_section);
   minfo (" *fill*");
 
   len = sizeof " *fill*" - 1;
@@ -4894,8 +5244,7 @@ insert_pad (lang_statement_union_type **ptr,
   else
     {
       /* Make a new padding statement, linked into existing chain.  */
-      pad = (lang_statement_union_type *)
-         stat_alloc (sizeof (lang_padding_statement_type));
+      pad = stat_alloc (sizeof (lang_padding_statement_type));
       pad->header.next = *ptr;
       *ptr = pad;
       pad->header.type = lang_padding_statement_enum;
@@ -4918,11 +5267,27 @@ size_input_section
   (lang_statement_union_type **this_ptr,
    lang_output_section_statement_type *output_section_statement,
    fill_type *fill,
+   bfd_boolean *removed,
    bfd_vma dot)
 {
   lang_input_section_type *is = &((*this_ptr)->input_section);
   asection *i = is->section;
   asection *o = output_section_statement->bfd_section;
+  *removed = 0;
+
+  if (link_info.non_contiguous_regions)
+    {
+      /* If the input section I has already been successfully assigned
+        to an output section other than O, don't bother with it and
+        let the caller remove it from the list.  Keep processing in
+        case we have already handled O, because the repeated passes
+        have reinitialized its size.  */
+      if (i->already_assigned && i->already_assigned != o)
+       {
+         *removed = 1;
+         return dot;
+       }
+    }
 
   if (i->sec_info_type == SEC_INFO_TYPE_JUST_SYMS)
     i->output_offset = i->vma - o->vma;
@@ -4954,6 +5319,36 @@ size_input_section
          dot += alignment_needed;
        }
 
+      if (link_info.non_contiguous_regions)
+       {
+         /* If I would overflow O, let the caller remove I from the
+            list.  */
+         if (output_section_statement->region)
+           {
+             bfd_vma end = output_section_statement->region->origin
+               + output_section_statement->region->length;
+
+             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);
+
+                 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);
+
+                 *removed = 1;
+                 dot = end;
+                 i->output_section = NULL;
+                 return dot;
+               }
+           }
+       }
+
       /* Remember where in the output section this input section goes.  */
       i->output_offset = dot - o->vma;
 
@@ -4961,6 +5356,14 @@ size_input_section
       dot += TO_ADDR (i->size);
       if (!(o->flags & SEC_FIXED_SIZE))
        o->size = TO_SIZE (dot - o->vma);
+
+      if (link_info.non_contiguous_regions)
+       {
+         /* Record that I was successfully assigned to O, and update
+            its actual output section too.  */
+         i->already_assigned = o;
+         i->output_section = o;
+       }
     }
 
   return dot;
@@ -5085,6 +5488,7 @@ lang_check_section_addresses (void)
   for (p = NULL, i = 0; i < count; i++)
     {
       s = sections[i].sec;
+      init_opb (s);
       if ((s->flags & SEC_LOAD) != 0)
        {
          s_start = s->lma;
@@ -5135,6 +5539,7 @@ lang_check_section_addresses (void)
       for (p = NULL, i = 0; i < count; i++)
        {
          s = sections[i].sec;
+         init_opb (s);
          s_start = s->vma;
          s_end = s_start + TO_ADDR (s->size) - 1;
 
@@ -5245,10 +5650,14 @@ lang_size_sections_1
    bfd_boolean check_regions)
 {
   lang_statement_union_type *s;
+  lang_statement_union_type *prev_s = NULL;
+  bfd_boolean removed_prev_s = FALSE;
 
   /* Size up the sections from their constituent parts.  */
-  for (s = *prev; s != NULL; s = s->header.next)
+  for (s = *prev; s != NULL; prev_s = s, s = s->header.next)
     {
+      bfd_boolean removed=FALSE;
+
       switch (s->header.type)
        {
        case lang_output_section_statement_enum:
@@ -5259,6 +5668,7 @@ lang_size_sections_1
            int section_alignment = 0;
 
            os = &s->output_section_statement;
+           init_opb (os->bfd_section);
            if (os->constraint == -1)
              break;
 
@@ -5311,9 +5721,8 @@ lang_size_sections_1
                           " section %s\n"), os->name);
 
                input = os->children.head->input_section.section;
-               bfd_set_section_vma (os->bfd_section->owner,
-                                    os->bfd_section,
-                                    bfd_section_vma (input->owner, input));
+               bfd_set_section_vma (os->bfd_section,
+                                    bfd_section_vma (input));
                if (!(os->bfd_section->flags & SEC_FIXED_SIZE))
                  os->bfd_section->size = input->size;
                break;
@@ -5354,7 +5763,7 @@ lang_size_sections_1
                        && (strcmp (lang_memory_region_list->name_list.name,
                                    DEFAULT_MEMORY_REGION) != 0
                            || lang_memory_region_list->next != NULL)
-                       && expld.phase != lang_mark_phase_enum)
+                       && lang_sizing_iteration == 1)
                      {
                        /* By default this is an error rather than just a
                           warning because if we allocate the section to the
@@ -5368,13 +5777,11 @@ lang_size_sections_1
                        if (command_line.check_section_addresses)
                          einfo (_("%F%P: error: no memory region specified"
                                   " for loadable section `%s'\n"),
-                                bfd_get_section_name (link_info.output_bfd,
-                                                      os->bfd_section));
+                                bfd_section_name (os->bfd_section));
                        else
                          einfo (_("%P: warning: no memory region specified"
                                   " for loadable section `%s'\n"),
-                                bfd_get_section_name (link_info.output_bfd,
-                                                      os->bfd_section));
+                                bfd_section_name (os->bfd_section));
                      }
 
                    newdot = os->region->current;
@@ -5388,22 +5795,30 @@ lang_size_sections_1
                if (section_alignment > 0)
                  {
                    bfd_vma savedot = newdot;
-                   newdot = align_power (newdot, section_alignment);
+                   bfd_vma diff = 0;
 
+                   newdot = align_power (newdot, section_alignment);
                    dotdelta = newdot - savedot;
-                   if (dotdelta != 0
+
+                   if (lang_sizing_iteration == 1)
+                     diff = dotdelta;
+                   else if (lang_sizing_iteration > 1)
+                     {
+                       /* Only report adjustments that would change
+                          alignment from what we have already reported.  */
+                       diff = newdot - os->bfd_section->vma;
+                       if (!(diff & (((bfd_vma) 1 << section_alignment) - 1)))
+                         diff = 0;
+                     }
+                   if (diff != 0
                        && (config.warn_section_align
-                           || os->addr_tree != NULL)
-                       && expld.phase != lang_mark_phase_enum)
-                     einfo (ngettext ("%P: warning: changing start of "
-                                      "section %s by %lu byte\n",
-                                      "%P: warning: changing start of "
-                                      "section %s by %lu bytes\n",
-                                      (unsigned long) dotdelta),
-                            os->name, (unsigned long) dotdelta);
+                           || os->addr_tree != NULL))
+                     einfo (_("%P: warning: "
+                              "start of section %s changed by %ld\n"),
+                            os->name, (long) diff);
                  }
 
-               bfd_set_section_vma (0, os->bfd_section, newdot);
+               bfd_set_section_vma (os->bfd_section, newdot);
 
                os->bfd_section->output_offset = 0;
              }
@@ -5503,7 +5918,7 @@ lang_size_sections_1
                    /* Otherwise, keep the same lma to vma relationship
                       as the previous section.  */
                    else
-                     lma = dot + last->lma - last->vma;
+                     lma = os->bfd_section->vma + last->lma - last->vma;
 
                    if (section_alignment > 0)
                      lma = align_power (lma, section_alignment);
@@ -5676,7 +6091,7 @@ lang_size_sections_1
                  *relax = TRUE;
              }
            dot = size_input_section (prev, output_section_statement,
-                                     fill, dot);
+                                     fill, &removed, dot);
          }
          break;
 
@@ -5781,7 +6196,43 @@ lang_size_sections_1
          FAIL ();
          break;
        }
-      prev = &s->header.next;
+
+      /* If an input section doesn't fit in the current output
+        section, remove it from the list.  Handle the case where we
+        have to remove an input_section statement here: there is a
+        special case to remove the first element of the list.  */
+      if (link_info.non_contiguous_regions && removed)
+       {
+         /* If we removed the first element during the previous
+            iteration, override the loop assignment of prev_s.  */
+         if (removed_prev_s)
+             prev_s = NULL;
+
+         if (prev_s)
+           {
+             /* If there was a real previous input section, just skip
+                the current one.  */
+             prev_s->header.next=s->header.next;
+             s = prev_s;
+             removed_prev_s = FALSE;
+           }
+         else
+           {
+             /* Remove the first input section of the list.  */
+             *prev = s->header.next;
+             removed_prev_s = TRUE;
+           }
+
+         /* Move to next element, unless we removed the head of the
+            list.  */
+         if (!removed_prev_s)
+           prev = &s->header.next;
+       }
+      else
+       {
+         prev = &s->header.next;
+         removed_prev_s = FALSE;
+       }
     }
   return dot;
 }
@@ -5838,6 +6289,8 @@ void
 one_lang_size_sections_pass (bfd_boolean *relax, bfd_boolean check_regions)
 {
   lang_statement_iteration++;
+  if (expld.phase != lang_mark_phase_enum)
+    lang_sizing_iteration++;
   lang_size_sections_1 (&statement_list.head, abs_output_section,
                        0, 0, relax, check_regions);
 }
@@ -6003,6 +6456,7 @@ lang_do_assignments_1 (lang_statement_union_type *s,
 
            os = &(s->output_section_statement);
            os->after_end = *found_end;
+           init_opb (os->bfd_section);
            if (os->bfd_section != NULL && !os->ignored)
              {
                if ((os->bfd_section->flags & SEC_ALLOC) != 0)
@@ -6438,10 +6892,24 @@ lang_end (void)
      --gc-sections, unless --gc-keep-exported was also given.  */
   if (bfd_link_relocatable (&link_info)
       && link_info.gc_sections
-      && !link_info.gc_keep_exported
-      && !(entry_from_cmdline || undef_from_cmdline))
-    einfo (_("%F%P: gc-sections requires either an entry or "
-            "an undefined symbol\n"));
+      && !link_info.gc_keep_exported)
+    {
+      struct bfd_sym_chain *sym;
+
+      for (sym = link_info.gc_sym_list; sym != NULL; sym = sym->next)
+       {
+         h = bfd_link_hash_lookup (link_info.hash, sym->name,
+                                   FALSE, FALSE, FALSE);
+         if (h != NULL
+             && (h->type == bfd_link_hash_defined
+                 || h->type == bfd_link_hash_defweak)
+             && !bfd_is_const_section (h->u.def.section))
+           break;
+       }
+      if (!sym)
+       einfo (_("%F%P: --gc-sections requires a defined symbol root "
+                "specified by -e or -u\n"));
+    }
 
   if (entry_symbol.name == NULL)
     {
@@ -6461,8 +6929,7 @@ lang_end (void)
       bfd_vma val;
 
       val = (h->u.def.value
-            + bfd_get_section_vma (link_info.output_bfd,
-                                   h->u.def.section->output_section)
+            + bfd_section_vma (h->u.def.section->output_section)
             + h->u.def.section->output_offset);
       if (!bfd_set_start_address (link_info.output_bfd, val))
        einfo (_("%F%P: %s: can't set start address\n"), entry_symbol.name);
@@ -6493,10 +6960,9 @@ lang_end (void)
                einfo (_("%P: warning: cannot find entry symbol %s;"
                         " defaulting to %V\n"),
                       entry_symbol.name,
-                      bfd_get_section_vma (link_info.output_bfd, ts));
-             if (!(bfd_set_start_address
-                   (link_info.output_bfd,
-                    bfd_get_section_vma (link_info.output_bfd, ts))))
+                      bfd_section_vma (ts));
+             if (!bfd_set_start_address (link_info.output_bfd,
+                                         bfd_section_vma (ts)))
                einfo (_("%F%P: can't set start address\n"));
            }
          else
@@ -6531,15 +6997,15 @@ lang_check (void)
   bfd *input_bfd;
   const bfd_arch_info_type *compatible;
 
-  for (file = &file_chain.head->input_statement;
+  for (file = (void *) file_chain.head;
        file != NULL;
        file = file->next)
     {
-#ifdef ENABLE_PLUGINS
+#if BFD_SUPPORTS_PLUGINS
       /* Don't check format of files claimed by plugin.  */
       if (file->flags.claimed)
        continue;
-#endif /* ENABLE_PLUGINS */
+#endif /* BFD_SUPPORTS_PLUGINS */
       input_bfd = file->the_bfd;
       compatible
        = bfd_arch_get_compatible (input_bfd, link_info.output_bfd,
@@ -6551,8 +7017,9 @@ lang_check (void)
         input format may not have equivalent representations in
         the output format (and besides BFD does not translate
         relocs for other link purposes than a final link).  */
-      if ((bfd_link_relocatable (&link_info)
-          || link_info.emitrelocations)
+      if (!file->flags.just_syms
+         && (bfd_link_relocatable (&link_info)
+             || link_info.emitrelocations)
          && (compatible == NULL
              || (bfd_get_flavour (input_bfd)
                  != bfd_get_flavour (link_info.output_bfd)))
@@ -6573,11 +7040,13 @@ lang_check (void)
                   bfd_printable_name (input_bfd), input_bfd,
                   bfd_printable_name (link_info.output_bfd));
        }
-      else if (bfd_count_sections (input_bfd))
-       {
-         /* If the input bfd has no contents, it shouldn't set the
-            private data of the output bfd.  */
 
+      /* If the input bfd has no contents, it shouldn't set the
+        private data of the output bfd.  */
+      else if (!file->flags.just_syms
+              && ((input_bfd->flags & DYNAMIC) != 0
+                  || bfd_count_sections (input_bfd) != 0))
+       {
          bfd_error_handler_type pfn = NULL;
 
          /* If we aren't supposed to warn about mismatched input
@@ -6733,8 +7202,7 @@ ldlang_place_orphan (asection *s)
   if (config.orphan_handling == orphan_handling_discard)
     {
       lang_output_section_statement_type *os;
-      os = lang_output_section_statement_lookup (DISCARD_SECTION_NAME, 0,
-                                                TRUE);
+      os = lang_output_section_statement_lookup (DISCARD_SECTION_NAME, 0, 1);
       if (os->addr_tree == NULL
          && (bfd_link_relocatable (&link_info)
              || (s->flags & (SEC_LOAD | SEC_ALLOC)) == 0))
@@ -6757,7 +7225,7 @@ ldlang_place_orphan (asection *s)
       os = ldemul_place_orphan (s, name, constraint);
       if (os == NULL)
        {
-         os = lang_output_section_statement_lookup (name, constraint, TRUE);
+         os = lang_output_section_statement_lookup (name, constraint, 1);
          if (os->addr_tree == NULL
              && (bfd_link_relocatable (&link_info)
                  || (s->flags & (SEC_LOAD | SEC_ALLOC)) == 0))
@@ -6804,8 +7272,7 @@ lang_place_orphans (void)
                    {
                      if (default_common_section == NULL)
                        default_common_section
-                         = lang_output_section_statement_lookup (".bss", 0,
-                                                                 TRUE);
+                         = lang_output_section_statement_lookup (".bss", 0, 1);
                      lang_add_section (&default_common_section->children, s,
                                        NULL, default_common_section);
                    }
@@ -6865,30 +7332,32 @@ lang_set_flags (lang_memory_region_type *ptr, const char *flags, int invert)
     }
 }
 
-/* Call a function on each input file.  This function will be called
-   on an archive, but not on the elements.  */
+/* Call a function on each real input file.  This function will be
+   called on an archive, but not on the elements.  */
 
 void
 lang_for_each_input_file (void (*func) (lang_input_statement_type *))
 {
   lang_input_statement_type *f;
 
-  for (f = &input_file_chain.head->input_statement;
+  for (f = (void *) input_file_chain.head;
        f != NULL;
        f = f->next_real_file)
-    func (f);
+    if (f->flags.real)
+      func (f);
 }
 
-/* Call a function on each file.  The function will be called on all
-   the elements of an archive which are included in the link, but will
-   not be called on the archive file itself.  */
+/* Call a function on each real file.  The function will be called on
+   all the elements of an archive which are included in the link, but
+   will not be called on the archive file itself.  */
 
 void
 lang_for_each_file (void (*func) (lang_input_statement_type *))
 {
   LANG_FOR_EACH_INPUT_STATEMENT (f)
     {
-      func (f);
+      if (f->flags.real)
+       func (f);
     }
 }
 
@@ -6899,12 +7368,13 @@ ldlang_add_file (lang_input_statement_type *entry)
 
   /* The BFD linker needs to have a list of all input BFDs involved in
      a link.  */
-  ASSERT (entry->the_bfd->link.next == NULL);
+  ASSERT (link_info.input_bfds_tail != &entry->the_bfd->link.next
+         && entry->the_bfd->link.next == NULL);
   ASSERT (entry->the_bfd != link_info.output_bfd);
 
   *link_info.input_bfds_tail = entry->the_bfd;
   link_info.input_bfds_tail = &entry->the_bfd->link.next;
-  entry->the_bfd->usrdata = entry;
+  bfd_set_usrdata (entry->the_bfd, entry);
   bfd_set_gp_size (entry->the_bfd, g_switch_value);
 
   /* Look through the sections and check for any which should not be
@@ -6944,7 +7414,7 @@ lang_enter_output_section_statement (const char *output_section_statement_name,
   lang_output_section_statement_type *os;
 
   os = lang_output_section_statement_lookup (output_section_statement_name,
-                                            constraint, TRUE);
+                                            constraint, 2);
   current_section = os;
 
   if (os->addr_tree == NULL)
@@ -6997,7 +7467,7 @@ lang_reset_memory_regions (void)
       p->last_os = NULL;
     }
 
-  for (os = &lang_os_list.head->output_section_statement;
+  for (os = (void *) lang_os_list.head;
        os != NULL;
        os = os->next)
     {
@@ -7071,7 +7541,7 @@ lang_gc_sections (void)
       LANG_FOR_EACH_INPUT_STATEMENT (f)
        {
          asection *sec;
-#ifdef ENABLE_PLUGINS
+#if BFD_SUPPORTS_PLUGINS
          if (f->flags.claimed)
            continue;
 #endif
@@ -7218,7 +7688,7 @@ lang_relax_sections (bfd_boolean need_layout)
     }
 }
 
-#ifdef ENABLE_PLUGINS
+#if BFD_SUPPORTS_PLUGINS
 /* Find the insert point for the plugin's replacement files.  We
    place them after the first claimed real object file, or if the
    first claimed object is an archive member, after the last real
@@ -7234,8 +7704,8 @@ static lang_input_statement_type *
 find_replacements_insert_point (bfd_boolean *before)
 {
   lang_input_statement_type *claim1, *lastobject;
-  lastobject = &input_file_chain.head->input_statement;
-  for (claim1 = &file_chain.head->input_statement;
+  lastobject = (void *) input_file_chain.head;
+  for (claim1 = (void *) file_chain.head;
        claim1 != NULL;
        claim1 = claim1->next)
     {
@@ -7277,7 +7747,7 @@ find_rescan_insertion (lang_input_statement_type *add)
      file chain if it is full of archive elements.  Archives don't
      appear on the file chain, but if an element has been extracted
      then their input_statement->next points at it.  */
-  for (f = &input_file_chain.head->input_statement;
+  for (f = (void *) input_file_chain.head;
        f != NULL;
        f = f->next_real_file)
     {
@@ -7361,7 +7831,7 @@ find_next_input_statement (lang_statement_union_type **s)
     }
   return s;
 }
-#endif /* ENABLE_PLUGINS */
+#endif /* BFD_SUPPORTS_PLUGINS */
 
 /* Add NAME to the list of garbage collection entry points.  */
 
@@ -7373,7 +7843,7 @@ lang_add_gc_name (const char *name)
   if (name == NULL)
     return;
 
-  sym = (struct bfd_sym_chain *) stat_alloc (sizeof (*sym));
+  sym = stat_alloc (sizeof (*sym));
 
   sym->next = link_info.gc_sym_list;
   sym->name = name;
@@ -7410,7 +7880,7 @@ lang_propagate_lma_regions (void)
 {
   lang_output_section_statement_type *os;
 
-  for (os = &lang_os_list.head->output_section_statement;
+  for (os = (void *) lang_os_list.head;
        os != NULL;
        os = os->next)
     {
@@ -7434,7 +7904,7 @@ lang_process (void)
 
   /* Open the output file.  */
   lang_for_each_statement (ldlang_open_output);
-  init_opb ();
+  init_opb (NULL);
 
   ldemul_create_output_section_statements ();
 
@@ -7444,15 +7914,24 @@ lang_process (void)
   if (!bfd_section_already_linked_table_init ())
     einfo (_("%F%P: can not create hash table: %E\n"));
 
+  /* A first pass through the memory regions ensures that if any region
+     references a symbol for its origin or length then this symbol will be
+     added to the symbol table.  Having these symbols in the symbol table
+     means that when we call open_input_bfds PROVIDE statements will
+     trigger to provide any needed symbols.  The regions origins and
+     lengths are not assigned as a result of this call.  */
+  lang_do_memory_regions (FALSE);
+
   /* 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 also handles assignments, so we can give values
-     to symbolic origin/length now.  */
-  lang_do_memory_regions ();
 
-#ifdef ENABLE_PLUGINS
+  /* 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);
+
+#if BFD_SUPPORTS_PLUGINS
   if (link_info.lto_plugin_active)
     {
       lang_statement_list_type added;
@@ -7471,6 +7950,7 @@ lang_process (void)
       if (plugin_call_all_symbols_read ())
        einfo (_("%F%P: %s: plugin reported error after all symbols read\n"),
               plugin_error_plugin ());
+      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);
@@ -7503,8 +7983,8 @@ lang_process (void)
              prev = find_next_input_statement (prev);
              if (*prev != (void *) plugin_insert->next_real_file)
                {
-                 /* Huh?  We didn't find the expected input statement.  */
-                 ASSERT (0);
+                 /* We didn't find the expected input statement.
+                    Fall back to adding after plugin_insert.  */
                  prev = &plugin_insert->header.next;
                }
            }
@@ -7546,7 +8026,7 @@ lang_process (void)
              *iter = temp;
              if (my_arch != NULL)
                {
-                 lang_input_statement_type *parent = my_arch->usrdata;
+                 lang_input_statement_type *parent = bfd_usrdata (my_arch);
                  if (parent != NULL)
                    parent->next = (lang_input_statement_type *)
                      ((char *) iter
@@ -7555,7 +8035,7 @@ lang_process (void)
            }
        }
     }
-#endif /* ENABLE_PLUGINS */
+#endif /* BFD_SUPPORTS_PLUGINS */
 
   /* Make sure that nobody has tried to add a symbol to this list
      before now.  */
@@ -7585,6 +8065,8 @@ lang_process (void)
   if (config.map_file != NULL)
     lang_print_asneeded ();
 
+  ldlang_open_ctf ();
+
   bfd_section_already_linked_table_free ();
 
   /* Make sure that we're not mixing architectures.  We call this
@@ -7636,6 +8118,8 @@ lang_process (void)
      output statement, so that it isn't reordered.  */
   process_insert_statements (&lang_os_list.head->header.next);
 
+  ldemul_before_place_orphans ();
+
   /* Find any sections not attached explicitly and handle them.  */
   lang_place_orphans ();
 
@@ -7661,6 +8145,14 @@ lang_process (void)
        }
     }
 
+  /* Merge together CTF sections.  After this, only the symtab-dependent
+     function and data object sections need adjustment.  */
+  lang_merge_ctf ();
+
+  /* Emit the CTF, iff the emulation doesn't need to do late emission after
+     examining things laid out late, like the strtab.  */
+  lang_write_ctf (0);
+
   /* Copy forward lma regions for output sections in same lma region.  */
   lang_propagate_lma_regions ();
 
@@ -8030,7 +8522,7 @@ lang_new_phdr (const char *name,
   struct lang_phdr *n, **pp;
   bfd_boolean hdrs;
 
-  n = (struct lang_phdr *) stat_alloc (sizeof (struct lang_phdr));
+  n = stat_alloc (sizeof (struct lang_phdr));
   n->next = NULL;
   n->name = name;
   n->type = exp_get_vma (type, 0, "program header type");
@@ -8077,7 +8569,7 @@ lang_record_phdrs (void)
       bfd_vma at;
 
       c = 0;
-      for (os = &lang_os_list.head->output_section_statement;
+      for (os = (void *) lang_os_list.head;
           os != NULL;
           os = os->next)
        {
@@ -8163,7 +8655,7 @@ lang_record_phdrs (void)
   free (secs);
 
   /* Make sure all the phdr assignments succeeded.  */
-  for (os = &lang_os_list.head->output_section_statement;
+  for (os = (void *) lang_os_list.head;
        os != NULL;
        os = os->next)
     {
@@ -8895,10 +9387,16 @@ lang_do_version_exports_section (void)
                           lang_new_vers_node (greg, lreg), NULL);
 }
 
-/* Evaluate LENGTH and ORIGIN parts of MEMORY spec */
+/* Evaluate LENGTH and ORIGIN parts of MEMORY spec.  This is initially
+   called with UPDATE_REGIONS_P set to FALSE, in this case no errors are
+   thrown, however, references to symbols in the origin and length fields
+   will be pushed into the symbol table, this allows PROVIDE statements to
+   then provide these symbols.  This function is called a second time with
+   UPDATE_REGIONS_P set to TRUE, this time the we update the actual region
+   data structures, and throw errors if missing symbols are encountered.  */
 
 static void
-lang_do_memory_regions (void)
+lang_do_memory_regions (bfd_boolean update_regions_p)
 {
   lang_memory_region_type *r = lang_memory_region_list;
 
@@ -8907,24 +9405,30 @@ lang_do_memory_regions (void)
       if (r->origin_exp)
        {
          exp_fold_tree_no_dot (r->origin_exp);
-         if (expld.result.valid_p)
-           {
-             r->origin = expld.result.value;
-             r->current = r->origin;
-           }
-         else
-           einfo (_("%F%P: invalid origin for memory region %s\n"),
-                  r->name_list.name);
+          if (update_regions_p)
+            {
+              if (expld.result.valid_p)
+                {
+                  r->origin = expld.result.value;
+                  r->current = r->origin;
+                }
+              else
+                einfo (_("%P: invalid origin for memory region %s\n"),
+                       r->name_list.name);
+            }
        }
       if (r->length_exp)
        {
          exp_fold_tree_no_dot (r->length_exp);
-         if (expld.result.valid_p)
-           r->length = expld.result.value;
-         else
-           einfo (_("%F%P: invalid length for memory region %s\n"),
-                  r->name_list.name);
-       }
+          if (update_regions_p)
+            {
+              if (expld.result.valid_p)
+                r->length = expld.result.value;
+              else
+                einfo (_("%P: invalid length for memory region %s\n"),
+                       r->name_list.name);
+            }
+        }
     }
 }
 
@@ -8946,15 +9450,16 @@ lang_add_unique (const char *name)
 /* Append the list of dynamic symbols to the existing one.  */
 
 void
-lang_append_dynamic_list (struct bfd_elf_version_expr *dynamic)
+lang_append_dynamic_list (struct bfd_elf_dynamic_list **list_p,
+                         struct bfd_elf_version_expr *dynamic)
 {
-  if (link_info.dynamic_list)
+  if (*list_p)
     {
       struct bfd_elf_version_expr *tail;
       for (tail = dynamic; tail->next != NULL; tail = tail->next)
        ;
-      tail->next = link_info.dynamic_list->head.list;
-      link_info.dynamic_list->head.list = dynamic;
+      tail->next = (*list_p)->head.list;
+      (*list_p)->head.list = dynamic;
     }
   else
     {
@@ -8963,7 +9468,7 @@ lang_append_dynamic_list (struct bfd_elf_version_expr *dynamic)
       d = (struct bfd_elf_dynamic_list *) xcalloc (1, sizeof *d);
       d->head.list = dynamic;
       d->match = lang_vers_match;
-      link_info.dynamic_list = d;
+      *list_p = d;
     }
 }
 
@@ -8985,7 +9490,7 @@ lang_append_dynamic_list_cpp_typeinfo (void)
     dynamic = lang_new_vers_pattern (dynamic, symbols [i], "C++",
                                     FALSE);
 
-  lang_append_dynamic_list (dynamic);
+  lang_append_dynamic_list (&link_info.dynamic_list, dynamic);
 }
 
 /* Append the list of C++ operator new and delete dynamic symbols to the
@@ -9006,7 +9511,7 @@ lang_append_dynamic_list_cpp_new (void)
     dynamic = lang_new_vers_pattern (dynamic, symbols [i], "C++",
                                     FALSE);
 
-  lang_append_dynamic_list (dynamic);
+  lang_append_dynamic_list (&link_info.dynamic_list, dynamic);
 }
 
 /* Scan a space and/or comma separated string of features.  */
@@ -9064,14 +9569,16 @@ lang_print_memory_usage (void)
   for (r = lang_memory_region_list; r->next != NULL; r = r->next)
     {
       bfd_vma used_length = r->current - r->origin;
-      double percent;
 
       printf ("%16s: ",r->name_list.name);
       lang_print_memory_size (used_length);
       lang_print_memory_size ((bfd_vma) r->length);
 
-      percent = used_length * 100.0 / r->length;
-
-      printf ("    %6.2f%%\n", percent);
+      if (r->length != 0)
+       {
+         double percent = used_length * 100.0 / r->length;
+         printf ("    %6.2f%%", percent);
+       }
+      printf ("\n");
     }
 }