Change the linker's heuristic for computing the entry point for binaries so that...
[binutils-gdb.git] / ld / ldlang.c
index 05ea0c881f825d12bd7cd0e3117fd8cf02c9f2a6..bc3f8b76d355e952a1036c3ff712e5f51863839e 100644 (file)
@@ -1,5 +1,5 @@
 /* Linker command language support.
 /* 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.
 
 
    This file is part of the GNU Binutils.
 
@@ -42,9 +42,9 @@
 #include "demangle.h"
 #include "hashtab.h"
 #include "elf-bfd.h"
 #include "demangle.h"
 #include "hashtab.h"
 #include "elf-bfd.h"
-#ifdef ENABLE_PLUGINS
+#if BFD_SUPPORTS_PLUGINS
 #include "plugin.h"
 #include "plugin.h"
-#endif /* ENABLE_PLUGINS */
+#endif /* BFD_SUPPORTS_PLUGINS */
 
 #ifndef offsetof
 #define offsetof(TYPE, MEMBER) ((size_t) & (((TYPE*) 0)->MEMBER))
 
 #ifndef offsetof
 #define offsetof(TYPE, MEMBER) ((size_t) & (((TYPE*) 0)->MEMBER))
@@ -63,19 +63,12 @@ static struct obstack map_obstack;
 #define obstack_chunk_alloc xmalloc
 #define obstack_chunk_free free
 static const char *entry_symbol_default = "start";
 #define obstack_chunk_alloc xmalloc
 #define obstack_chunk_free free
 static const char *entry_symbol_default = "start";
-static bfd_boolean map_head_is_link_order = FALSE;
+static bool map_head_is_link_order = false;
 static lang_output_section_statement_type *default_common_section;
 static lang_output_section_statement_type *default_common_section;
-static bfd_boolean map_option_f;
+static bool map_option_f;
 static bfd_vma print_dot;
 static lang_input_statement_type *first_file;
 static const char *current_target;
 static bfd_vma print_dot;
 static lang_input_statement_type *first_file;
 static const char *current_target;
-/* Header for list of statements corresponding to any files involved in the
-   link, either specified from the command-line or added implicitely (eg.
-   archive member used to resolved undefined symbol, wildcard statement from
-   linker script, etc.).  Next pointer is in next field of a
-   lang_statement_header_type (reached via header field in a
-   lang_statement_union).  */
-static lang_statement_list_type statement_list;
 static lang_statement_list_type *stat_save[10];
 static lang_statement_list_type **stat_save_ptr = &stat_save[0];
 static struct unique_sections *unique_section_list;
 static lang_statement_list_type *stat_save[10];
 static lang_statement_list_type **stat_save_ptr = &stat_save[0];
 static struct unique_sections *unique_section_list;
@@ -86,23 +79,30 @@ static unsigned int opb_shift = 0;
 static void exp_init_os (etree_type *);
 static lang_input_statement_type *lookup_name (const char *);
 static void insert_undefined (const char *);
 static void exp_init_os (etree_type *);
 static lang_input_statement_type *lookup_name (const char *);
 static void insert_undefined (const char *);
-static bfd_boolean sort_def_symbol (struct bfd_link_hash_entry *, void *);
+static bool sort_def_symbol (struct bfd_link_hash_entry *, void *);
 static void print_statement (lang_statement_union_type *,
                             lang_output_section_statement_type *);
 static void print_statement_list (lang_statement_union_type *,
                                  lang_output_section_statement_type *);
 static void print_statements (void);
 static void print_statement (lang_statement_union_type *,
                             lang_output_section_statement_type *);
 static void print_statement_list (lang_statement_union_type *,
                                  lang_output_section_statement_type *);
 static void print_statements (void);
-static void print_input_section (asection *, bfd_boolean);
-static bfd_boolean lang_one_common (struct bfd_link_hash_entry *, void *);
+static void print_input_section (asection *, bool);
+static bool lang_one_common (struct bfd_link_hash_entry *, void *);
 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_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 (bool);
 
 /* Exported variables.  */
 const char *output_target;
 lang_output_section_statement_type *abs_output_section;
 
 /* Exported variables.  */
 const char *output_target;
 lang_output_section_statement_type *abs_output_section;
+/* Header for list of statements corresponding to any files involved in the
+   link, either specified from the command-line or added implicitely (eg.
+   archive member used to resolved undefined symbol, wildcard statement from
+   linker script, etc.).  Next pointer is in next field of a
+   lang_statement_header_type (reached via header field in a
+   lang_statement_union).  */
+lang_statement_list_type statement_list;
 lang_statement_list_type lang_os_list;
 lang_statement_list_type *stat_ptr = &statement_list;
 /* Header for list of statements corresponding to files used in the final
 lang_statement_list_type lang_os_list;
 lang_statement_list_type *stat_ptr = &statement_list;
 /* Header for list of statements corresponding to files used in the final
@@ -117,24 +117,30 @@ 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;
    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;
 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;
-bfd_boolean delete_output_file_on_failure = FALSE;
+bool entry_from_cmdline;
+bool lang_has_input_file = false;
+bool had_output_filename = false;
+bool lang_float_flag = false;
+bool delete_output_file_on_failure = false;
 struct lang_phdr *lang_phdr_list;
 struct lang_nocrossrefs *nocrossref_list;
 struct asneeded_minfo **asneeded_list_tail;
 struct lang_phdr *lang_phdr_list;
 struct lang_nocrossrefs *nocrossref_list;
 struct asneeded_minfo **asneeded_list_tail;
-static ctf_file_t *ctf_output;
+#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;
 
 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
 /* 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
@@ -151,8 +157,6 @@ int lang_statement_iteration = 0;
 #define outside_symbol_address(q) \
   ((q)->value + outside_section_address (q->section))
 
 #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
 /* 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
@@ -173,6 +177,21 @@ name_match (const char *pattern, const char *name)
   return strcmp (pattern, 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.  */
 
 /* If PATTERN is of the form archive:file, return a pointer to the
    separator.  If not, return NULL.  */
 
@@ -200,22 +219,22 @@ archive_path (const char *pattern)
 /* Given that FILE_SPEC results in a non-NULL SEP result from archive_path,
    return whether F matches FILE_SPEC.  */
 
 /* Given that FILE_SPEC results in a non-NULL SEP result from archive_path,
    return whether F matches FILE_SPEC.  */
 
-static bfd_boolean
+static bool
 input_statement_is_archive_path (const char *file_spec, char *sep,
                                 lang_input_statement_type *f)
 {
 input_statement_is_archive_path (const char *file_spec, char *sep,
                                 lang_input_statement_type *f)
 {
-  bfd_boolean match = FALSE;
+  bool match = false;
 
   if ((*(sep + 1) == 0
        || name_match (sep + 1, f->filename) == 0)
       && ((sep != file_spec)
          == (f->the_bfd != NULL && f->the_bfd->my_archive != NULL)))
     {
 
   if ((*(sep + 1) == 0
        || name_match (sep + 1, f->filename) == 0)
       && ((sep != file_spec)
          == (f->the_bfd != NULL && f->the_bfd->my_archive != NULL)))
     {
-      match = TRUE;
+      match = true;
 
       if (sep != file_spec)
        {
 
       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;
          *sep = 0;
          match = name_match (file_spec, aname) == 0;
          *sep = link_info.path_separator;
@@ -224,7 +243,7 @@ input_statement_is_archive_path (const char *file_spec, char *sep,
   return match;
 }
 
   return match;
 }
 
-static bfd_boolean
+static bool
 unique_section_p (const asection *sec,
                  const lang_output_section_statement_type *os)
 {
 unique_section_p (const asection *sec,
                  const lang_output_section_statement_type *os)
 {
@@ -240,9 +259,9 @@ unique_section_p (const asection *sec,
   secnam = sec->name;
   for (unam = unique_section_list; unam; unam = unam->next)
     if (name_match (unam->name, secnam) == 0)
   secnam = sec->name;
   for (unam = unique_section_list; unam; unam = unam->next)
     if (name_match (unam->name, secnam) == 0)
-      return TRUE;
+      return true;
 
 
-  return FALSE;
+  return false;
 }
 
 /* Generic traversal routines for finding matching sections.  */
 }
 
 /* Generic traversal routines for finding matching sections.  */
@@ -250,7 +269,7 @@ unique_section_p (const asection *sec,
 /* Return true if FILE matches a pattern in EXCLUDE_LIST, otherwise return
    false.  */
 
 /* Return true if FILE matches a pattern in EXCLUDE_LIST, otherwise return
    false.  */
 
-static bfd_boolean
+static bool
 walk_wild_file_in_exclude_list (struct name_list *exclude_list,
                                lang_input_statement_type *file)
 {
 walk_wild_file_in_exclude_list (struct name_list *exclude_list,
                                lang_input_statement_type *file)
 {
@@ -265,11 +284,11 @@ walk_wild_file_in_exclude_list (struct name_list *exclude_list,
       if (p != NULL)
        {
          if (input_statement_is_archive_path (list_tmp->name, p, file))
       if (p != NULL)
        {
          if (input_statement_is_archive_path (list_tmp->name, p, file))
-           return TRUE;
+           return true;
        }
 
       else if (name_match (list_tmp->name, file->filename) == 0)
        }
 
       else if (name_match (list_tmp->name, file->filename) == 0)
-       return TRUE;
+       return true;
 
       /* FIXME: Perhaps remove the following at some stage?  Matching
         unadorned archives like this was never documented and has
 
       /* FIXME: Perhaps remove the following at some stage?  Matching
         unadorned archives like this was never documented and has
@@ -277,11 +296,11 @@ 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,
       else if (file->the_bfd != NULL
               && file->the_bfd->my_archive != NULL
               && name_match (list_tmp->name,
-                             file->the_bfd->my_archive->filename) == 0)
-       return TRUE;
+                             bfd_get_filename (file->the_bfd->my_archive)) == 0)
+       return true;
     }
 
     }
 
-  return FALSE;
+  return false;
 }
 
 /* Try processing a section against a wildcard.  This just calls
 }
 
 /* Try processing a section against a wildcard.  This just calls
@@ -301,7 +320,7 @@ walk_wild_consider_section (lang_wild_statement_type *ptr,
   if (walk_wild_file_in_exclude_list (sec->spec.exclude_name_list, file))
     return;
 
   if (walk_wild_file_in_exclude_list (sec->spec.exclude_name_list, file))
     return;
 
-  (*callback) (ptr, sec, s, ptr->section_flag_list, file, data);
+  (*callback) (ptr, sec, s, file, data);
 }
 
 /* Lowest common denominator routine that can handle everything correctly,
 }
 
 /* Lowest common denominator routine that can handle everything correctly,
@@ -320,11 +339,11 @@ walk_wild_section_general (lang_wild_statement_type *ptr,
     {
       sec = ptr->section_list;
       if (sec == NULL)
     {
       sec = ptr->section_list;
       if (sec == NULL)
-       (*callback) (ptr, sec, s, ptr->section_flag_list, file, data);
+       (*callback) (ptr, sec, s, file, data);
 
       while (sec != NULL)
        {
 
       while (sec != NULL)
        {
-         bfd_boolean skip = FALSE;
+         bool skip = false;
 
          if (sec->spec.name != NULL)
            {
 
          if (sec->spec.name != NULL)
            {
@@ -347,30 +366,30 @@ walk_wild_section_general (lang_wild_statement_type *ptr,
 typedef struct
 {
   asection *found_section;
 typedef struct
 {
   asection *found_section;
-  bfd_boolean multiple_sections_found;
+  bool multiple_sections_found;
 } section_iterator_callback_data;
 
 } section_iterator_callback_data;
 
-static bfd_boolean
+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)
     {
 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)
     {
-      d->multiple_sections_found = TRUE;
-      return TRUE;
+      d->multiple_sections_found = true;
+      return true;
     }
 
   d->found_section = s;
     }
 
   d->found_section = s;
-  return FALSE;
+  return false;
 }
 
 static asection *
 find_section (lang_input_statement_type *file,
              struct wildcard_list *sec,
 }
 
 static asection *
 find_section (lang_input_statement_type *file,
              struct wildcard_list *sec,
-             bfd_boolean *multiple_sections_found)
+             bool *multiple_sections_found)
 {
 {
-  section_iterator_callback_data cb_data = { NULL, FALSE };
+  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);
 
   bfd_get_section_by_name_if (file->the_bfd, sec->spec.name,
                              section_iterator_callback, &cb_data);
@@ -384,29 +403,29 @@ find_section (lang_input_statement_type *file,
 /* A simple wild is a literal string followed by a single '*',
    where the literal part is at least 4 characters long.  */
 
 /* A simple wild is a literal string followed by a single '*',
    where the literal part is at least 4 characters long.  */
 
-static bfd_boolean
+static bool
 is_simple_wild (const char *name)
 {
   size_t len = strcspn (name, "*?[");
   return len >= 4 && name[len] == '*' && name[len + 1] == '\0';
 }
 
 is_simple_wild (const char *name)
 {
   size_t len = strcspn (name, "*?[");
   return len >= 4 && name[len] == '*' && name[len + 1] == '\0';
 }
 
-static bfd_boolean
+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])
 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;
+    return false;
 
   pattern += 4;
   name += 4;
   while (*pattern != '*')
     if (*name++ != *pattern++)
 
   pattern += 4;
   name += 4;
   while (*pattern != '*')
     if (*name++ != *pattern++)
-      return FALSE;
+      return false;
 
 
-  return TRUE;
+  return true;
 }
 
 /* Return the numerical value of the init_priority attribute from
 }
 
 /* Return the numerical value of the init_priority attribute from
@@ -489,7 +508,7 @@ compare_section (sort_type sort, asection *asec, asection *bsec)
       /* Fall through.  */
 
     case by_name:
       /* Fall through.  */
 
     case by_name:
-sort_by_name:
+    sort_by_name:
       ret = strcmp (bfd_section_name (asec), bfd_section_name (bsec));
       break;
 
       ret = strcmp (bfd_section_name (asec), bfd_section_name (bsec));
       break;
 
@@ -547,7 +566,6 @@ static void
 output_section_callback_fast (lang_wild_statement_type *ptr,
                              struct wildcard_list *sec,
                              asection *section,
 output_section_callback_fast (lang_wild_statement_type *ptr,
                              struct wildcard_list *sec,
                              asection *section,
-                             struct flag_info *sflag_list ATTRIBUTE_UNUSED,
                              lang_input_statement_type *file,
                              void *output)
 {
                              lang_input_statement_type *file,
                              void *output)
 {
@@ -564,6 +582,7 @@ output_section_callback_fast (lang_wild_statement_type *ptr,
   node->left = 0;
   node->right = 0;
   node->section = section;
   node->left = 0;
   node->right = 0;
   node->section = section;
+  node->pattern = ptr->section_list;
 
   tree = wild_sort_fast (ptr, sec, file, section);
   if (tree != NULL)
 
   tree = wild_sort_fast (ptr, sec, file, section);
   if (tree != NULL)
@@ -580,7 +599,7 @@ output_section_callback_tree_to_list (lang_wild_statement_type *ptr,
   if (tree->left)
     output_section_callback_tree_to_list (ptr, tree->left, output);
 
   if (tree->left)
     output_section_callback_tree_to_list (ptr, tree->left, output);
 
-  lang_add_section (&ptr->children, tree->section, NULL,
+  lang_add_section (&ptr->children, tree->section, tree->pattern, NULL,
                    (lang_output_section_statement_type *) output);
 
   if (tree->right)
                    (lang_output_section_statement_type *) output);
 
   if (tree->right)
@@ -603,7 +622,7 @@ walk_wild_section_specs1_wild0 (lang_wild_statement_type *ptr,
      (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.  */
      (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.  */
-  bfd_boolean multiple_sections_found;
+  bool multiple_sections_found;
   struct wildcard_list *sec0 = ptr->handler_data[0];
   asection *s0 = find_section (file, sec0, &multiple_sections_found);
 
   struct wildcard_list *sec0 = ptr->handler_data[0];
   asection *s0 = find_section (file, sec0, &multiple_sections_found);
 
@@ -625,7 +644,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_section_name (s);
   for (s = file->the_bfd->sections; s != NULL; s = s->next)
     {
       const char *sname = bfd_section_name (s);
-      bfd_boolean skip = !match_simple_wild (wildsec0->spec.name, sname);
+      bool skip = !match_simple_wild (wildsec0->spec.name, sname);
 
       if (!skip)
        walk_wild_consider_section (ptr, file, s, wildsec0, callback, data);
 
       if (!skip)
        walk_wild_consider_section (ptr, file, s, wildsec0, callback, data);
@@ -641,7 +660,7 @@ walk_wild_section_specs2_wild1 (lang_wild_statement_type *ptr,
   asection *s;
   struct wildcard_list *sec0 = ptr->handler_data[0];
   struct wildcard_list *wildsec1 = ptr->handler_data[1];
   asection *s;
   struct wildcard_list *sec0 = ptr->handler_data[0];
   struct wildcard_list *wildsec1 = ptr->handler_data[1];
-  bfd_boolean multiple_sections_found;
+  bool multiple_sections_found;
   asection *s0 = find_section (file, sec0, &multiple_sections_found);
 
   if (multiple_sections_found)
   asection *s0 = find_section (file, sec0, &multiple_sections_found);
 
   if (multiple_sections_found)
@@ -662,7 +681,7 @@ walk_wild_section_specs2_wild1 (lang_wild_statement_type *ptr,
       else
        {
          const char *sname = bfd_section_name (s);
       else
        {
          const char *sname = bfd_section_name (s);
-         bfd_boolean skip = !match_simple_wild (wildsec1->spec.name, sname);
+         bool skip = !match_simple_wild (wildsec1->spec.name, sname);
 
          if (!skip)
            walk_wild_consider_section (ptr, file, s, wildsec1, callback,
 
          if (!skip)
            walk_wild_consider_section (ptr, file, s, wildsec1, callback,
@@ -681,7 +700,7 @@ walk_wild_section_specs3_wild2 (lang_wild_statement_type *ptr,
   struct wildcard_list *sec0 = ptr->handler_data[0];
   struct wildcard_list *wildsec1 = ptr->handler_data[1];
   struct wildcard_list *wildsec2 = ptr->handler_data[2];
   struct wildcard_list *sec0 = ptr->handler_data[0];
   struct wildcard_list *wildsec1 = ptr->handler_data[1];
   struct wildcard_list *wildsec2 = ptr->handler_data[2];
-  bfd_boolean multiple_sections_found;
+  bool multiple_sections_found;
   asection *s0 = find_section (file, sec0, &multiple_sections_found);
 
   if (multiple_sections_found)
   asection *s0 = find_section (file, sec0, &multiple_sections_found);
 
   if (multiple_sections_found)
@@ -697,7 +716,7 @@ walk_wild_section_specs3_wild2 (lang_wild_statement_type *ptr,
       else
        {
          const char *sname = bfd_section_name (s);
       else
        {
          const char *sname = bfd_section_name (s);
-         bfd_boolean skip = !match_simple_wild (wildsec1->spec.name, sname);
+         bool skip = !match_simple_wild (wildsec1->spec.name, sname);
 
          if (!skip)
            walk_wild_consider_section (ptr, file, s, wildsec1, callback, data);
 
          if (!skip)
            walk_wild_consider_section (ptr, file, s, wildsec1, callback, data);
@@ -723,7 +742,7 @@ walk_wild_section_specs4_wild2 (lang_wild_statement_type *ptr,
   struct wildcard_list *sec1 = ptr->handler_data[1];
   struct wildcard_list *wildsec2 = ptr->handler_data[2];
   struct wildcard_list *wildsec3 = ptr->handler_data[3];
   struct wildcard_list *sec1 = ptr->handler_data[1];
   struct wildcard_list *wildsec2 = ptr->handler_data[2];
   struct wildcard_list *wildsec3 = ptr->handler_data[3];
-  bfd_boolean multiple_sections_found;
+  bool multiple_sections_found;
   asection *s0 = find_section (file, sec0, &multiple_sections_found), *s1;
 
   if (multiple_sections_found)
   asection *s0 = find_section (file, sec0, &multiple_sections_found), *s1;
 
   if (multiple_sections_found)
@@ -749,8 +768,7 @@ walk_wild_section_specs4_wild2 (lang_wild_statement_type *ptr,
        else
          {
            const char *sname = bfd_section_name (s);
        else
          {
            const char *sname = bfd_section_name (s);
-           bfd_boolean skip = !match_simple_wild (wildsec2->spec.name,
-                                                  sname);
+           bool skip = !match_simple_wild (wildsec2->spec.name, sname);
 
            if (!skip)
              walk_wild_consider_section (ptr, file, s, wildsec2, callback,
 
            if (!skip)
              walk_wild_consider_section (ptr, file, s, wildsec2, callback,
@@ -783,7 +801,7 @@ walk_wild_section (lang_wild_statement_type *ptr,
    only if the prefixes of name1 and name2 are different up to the
    first wildcard character.  */
 
    only if the prefixes of name1 and name2 are different up to the
    first wildcard character.  */
 
-static bfd_boolean
+static bool
 wild_spec_can_overlap (const char *name1, const char *name2)
 {
   size_t prefix1_len = strcspn (name1, "?*[");
 wild_spec_can_overlap (const char *name1, const char *name2)
 {
   size_t prefix1_len = strcspn (name1, "?*[");
@@ -1090,15 +1108,17 @@ new_statement (enum statement_enum type,
 static lang_input_statement_type *
 new_afile (const char *name,
           lang_input_file_enum_type file_type,
 static lang_input_statement_type *
 new_afile (const char *name,
           lang_input_file_enum_type file_type,
-          const char *target)
+          const char *target,
+          const char *from_filename)
 {
   lang_input_statement_type *p;
 
 {
   lang_input_statement_type *p;
 
-  lang_has_input_file = TRUE;
+  lang_has_input_file = true;
 
   p = new_stat (lang_input_statement, stat_ptr);
   memset (&p->the_bfd, 0,
          sizeof (*p) - offsetof (lang_input_statement_type, the_bfd));
 
   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;
   p->target = target;
   p->flags.dynamic = input_flags.dynamic;
   p->flags.add_DT_NEEDED_for_dynamic = input_flags.add_DT_NEEDED_for_dynamic;
@@ -1111,8 +1131,8 @@ new_afile (const char *name,
     case lang_input_file_is_symbols_only_enum:
       p->filename = name;
       p->local_sym_name = name;
     case lang_input_file_is_symbols_only_enum:
       p->filename = name;
       p->local_sym_name = name;
-      p->flags.real = TRUE;
-      p->flags.just_syms = TRUE;
+      p->flags.real = true;
+      p->flags.just_syms = true;
       break;
     case lang_input_file_is_fake_enum:
       p->filename = name;
       break;
     case lang_input_file_is_fake_enum:
       p->filename = name;
@@ -1122,30 +1142,34 @@ new_afile (const char *name,
       if (name[0] == ':' && name[1] != '\0')
        {
          p->filename = name + 1;
       if (name[0] == ':' && name[1] != '\0')
        {
          p->filename = name + 1;
-         p->flags.full_name_provided = TRUE;
+         p->flags.full_name_provided = true;
        }
       else
        p->filename = name;
       p->local_sym_name = concat ("-l", name, (const char *) NULL);
        }
       else
        p->filename = name;
       p->local_sym_name = concat ("-l", name, (const char *) NULL);
-      p->flags.maybe_archive = TRUE;
-      p->flags.real = TRUE;
-      p->flags.search_dirs = TRUE;
+      p->flags.maybe_archive = true;
+      p->flags.real = true;
+      p->flags.search_dirs = true;
       break;
     case lang_input_file_is_marker_enum:
       p->filename = name;
       p->local_sym_name = name;
       break;
     case lang_input_file_is_marker_enum:
       p->filename = name;
       p->local_sym_name = name;
-      p->flags.search_dirs = TRUE;
+      p->flags.search_dirs = true;
       break;
     case lang_input_file_is_search_file_enum:
       p->filename = name;
       p->local_sym_name = name;
       break;
     case lang_input_file_is_search_file_enum:
       p->filename = name;
       p->local_sym_name = name;
-      p->flags.real = TRUE;
-      p->flags.search_dirs = TRUE;
+      /* 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;
     case lang_input_file_is_file_enum:
       p->filename = name;
       p->local_sym_name = name;
       break;
     case lang_input_file_is_file_enum:
       p->filename = name;
       p->local_sym_name = name;
-      p->flags.real = TRUE;
+      p->flags.real = true;
       break;
     default:
       FAIL ();
       break;
     default:
       FAIL ();
@@ -1161,7 +1185,7 @@ lang_add_input_file (const char *name,
                     const char *target)
 {
   if (name != NULL
                     const char *target)
 {
   if (name != NULL
-      && (*name == '=' || CONST_STRNEQ (name, "$SYSROOT")))
+      && (*name == '=' || startswith (name, "$SYSROOT")))
     {
       lang_input_statement_type *ret;
       char *sysrooted_name
     {
       lang_input_statement_type *ret;
       char *sysrooted_name
@@ -1178,12 +1202,12 @@ lang_add_input_file (const char *name,
         within the sysroot subdirectory.)  */
       unsigned int outer_sysrooted = input_flags.sysrooted;
       input_flags.sysrooted = 0;
         within the sysroot subdirectory.)  */
       unsigned int outer_sysrooted = input_flags.sysrooted;
       input_flags.sysrooted = 0;
-      ret = new_afile (sysrooted_name, file_type, target);
+      ret = new_afile (sysrooted_name, file_type, target, NULL);
       input_flags.sysrooted = outer_sysrooted;
       return ret;
     }
 
       input_flags.sysrooted = outer_sysrooted;
       return ret;
     }
 
-  return new_afile (name, file_type, target);
+  return new_afile (name, file_type, target, current_input_file);
 }
 
 struct out_section_hash_entry
 }
 
 struct out_section_hash_entry
@@ -1280,7 +1304,7 @@ lang_init (void)
   first_file = lang_add_input_file (NULL, lang_input_file_is_marker_enum,
                                    NULL);
   abs_output_section =
   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;
 
 
   abs_output_section->bfd_section = bfd_abs_section_ptr;
 
@@ -1321,7 +1345,7 @@ static lang_memory_region_type **lang_memory_region_list_tail
   = &lang_memory_region_list;
 
 lang_memory_region_type *
   = &lang_memory_region_list;
 
 lang_memory_region_type *
-lang_memory_region_lookup (const char *const name, bfd_boolean create)
+lang_memory_region_lookup (const char *const name, bool create)
 {
   lang_memory_region_name *n;
   lang_memory_region_type *r;
 {
   lang_memory_region_name *n;
   lang_memory_region_type *r;
@@ -1358,7 +1382,7 @@ lang_memory_region_lookup (const char *const name, bfd_boolean create)
   new_region->last_os = NULL;
   new_region->flags = 0;
   new_region->not_flags = 0;
   new_region->last_os = NULL;
   new_region->flags = 0;
   new_region->not_flags = 0;
-  new_region->had_full_message = FALSE;
+  new_region->had_full_message = false;
 
   *lang_memory_region_list_tail = new_region;
   lang_memory_region_list_tail = &new_region->next;
 
   *lang_memory_region_list_tail = new_region;
   lang_memory_region_list_tail = &new_region->next;
@@ -1426,7 +1450,7 @@ lang_memory_default (asection *section)
          return p;
        }
     }
          return p;
        }
     }
-  return lang_memory_region_lookup (DEFAULT_MEMORY_REGION, FALSE);
+  return lang_memory_region_lookup (DEFAULT_MEMORY_REGION, false);
 }
 
 /* Get the output section statement directly from the userdata.  */
 }
 
 /* Get the output section statement directly from the userdata.  */
@@ -1439,19 +1463,21 @@ lang_output_section_get (const asection *output_section)
 
 /* Find or create an output_section_statement with the given NAME.
    If CONSTRAINT is non-zero match one with that constraint, otherwise
 
 /* 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,
 
 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,
 {
   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)
   if (entry == NULL)
     {
       if (create)
@@ -1466,23 +1492,19 @@ lang_output_section_statement_lookup (const char *name,
       struct out_section_hash_entry *last_ent;
 
       name = entry->s.output_section_statement.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;
 
       if (!create)
        return NULL;
@@ -1503,6 +1525,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.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;
 }
 
   return &entry->s.output_section_statement;
 }
 
@@ -1552,7 +1576,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.  */
 
   /* 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.  */
   first = first->next;
 
   /* First try for an exact match.  */
@@ -1630,7 +1654,7 @@ lang_output_section_find_by_flags (const asection *sec,
     {
       /* .tdata can go after .data, .tbss after .tdata.  Treat .tbss
         as if it were a loaded section, and don't use match_type.  */
     {
       /* .tdata can go after .data, .tbss after .tdata.  Treat .tbss
         as if it were a loaded section, and don't use match_type.  */
-      bfd_boolean seen_thread_local = FALSE;
+      bool seen_thread_local = false;
 
       match_type = NULL;
       for (look = first; look; look = look->next)
 
       match_type = NULL;
       for (look = first; look; look = look->next)
@@ -1650,7 +1674,7 @@ lang_output_section_find_by_flags (const asection *sec,
                   previous section.  */
                break;
              found = look;
                   previous section.  */
                break;
              found = look;
-             seen_thread_local = TRUE;
+             seen_thread_local = true;
            }
          else if (seen_thread_local)
            break;
            }
          else if (seen_thread_local)
            break;
@@ -1778,9 +1802,9 @@ insert_os_after (lang_output_section_statement_type *after)
 {
   lang_statement_union_type **where;
   lang_statement_union_type **assign = NULL;
 {
   lang_statement_union_type **where;
   lang_statement_union_type **assign = NULL;
-  bfd_boolean ignore_first;
+  bool 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;
 
   for (where = &after->header.next;
        *where != NULL;
@@ -1800,7 +1824,7 @@ insert_os_after (lang_output_section_statement_type *after)
                {
                  if (!ignore_first)
                    assign = where;
                {
                  if (!ignore_first)
                    assign = where;
-                 ignore_first = FALSE;
+                 ignore_first = false;
                }
            }
          continue;
                }
            }
          continue;
@@ -1813,7 +1837,7 @@ insert_os_after (lang_output_section_statement_type *after)
        case lang_padding_statement_enum:
        case lang_constructors_statement_enum:
          assign = NULL;
        case lang_padding_statement_enum:
        case lang_constructors_statement_enum:
          assign = NULL;
-         ignore_first = FALSE;
+         ignore_first = false;
          continue;
        case lang_output_section_statement_enum:
          if (assign != NULL)
          continue;
        case lang_output_section_statement_enum:
          if (assign != NULL)
@@ -1872,7 +1896,7 @@ lang_insert_orphan (asection *s,
 
   if (add_child == NULL)
     add_child = &os->children;
 
   if (add_child == NULL)
     add_child = &os->children;
-  lang_add_section (add_child, s, NULL, os);
+  lang_add_section (add_child, s, NULL, NULL, os);
 
   if (after && (s->flags & (SEC_LOAD | SEC_ALLOC)) != 0)
     {
 
   if (after && (s->flags & (SEC_LOAD | SEC_ALLOC)) != 0)
     {
@@ -1896,15 +1920,15 @@ lang_insert_orphan (asection *s,
   if (after != NULL && os->bfd_section != NULL)
     {
       asection *snew, *as;
   if (after != NULL && os->bfd_section != NULL)
     {
       asection *snew, *as;
-      bfd_boolean place_after = place->stmt == NULL;
-      bfd_boolean insert_after = TRUE;
+      bool place_after = place->stmt == NULL;
+      bool insert_after = true;
 
       snew = os->bfd_section;
 
       /* Shuffle the bfd section list to make the output file look
         neater.  This is really only cosmetic.  */
       if (place->section == NULL
 
       snew = os->bfd_section;
 
       /* 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;
 
        {
          asection *bfd_section = after->bfd_section;
 
@@ -1952,7 +1976,7 @@ lang_insert_orphan (asection *s,
          asection *after_sec;
          /* True if we need to insert the orphan section after a
             specific section to maintain output note section order.  */
          asection *after_sec;
          /* True if we need to insert the orphan section after a
             specific section to maintain output note section order.  */
-         bfd_boolean after_sec_note = FALSE;
+         bool after_sec_note = false;
 
          static asection *first_orphan_note = NULL;
 
 
          static asection *first_orphan_note = NULL;
 
@@ -1996,14 +2020,14 @@ lang_insert_orphan (asection *s,
                     alignments, place the section before all
                     output orphan note sections.  */
                  after_sec = first_orphan_note;
                     alignments, place the section before all
                     output orphan note sections.  */
                  after_sec = first_orphan_note;
-                 insert_after = FALSE;
+                 insert_after = false;
                }
            }
          else if (first_orphan_note)
            {
              /* Don't place non-note sections in the middle of orphan
                 note sections.  */
                }
            }
          else if (first_orphan_note)
            {
              /* Don't place non-note sections in the middle of orphan
                 note sections.  */
-             after_sec_note = TRUE;
+             after_sec_note = true;
              after_sec = as;
              for (sec = as->next;
                   (sec != NULL
              after_sec = as;
              for (sec = as->next;
                   (sec != NULL
@@ -2021,7 +2045,7 @@ lang_insert_orphan (asection *s,
                  /* Search forward to insert OS after AFTER_SEC output
                     statement.  */
                  lang_output_section_statement_type *stmt, *next;
                  /* Search forward to insert OS after AFTER_SEC output
                     statement.  */
                  lang_output_section_statement_type *stmt, *next;
-                 bfd_boolean found = FALSE;
+                 bool found = false;
                  for (stmt = after; stmt != NULL; stmt = next)
                    {
                      next = stmt->next;
                  for (stmt = after; stmt != NULL; stmt = next)
                    {
                      next = stmt->next;
@@ -2029,8 +2053,8 @@ lang_insert_orphan (asection *s,
                        {
                          if (stmt->bfd_section == after_sec)
                            {
                        {
                          if (stmt->bfd_section == after_sec)
                            {
-                             place_after = TRUE;
-                             found = TRUE;
+                             place_after = true;
+                             found = true;
                              after = stmt;
                              break;
                            }
                              after = stmt;
                              break;
                            }
@@ -2041,8 +2065,8 @@ lang_insert_orphan (asection *s,
                             AFTER_SEC output statement.  */
                          if (next && next->bfd_section == after_sec)
                            {
                             AFTER_SEC output statement.  */
                          if (next && next->bfd_section == after_sec)
                            {
-                             place_after = TRUE;
-                             found = TRUE;
+                             place_after = true;
+                             found = true;
                              after = stmt;
                              break;
                            }
                              after = stmt;
                              break;
                            }
@@ -2058,7 +2082,7 @@ lang_insert_orphan (asection *s,
                          {
                            if (stmt->bfd_section == after_sec)
                              {
                          {
                            if (stmt->bfd_section == after_sec)
                              {
-                               place_after = TRUE;
+                               place_after = true;
                                after = stmt;
                                break;
                              }
                                after = stmt;
                                break;
                              }
@@ -2069,7 +2093,7 @@ lang_insert_orphan (asection *s,
                               AFTER_SEC output statement.  */
                            if (stmt->next->bfd_section == after_sec)
                              {
                               AFTER_SEC output statement.  */
                            if (stmt->next->bfd_section == after_sec)
                              {
-                               place_after = TRUE;
+                               place_after = true;
                                after = stmt;
                                break;
                              }
                                after = stmt;
                                break;
                              }
@@ -2241,7 +2265,7 @@ void
 lang_map (void)
 {
   lang_memory_region_type *m;
 lang_map (void)
 {
   lang_memory_region_type *m;
-  bfd_boolean dis_header_printed = FALSE;
+  bool dis_header_printed = false;
 
   LANG_FOR_EACH_INPUT_STATEMENT (file)
     {
 
   LANG_FOR_EACH_INPUT_STATEMENT (file)
     {
@@ -2260,10 +2284,10 @@ lang_map (void)
              if (! dis_header_printed)
                {
                  fprintf (config.map_file, _("\nDiscarded input sections\n\n"));
              if (! dis_header_printed)
                {
                  fprintf (config.map_file, _("\nDiscarded input sections\n\n"));
-                 dis_header_printed = TRUE;
+                 dis_header_printed = true;
                }
 
                }
 
-             print_input_section (s, TRUE);
+             print_input_section (s, true);
            }
     }
 
            }
     }
 
@@ -2324,7 +2348,7 @@ lang_map (void)
                              config.map_file);
 }
 
                              config.map_file);
 }
 
-static bfd_boolean
+static bool
 sort_def_symbol (struct bfd_link_hash_entry *hash_entry,
                 void *info ATTRIBUTE_UNUSED)
 {
 sort_def_symbol (struct bfd_link_hash_entry *hash_entry,
                 void *info ATTRIBUTE_UNUSED)
 {
@@ -2353,7 +2377,7 @@ sort_def_symbol (struct bfd_link_hash_entry *hash_entry,
       ud->map_symbol_def_tail = &def->next;
       ud->map_symbol_def_count++;
     }
       ud->map_symbol_def_tail = &def->next;
       ud->map_symbol_def_count++;
     }
-  return TRUE;
+  return true;
 }
 
 /* Initialize an output section.  */
 }
 
 /* Initialize an output section.  */
@@ -2364,7 +2388,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 (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,
     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,
@@ -2477,10 +2501,10 @@ section_already_linked (bfd *abfd, asection *sec, void *data)
 /* Returns true if SECTION is one we know will be discarded based on its
    section flags, otherwise returns false.  */
 
 /* Returns true if SECTION is one we know will be discarded based on its
    section flags, otherwise returns false.  */
 
-static bfd_boolean
+static bool
 lang_discard_section_p (asection *section)
 {
 lang_discard_section_p (asection *section)
 {
-  bfd_boolean discard;
+  bool discard;
   flagword flags = section->flags;
 
   /* Discard sections marked with SEC_EXCLUDE.  */
   flagword flags = section->flags;
 
   /* Discard sections marked with SEC_EXCLUDE.  */
@@ -2490,13 +2514,13 @@ lang_discard_section_p (asection *section)
      sections from within the group.  */
   if ((flags & SEC_GROUP) != 0
       && link_info.resolve_section_groups)
      sections from within the group.  */
   if ((flags & SEC_GROUP) != 0
       && link_info.resolve_section_groups)
-    discard = TRUE;
+    discard = true;
 
   /* Discard debugging sections if we are stripping debugging
      information.  */
   if ((link_info.strip == strip_debugger || link_info.strip == strip_all)
       && (flags & SEC_DEBUGGING) != 0)
 
   /* Discard debugging sections if we are stripping debugging
      information.  */
   if ((link_info.strip == strip_debugger || link_info.strip == strip_all)
       && (flags & SEC_DEBUGGING) != 0)
-    discard = TRUE;
+    discard = true;
 
   return discard;
 }
 
   return discard;
 }
@@ -2513,12 +2537,13 @@ lang_discard_section_p (asection *section)
 void
 lang_add_section (lang_statement_list_type *ptr,
                  asection *section,
 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;
 
                  struct flag_info *sflag_info,
                  lang_output_section_statement_type *output)
 {
   flagword flags = section->flags;
 
-  bfd_boolean discard;
+  bool discard;
   lang_input_section_type *new_section;
   bfd *abfd = link_info.output_bfd;
 
   lang_input_section_type *new_section;
   bfd *abfd = link_info.output_bfd;
 
@@ -2528,7 +2553,7 @@ lang_add_section (lang_statement_list_type *ptr,
   /* Discard input sections which are assigned to a section named
      DISCARD_SECTION_NAME.  */
   if (strcmp (output->name, DISCARD_SECTION_NAME) == 0)
   /* Discard input sections which are assigned to a section named
      DISCARD_SECTION_NAME.  */
   if (strcmp (output->name, DISCARD_SECTION_NAME) == 0)
-    discard = TRUE;
+    discard = true;
 
   if (discard)
     {
 
   if (discard)
     {
@@ -2537,12 +2562,17 @@ lang_add_section (lang_statement_list_type *ptr,
          /* This prevents future calls from assigning this section.  */
          section->output_section = bfd_abs_section_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;
     }
 
   if (sflag_info)
     {
       return;
     }
 
   if (sflag_info)
     {
-      bfd_boolean keep;
+      bool keep;
 
       keep = bfd_lookup_section_flags (&link_info, sflag_info, section);
       if (!keep)
 
       keep = bfd_lookup_section_flags (&link_info, sflag_info, section);
       if (!keep)
@@ -2550,7 +2580,33 @@ lang_add_section (lang_statement_list_type *ptr,
     }
 
   if (section->output_section != NULL)
     }
 
   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
 
   /* 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
@@ -2583,6 +2639,9 @@ lang_add_section (lang_statement_list_type *ptr,
     case noalloc_section:
       flags &= ~SEC_ALLOC;
       break;
     case noalloc_section:
       flags &= ~SEC_ALLOC;
       break;
+    case readonly_section:
+      flags |= SEC_READONLY;
+      break;
     case noload_section:
       flags &= ~SEC_LOAD;
       flags |= SEC_NEVER_LOAD;
     case noload_section:
       flags &= ~SEC_LOAD;
       flags |= SEC_NEVER_LOAD;
@@ -2662,6 +2721,7 @@ lang_add_section (lang_statement_list_type *ptr,
   /* Add a section reference to the list.  */
   new_section = new_stat (lang_input_section, ptr);
   new_section->section = 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
 }
 
 /* Handle wildcard sorting.  This returns the lang_input_section which
@@ -2695,7 +2755,7 @@ wild_sort (lang_wild_statement_type *wild,
       if (wild->filenames_sorted)
        {
          const char *fn, *ln;
       if (wild->filenames_sorted)
        {
          const char *fn, *ln;
-         bfd_boolean fa, la;
+         bool fa, la;
          int i;
 
          /* The PE support for the .idata section as generated by
          int i;
 
          /* The PE support for the .idata section as generated by
@@ -2707,23 +2767,23 @@ wild_sort (lang_wild_statement_type *wild,
              && file->the_bfd->my_archive != NULL)
            {
              fn = bfd_get_filename (file->the_bfd->my_archive);
              && file->the_bfd->my_archive != NULL)
            {
              fn = bfd_get_filename (file->the_bfd->my_archive);
-             fa = TRUE;
+             fa = true;
            }
          else
            {
              fn = file->filename;
            }
          else
            {
              fn = file->filename;
-             fa = FALSE;
+             fa = false;
            }
 
          if (ls->section->owner->my_archive != NULL)
            {
              ln = bfd_get_filename (ls->section->owner->my_archive);
            }
 
          if (ls->section->owner->my_archive != NULL)
            {
              ln = bfd_get_filename (ls->section->owner->my_archive);
-             la = TRUE;
+             la = true;
            }
          else
            {
            }
          else
            {
-             ln = ls->section->owner->filename;
-             la = FALSE;
+             ln = bfd_get_filename (ls->section->owner);
+             la = false;
            }
 
          i = filename_cmp (fn, ln);
            }
 
          i = filename_cmp (fn, ln);
@@ -2737,7 +2797,7 @@ wild_sort (lang_wild_statement_type *wild,
              if (fa)
                fn = file->filename;
              if (la)
              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)
 
              i = filename_cmp (fn, ln);
              if (i > 0)
@@ -2767,7 +2827,6 @@ static void
 output_section_callback (lang_wild_statement_type *ptr,
                         struct wildcard_list *sec,
                         asection *section,
 output_section_callback (lang_wild_statement_type *ptr,
                         struct wildcard_list *sec,
                         asection *section,
-                        struct flag_info *sflag_info,
                         lang_input_statement_type *file,
                         void *output)
 {
                         lang_input_statement_type *file,
                         void *output)
 {
@@ -2788,14 +2847,16 @@ output_section_callback (lang_wild_statement_type *ptr,
      of the current list.  */
 
   if (before == NULL)
      of the current list.  */
 
   if (before == NULL)
-    lang_add_section (&ptr->children, section, sflag_info, os);
+    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);
   else
     {
       lang_statement_list_type list;
       lang_statement_union_type **pp;
 
       lang_list_init (&list);
-      lang_add_section (&list, section, sflag_info, os);
+      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 we are discarding the section, LIST.HEAD will
         be NULL.  */
@@ -2821,7 +2882,6 @@ static void
 check_section_callback (lang_wild_statement_type *ptr ATTRIBUTE_UNUSED,
                        struct wildcard_list *sec ATTRIBUTE_UNUSED,
                        asection *section,
 check_section_callback (lang_wild_statement_type *ptr ATTRIBUTE_UNUSED,
                        struct wildcard_list *sec ATTRIBUTE_UNUSED,
                        asection *section,
-                       struct flag_info *sflag_info ATTRIBUTE_UNUSED,
                        lang_input_statement_type *file ATTRIBUTE_UNUSED,
                        void *output)
 {
                        lang_input_statement_type *file ATTRIBUTE_UNUSED,
                        void *output)
 {
@@ -2834,7 +2894,7 @@ check_section_callback (lang_wild_statement_type *ptr ATTRIBUTE_UNUSED,
     return;
 
   if (section->output_section == NULL && (section->flags & SEC_READONLY) == 0)
     return;
 
   if (section->output_section == NULL && (section->flags & SEC_READONLY) == 0)
-    os->all_input_readonly = FALSE;
+    os->all_input_readonly = false;
 }
 
 /* This is passed a file name which must have been seen already and
 }
 
 /* This is passed a file name which must have been seen already and
@@ -2846,7 +2906,7 @@ lookup_name (const char *name)
 {
   lang_input_statement_type *search;
 
 {
   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)
     {
        search != NULL;
        search = search->next_real_file)
     {
@@ -2875,7 +2935,7 @@ lookup_name (const char *name)
       lang_statement_union_type *rest = *after;
       stat_ptr->tail = after;
       search = new_afile (name, lang_input_file_is_search_file_enum,
       lang_statement_union_type *rest = *after;
       stat_ptr->tail = after;
       search = new_afile (name, lang_input_file_is_search_file_enum,
-                         default_target);
+                         default_target, NULL);
       *stat_ptr->tail = rest;
       if (*tail == NULL)
        stat_ptr->tail = tail;
       *stat_ptr->tail = rest;
       if (*tail == NULL)
        stat_ptr->tail = tail;
@@ -2932,11 +2992,11 @@ check_excluded_libs (bfd *abfd)
   while (lib)
     {
       int len = strlen (lib->name);
   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)
        {
 
       if (strcmp (lib->name, "ALL") == 0)
        {
-         abfd->no_export = TRUE;
+         abfd->no_export = true;
          return;
        }
 
          return;
        }
 
@@ -2945,7 +3005,7 @@ check_excluded_libs (bfd *abfd)
              || (filename[len] == '.' && filename[len + 1] == 'a'
                  && filename[len + 2] == '\0')))
        {
              || (filename[len] == '.' && filename[len + 1] == 'a'
                  && filename[len + 2] == '\0')))
        {
-         abfd->no_export = TRUE;
+         abfd->no_export = true;
          return;
        }
 
          return;
        }
 
@@ -2955,20 +3015,20 @@ check_excluded_libs (bfd *abfd)
 
 /* Get the symbols for an input file.  */
 
 
 /* Get the symbols for an input file.  */
 
-bfd_boolean
+bool
 load_symbols (lang_input_statement_type *entry,
              lang_statement_list_type *place)
 {
   char **matching;
 
   if (entry->flags.loaded)
 load_symbols (lang_input_statement_type *entry,
              lang_statement_list_type *place)
 {
   char **matching;
 
   if (entry->flags.loaded)
-    return TRUE;
+    return true;
 
   ldfile_open_file (entry);
 
   /* Do not process further if the file was missing.  */
   if (entry->flags.missing_file)
 
   ldfile_open_file (entry);
 
   /* Do not process further if the file was missing.  */
   if (entry->flags.missing_file)
-    return TRUE;
+    return true;
 
   if (trace_files || verbose)
     info_msg ("%pI\n", entry);
 
   if (trace_files || verbose)
     info_msg ("%pI\n", entry);
@@ -2984,7 +3044,7 @@ load_symbols (lang_input_statement_type *entry,
 
       /* See if the emulation has some special knowledge.  */
       if (ldemul_unrecognized_file (entry))
 
       /* See if the emulation has some special knowledge.  */
       if (ldemul_unrecognized_file (entry))
-       return TRUE;
+       return true;
 
       if (err == bfd_error_file_ambiguously_recognized)
        {
 
       if (err == bfd_error_file_ambiguously_recognized)
        {
@@ -3015,10 +3075,12 @@ load_symbols (lang_input_statement_type *entry,
       input_flags.whole_archive = entry->flags.whole_archive;
       input_flags.dynamic = entry->flags.dynamic;
 
       input_flags.whole_archive = entry->flags.whole_archive;
       input_flags.dynamic = entry->flags.dynamic;
 
-      ldfile_assumed_script = TRUE;
+      ldfile_assumed_script = true;
       parser_input = input_script;
       parser_input = input_script;
+      current_input_file = entry->filename;
       yyparse ();
       yyparse ();
-      ldfile_assumed_script = FALSE;
+      current_input_file = NULL;
+      ldfile_assumed_script = false;
 
       /* missing_file is sticky.  sysrooted will already have been
         restored when seeing EOF in yyparse, but no harm to restore
 
       /* missing_file is sticky.  sysrooted will already have been
         restored when seeing EOF in yyparse, but no harm to restore
@@ -3028,13 +3090,13 @@ load_symbols (lang_input_statement_type *entry,
       pop_stat_ptr ();
       fclose (yyin);
       yyin = NULL;
       pop_stat_ptr ();
       fclose (yyin);
       yyin = NULL;
-      entry->flags.loaded = TRUE;
+      entry->flags.loaded = true;
 
 
-      return TRUE;
+      return true;
     }
 
   if (ldemul_recognized_file (entry))
     }
 
   if (ldemul_recognized_file (entry))
-    return TRUE;
+    return true;
 
   /* We don't call ldlang_add_file for an archive.  Instead, the
      add_symbols entry point will call ldlang_add_file, via the
 
   /* We don't call ldlang_add_file for an archive.  Instead, the
      add_symbols entry point will call ldlang_add_file, via the
@@ -3057,7 +3119,7 @@ load_symbols (lang_input_statement_type *entry,
       if (entry->flags.whole_archive)
        {
          bfd *member = NULL;
       if (entry->flags.whole_archive)
        {
          bfd *member = NULL;
-         bfd_boolean loaded = TRUE;
+         bool loaded = true;
 
          for (;;)
            {
 
          for (;;)
            {
@@ -3071,7 +3133,7 @@ load_symbols (lang_input_statement_type *entry,
                {
                  einfo (_("%F%P: %pB: member %pB in archive is not an object\n"),
                         entry->the_bfd, member);
                {
                  einfo (_("%F%P: %pB: member %pB in archive is not an object\n"),
                         entry->the_bfd, member);
-                 loaded = FALSE;
+                 loaded = false;
                }
 
              subsbfd = member;
                }
 
              subsbfd = member;
@@ -3085,7 +3147,7 @@ load_symbols (lang_input_statement_type *entry,
              if (!bfd_link_add_symbols (subsbfd, &link_info))
                {
                  einfo (_("%F%P: %pB: error adding symbols: %E\n"), member);
              if (!bfd_link_add_symbols (subsbfd, &link_info))
                {
                  einfo (_("%F%P: %pB: error adding symbols: %E\n"), member);
-                 loaded = FALSE;
+                 loaded = false;
                }
            }
 
                }
            }
 
@@ -3096,7 +3158,7 @@ load_symbols (lang_input_statement_type *entry,
     }
 
   if (bfd_link_add_symbols (entry->the_bfd, &link_info))
     }
 
   if (bfd_link_add_symbols (entry->the_bfd, &link_info))
-    entry->flags.loaded = TRUE;
+    entry->flags.loaded = true;
   else
     einfo (_("%F%P: %pB: error adding symbols: %E\n"), entry->the_bfd);
 
   else
     einfo (_("%F%P: %pB: error adding symbols: %E\n"), entry->the_bfd);
 
@@ -3391,7 +3453,7 @@ open_output (const char *name)
       einfo (_("%F%P: cannot open output file %s: %E\n"), name);
     }
 
       einfo (_("%F%P: cannot open output file %s: %E\n"), name);
     }
 
-  delete_output_file_on_failure = TRUE;
+  delete_output_file_on_failure = true;
 
   if (!bfd_set_format (link_info.output_bfd, bfd_object))
     einfo (_("%F%P: %s: can not make object file: %E\n"), name);
 
   if (!bfd_set_format (link_info.output_bfd, bfd_object))
     einfo (_("%F%P: %s: can not make object file: %E\n"), name);
@@ -3469,7 +3531,7 @@ enum open_bfd_mode
     OPEN_BFD_FORCE = 1,
     OPEN_BFD_RESCAN = 2
   };
     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
 static lang_input_statement_type *plugin_insert = NULL;
 static struct bfd_link_hash_entry *plugin_undefs = NULL;
 #endif
@@ -3499,7 +3561,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;
        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
 
            lang_input_statement_type *plugin_insert_save;
 #endif
 
@@ -3509,7 +3571,7 @@ open_input_bfds (lang_statement_union_type *s, enum open_bfd_mode mode)
 
            do
              {
 
            do
              {
-#ifdef ENABLE_PLUGINS
+#if BFD_SUPPORTS_PLUGINS
                plugin_insert_save = plugin_insert;
 #endif
                undefs = link_info.hash->undefs_tail;
                plugin_insert_save = plugin_insert;
 #endif
                undefs = link_info.hash->undefs_tail;
@@ -3517,7 +3579,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
                                 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.  */
                   /* Objects inserted by a plugin, which are loaded
                      before we hit this loop, may have added new
                      undefs.  */
@@ -3544,7 +3606,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
                 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
                  && ((mode & OPEN_BFD_RESCAN) == 0
                      || plugin_insert == NULL)
 #endif
@@ -3558,15 +3620,15 @@ open_input_bfds (lang_statement_union_type *s, enum open_bfd_mode mode)
                          && bfd_get_flavour (abfd) == bfd_target_elf_flavour
                          && (elf_dyn_lib_class (abfd) & DYN_AS_NEEDED) != 0)))
                {
                          && bfd_get_flavour (abfd) == bfd_target_elf_flavour
                          && (elf_dyn_lib_class (abfd) & DYN_AS_NEEDED) != 0)))
                {
-                 s->input_statement.flags.loaded = FALSE;
-                 s->input_statement.flags.reload = TRUE;
+                 s->input_statement.flags.loaded = false;
+                 s->input_statement.flags.reload = true;
                }
 
              os_tail = lang_os_list.tail;
              lang_list_init (&add);
 
              if (!load_symbols (&s->input_statement, &add))
                }
 
              os_tail = lang_os_list.tail;
              lang_list_init (&add);
 
              if (!load_symbols (&s->input_statement, &add))
-               config.make_executable = FALSE;
+               config.make_executable = false;
 
              if (add.head != NULL)
                {
 
              if (add.head != NULL)
                {
@@ -3591,7 +3653,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)
          /* 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)
@@ -3612,6 +3674,35 @@ open_input_bfds (lang_statement_union_type *s, enum open_bfd_mode mode)
     einfo ("%F");
 }
 
     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.  */
 /* 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.  */
@@ -3626,7 +3717,7 @@ ldlang_open_ctf (void)
     {
       asection *sect;
 
     {
       asection *sect;
 
-      /* Incoming files from the compiler have a single ctf_file_t in them
+      /* 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.  */
         (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.  */
@@ -3634,19 +3725,25 @@ ldlang_open_ctf (void)
       if ((file->the_ctf = ctf_bfdopen (file->the_bfd, &err)) == NULL)
        {
          if (err != ECTF_NOCTFDATA)
       if ((file->the_ctf = ctf_bfdopen (file->the_bfd, &err)) == NULL)
        {
          if (err != ECTF_NOCTFDATA)
-           einfo (_("%P: warning: CTF section in `%pI' not loaded: "
-                    "its types will be discarded: `%s'\n"), file,
+           {
+             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));
                     ctf_errmsg (err));
+           }
          continue;
        }
 
       /* Prevent the contents of this section from being written, while
          continue;
        }
 
       /* Prevent the contents of this section from being written, while
-        requiring the section itself to be duplicated in the output.  */
+        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;
 
       /* 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;
     }
 
       any_ctf = 1;
     }
 
@@ -3659,7 +3756,7 @@ ldlang_open_ctf (void)
   if ((ctf_output = ctf_create (&err)) != NULL)
     return;
 
   if ((ctf_output = ctf_create (&err)) != NULL)
     return;
 
-  einfo (_("%P: warning: CTF output not created: `s'\n"),
+  einfo (_("%P: warning: CTF output not created: `%s'\n"),
         ctf_errmsg (err));
 
   LANG_FOR_EACH_INPUT_STATEMENT (errfile)
         ctf_errmsg (err));
 
   LANG_FOR_EACH_INPUT_STATEMENT (errfile)
@@ -3673,6 +3770,7 @@ static void
 lang_merge_ctf (void)
 {
   asection *output_sect;
 lang_merge_ctf (void)
 {
   asection *output_sect;
+  int flags = 0;
 
   if (!ctf_output)
     return;
 
   if (!ctf_output)
     return;
@@ -3682,7 +3780,7 @@ lang_merge_ctf (void)
   /* If the section was discarded, don't waste time merging.  */
   if (output_sect == NULL)
     {
   /* If the section was discarded, don't waste time merging.  */
   if (output_sect == NULL)
     {
-      ctf_file_close (ctf_output);
+      ctf_dict_close (ctf_output);
       ctf_output = NULL;
 
       LANG_FOR_EACH_INPUT_STATEMENT (file)
       ctf_output = NULL;
 
       LANG_FOR_EACH_INPUT_STATEMENT (file)
@@ -3698,20 +3796,31 @@ lang_merge_ctf (void)
       if (!file->the_ctf)
        continue;
 
       if (!file->the_ctf)
        continue;
 
-      /* Takes ownership of file->u.the_ctfa.  */
+      /* Takes ownership of file->the_ctf.  */
       if (ctf_link_add_ctf (ctf_output, file->the_ctf, file->filename) < 0)
        {
       if (ctf_link_add_ctf (ctf_output, file->the_ctf, file->filename) < 0)
        {
-         einfo (_("%F%P: cannot link with CTF in %pB: %s\n"), file->the_bfd,
-                ctf_errmsg (ctf_errno (ctf_output)));
+         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;
        }
     }
 
          ctf_close (file->the_ctf);
          file->the_ctf = NULL;
          continue;
        }
     }
 
-  if (ctf_link (ctf_output, CTF_LINK_SHARE_UNCONFLICTED) < 0)
+  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 (bfd_link_relocatable (&link_info))
+    flags |= CTF_LINK_NO_FILTER_REPORTED_SYMS;
+
+  if (ctf_link (ctf_output, flags) < 0)
     {
     {
-      einfo (_("%F%P: CTF linking failed; output will have no CTF section: %s\n"),
+      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)
        {
             ctf_errmsg (ctf_errno (ctf_output)));
       if (output_sect)
        {
@@ -3719,16 +3828,24 @@ lang_merge_ctf (void)
          output_sect->flags |= SEC_EXCLUDE;
        }
     }
          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 examine the symbol table and strtab to help it optimize the
-   CTF, if supported.  */
+/* Let the emulation acquire strings from the dynamic strtab to help it optimize
+   the CTF, if supported.  */
 
 void
 
 void
-ldlang_ctf_apply_strsym (struct elf_sym_strtab *syms, bfd_size_type symcount,
-                        struct elf_strtab_hash *symstrtab)
+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_examine_strtab_for_ctf (ctf_output, syms, symcount, symstrtab);
+  ldemul_new_dynsym_for_ctf (ctf_output, symidx, sym);
 }
 
 /* Write out the CTF section.  Called early, if the emulation isn't going to
 }
 
 /* Write out the CTF section.  Called early, if the emulation isn't going to
@@ -3755,6 +3872,11 @@ lang_write_ctf (int late)
        return;
     }
 
        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");
   /* Emit CTF.  */
 
   output_sect = bfd_get_section_by_name (link_info.output_bfd, ".ctf");
@@ -3765,17 +3887,19 @@ lang_write_ctf (int late)
       output_sect->size = output_size;
       output_sect->flags |= SEC_IN_MEMORY | SEC_KEEP;
 
       output_sect->size = output_size;
       output_sect->flags |= SEC_IN_MEMORY | SEC_KEEP;
 
+      lang_ctf_errs_warnings (ctf_output);
       if (!output_sect->contents)
        {
       if (!output_sect->contents)
        {
-         einfo (_("%F%P: CTF section emission failed; output will have no "
-                  "CTF section: %s\n"), ctf_errmsg (ctf_errno (ctf_output)));
+         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.  */
          output_sect->size = 0;
          output_sect->flags |= SEC_EXCLUDE;
        }
     }
 
   /* This also closes every CTF input file used in the link.  */
-  ctf_file_close (ctf_output);
+  ctf_dict_close (ctf_output);
   ctf_output = NULL;
 
   LANG_FOR_EACH_INPUT_STATEMENT (file)
   ctf_output = NULL;
 
   LANG_FOR_EACH_INPUT_STATEMENT (file)
@@ -3791,6 +3915,38 @@ ldlang_write_ctf_late (void)
 
   lang_write_ctf (1);
 }
 
   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
 
 /* 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
@@ -3803,11 +3959,10 @@ typedef struct bfd_sym_chain ldlang_undef_chain_list_type;
 #define ldlang_undef_chain_list_head entry_symbol.next
 
 void
 #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, bool cmdline ATTRIBUTE_UNUSED)
 {
   ldlang_undef_chain_list_type *new_undef;
 
 {
   ldlang_undef_chain_list_type *new_undef;
 
-  undef_from_cmdline = undef_from_cmdline || cmdline;
   new_undef = stat_alloc (sizeof (*new_undef));
   new_undef->next = ldlang_undef_chain_list_head;
   ldlang_undef_chain_list_head = new_undef;
   new_undef = stat_alloc (sizeof (*new_undef));
   new_undef->next = ldlang_undef_chain_list_head;
   ldlang_undef_chain_list_head = new_undef;
@@ -3825,16 +3980,14 @@ insert_undefined (const char *name)
 {
   struct bfd_link_hash_entry *h;
 
 {
   struct bfd_link_hash_entry *h;
 
-  h = bfd_link_hash_lookup (link_info.hash, name, TRUE, FALSE, TRUE);
+  h = bfd_link_hash_lookup (link_info.hash, name, true, false, true);
   if (h == NULL)
     einfo (_("%F%P: bfd_link_hash_lookup failed: %E\n"));
   if (h->type == bfd_link_hash_new)
     {
       h->type = bfd_link_hash_undefined;
       h->u.undef.abfd = NULL;
   if (h == NULL)
     einfo (_("%F%P: bfd_link_hash_lookup failed: %E\n"));
   if (h->type == bfd_link_hash_new)
     {
       h->type = bfd_link_hash_undefined;
       h->u.undef.abfd = NULL;
-      h->non_ir_ref_regular = TRUE;
-      if (is_elf_hash_table (link_info.hash))
-       ((struct elf_link_hash_entry *) h)->mark = 1;
+      h->non_ir_ref_regular = true;
       bfd_link_add_undef (link_info.hash, h);
     }
 }
       bfd_link_add_undef (link_info.hash, h);
     }
 }
@@ -3852,6 +4005,23 @@ lang_place_undefineds (void)
     insert_undefined (ptr->name);
 }
 
     insert_undefined (ptr->name);
 }
 
+/* Mark -u symbols against garbage collection.  */
+
+static void
+lang_mark_undefineds (void)
+{
+  ldlang_undef_chain_list_type *ptr;
+
+  if (is_elf_hash_table (link_info.hash))
+    for (ptr = ldlang_undef_chain_list_head; ptr != NULL; ptr = ptr->next)
+      {
+       struct elf_link_hash_entry *h = (struct elf_link_hash_entry *)
+         bfd_link_hash_lookup (link_info.hash, ptr->name, false, false, true);
+       if (h != NULL)
+         h->mark = 1;
+      }
+}
+
 /* Structure used to build the list of symbols that the user has required
    be defined.  */
 
 /* Structure used to build the list of symbols that the user has required
    be defined.  */
 
@@ -3873,7 +4043,7 @@ ldlang_add_require_defined (const char *const name)
 {
   struct require_defined_symbol *ptr;
 
 {
   struct require_defined_symbol *ptr;
 
-  ldlang_add_undef (name, TRUE);
+  ldlang_add_undef (name, true);
   ptr = stat_alloc (sizeof (*ptr));
   ptr->next = require_defined_symbol_list;
   ptr->name = strdup (name);
   ptr = stat_alloc (sizeof (*ptr));
   ptr->next = require_defined_symbol_list;
   ptr->name = strdup (name);
@@ -3893,7 +4063,7 @@ ldlang_check_require_defined_symbols (void)
       struct bfd_link_hash_entry *h;
 
       h = bfd_link_hash_lookup (link_info.hash, ptr->name,
       struct bfd_link_hash_entry *h;
 
       h = bfd_link_hash_lookup (link_info.hash, ptr->name,
-                               FALSE, FALSE, TRUE);
+                               false, false, true);
       if (h == NULL
          || (h->type != bfd_link_hash_defined
              && h->type != bfd_link_hash_defweak))
       if (h == NULL
          || (h->type != bfd_link_hash_defined
              && h->type != bfd_link_hash_defweak))
@@ -4026,22 +4196,18 @@ map_input_to_output_sections
          break;
        case lang_output_section_statement_enum:
          tos = &s->output_section_statement;
          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;
+             tos->all_input_readonly = true;
              check_input_sections (tos->children.head, tos);
              if (tos->all_input_readonly != (tos->constraint == ONLY_IF_RO))
              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;
          break;
        case lang_output_statement_enum:
          break;
@@ -4069,6 +4235,9 @@ map_input_to_output_sections
            case noalloc_section:
              flags = SEC_HAS_CONTENTS;
              break;
            case noalloc_section:
              flags = SEC_HAS_CONTENTS;
              break;
+           case readonly_section:
+             flags |= SEC_READONLY;
+             break;
            case noload_section:
              if (bfd_get_flavour (link_info.output_bfd)
                  == bfd_target_elf_flavour)
            case noload_section:
              if (bfd_get_flavour (link_info.output_bfd)
                  == bfd_target_elf_flavour)
@@ -4078,7 +4247,7 @@ map_input_to_output_sections
              break;
            }
          if (os->bfd_section == NULL)
              break;
            }
          if (os->bfd_section == NULL)
-           init_os (os, flags);
+           init_os (os, flags | SEC_READONLY);
          else
            os->bfd_section->flags |= flags;
          break;
          else
            os->bfd_section->flags |= flags;
          break;
@@ -4121,7 +4290,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.  */
                 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);
              tos->addr_tree = s->address_statement.address;
              if (tos->bfd_section == NULL)
                init_os (tos, 0);
@@ -4194,6 +4363,12 @@ process_insert_statements (lang_statement_union_type **start)
          lang_statement_union_type **ptr;
          lang_statement_union_type *first;
 
          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)
            {
          where = lang_output_section_find (i->where);
          if (where != NULL && i->is_before)
            {
@@ -4325,16 +4500,16 @@ strip_excluded_output_sections (void)
     {
       expld.phase = lang_mark_phase_enum;
       expld.dataseg.phase = exp_seg_none;
     {
       expld.phase = lang_mark_phase_enum;
       expld.dataseg.phase = exp_seg_none;
-      one_lang_size_sections_pass (NULL, FALSE);
+      one_lang_size_sections_pass (NULL, false);
       lang_reset_memory_regions ();
     }
 
       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)
     {
       asection *output_section;
        os != NULL;
        os = os->next)
     {
       asection *output_section;
-      bfd_boolean exclude;
+      bool exclude;
 
       if (os->constraint < 0)
        continue;
 
       if (os->constraint < 0)
        continue;
@@ -4361,7 +4536,7 @@ strip_excluded_output_sections (void)
                && ((s->flags & SEC_LINKER_CREATED) != 0
                    || link_info.emitrelocations))
              {
                && ((s->flags & SEC_LINKER_CREATED) != 0
                    || link_info.emitrelocations))
              {
-               exclude = FALSE;
+               exclude = false;
                break;
              }
        }
                break;
              }
        }
@@ -4371,7 +4546,7 @@ strip_excluded_output_sections (void)
          /* We don't set bfd_section to NULL since bfd_section of the
             removed output section statement may still be used.  */
          if (!os->update_dot)
          /* We don't set bfd_section to NULL since bfd_section of the
             removed output section statement may still be used.  */
          if (!os->update_dot)
-           os->ignored = TRUE;
+           os->ignored = true;
          output_section->flags |= SEC_EXCLUDE;
          bfd_section_list_remove (link_info.output_bfd, output_section);
          link_info.output_bfd->section_count--;
          output_section->flags |= SEC_EXCLUDE;
          bfd_section_list_remove (link_info.output_bfd, output_section);
          link_info.output_bfd->section_count--;
@@ -4390,7 +4565,7 @@ lang_clear_os_map (void)
   if (map_head_is_link_order)
     return;
 
   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)
     {
        os != NULL;
        os = os->next)
     {
@@ -4410,7 +4585,7 @@ lang_clear_os_map (void)
 
   /* Stop future calls to lang_add_section from messing with map_head
      and map_tail link_order fields.  */
 
   /* Stop future calls to lang_add_section from messing with map_head
      and map_tail link_order fields.  */
-  map_head_is_link_order = TRUE;
+  map_head_is_link_order = true;
 }
 
 static void
 }
 
 static void
@@ -4462,7 +4637,7 @@ print_assignment (lang_assignment_statement_type *assignment,
                  lang_output_section_statement_type *output_section)
 {
   unsigned int i;
                  lang_output_section_statement_type *output_section)
 {
   unsigned int i;
-  bfd_boolean is_dot;
+  bool is_dot;
   etree_type *tree;
   asection *osec;
 
   etree_type *tree;
   asection *osec;
 
@@ -4471,7 +4646,7 @@ print_assignment (lang_assignment_statement_type *assignment,
 
   if (assignment->exp->type.node_class == etree_assert)
     {
 
   if (assignment->exp->type.node_class == etree_assert)
     {
-      is_dot = FALSE;
+      is_dot = false;
       tree = assignment->exp->assert_s.child;
     }
   else
       tree = assignment->exp->assert_s.child;
     }
   else
@@ -4489,7 +4664,7 @@ print_assignment (lang_assignment_statement_type *assignment,
   if (assignment->exp->type.node_class != etree_provide)
     exp_fold_tree (tree, osec, &print_dot);
   else
   if (assignment->exp->type.node_class != etree_provide)
     exp_fold_tree (tree, osec, &print_dot);
   else
-    expld.result.valid_p = FALSE;
+    expld.result.valid_p = false;
 
   if (expld.result.valid_p)
     {
 
   if (expld.result.valid_p)
     {
@@ -4513,7 +4688,7 @@ print_assignment (lang_assignment_statement_type *assignment,
          struct bfd_link_hash_entry *h;
 
          h = bfd_link_hash_lookup (link_info.hash, assignment->exp->assign.dst,
          struct bfd_link_hash_entry *h;
 
          h = bfd_link_hash_lookup (link_info.hash, assignment->exp->assign.dst,
-                                   FALSE, FALSE, TRUE);
+                                   false, false, true);
          if (h != NULL
              && (h->type == bfd_link_hash_defined
                  || h->type == bfd_link_hash_defweak))
          if (h != NULL
              && (h->type == bfd_link_hash_defined
                  || h->type == bfd_link_hash_defweak))
@@ -4555,7 +4730,7 @@ print_input_statement (lang_input_statement_type *statm)
 /* Print all symbols defined in a particular section.  This is called
    via bfd_link_hash_traverse, or by print_all_symbols.  */
 
 /* Print all symbols defined in a particular section.  This is called
    via bfd_link_hash_traverse, or by print_all_symbols.  */
 
-static bfd_boolean
+bool
 print_one_symbol (struct bfd_link_hash_entry *hash_entry, void *ptr)
 {
   asection *sec = (asection *) ptr;
 print_one_symbol (struct bfd_link_hash_entry *hash_entry, void *ptr)
 {
   asection *sec = (asection *) ptr;
@@ -4576,7 +4751,7 @@ print_one_symbol (struct bfd_link_hash_entry *hash_entry, void *ptr)
       minfo ("             %pT\n", hash_entry->root.string);
     }
 
       minfo ("             %pT\n", hash_entry->root.string);
     }
 
-  return TRUE;
+  return true;
 }
 
 static int
 }
 
 static int
@@ -4619,7 +4794,7 @@ print_all_symbols (asection *sec)
 
   /* Print the symbols.  */
   for (i = 0; i < ud->map_symbol_def_count; i++)
 
   /* 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);
 }
 
   obstack_free (&map_obstack, entries);
 }
@@ -4627,7 +4802,7 @@ print_all_symbols (asection *sec)
 /* Print information about an input section to the map file.  */
 
 static void
 /* Print information about an input section to the map file.  */
 
 static void
-print_input_section (asection *i, bfd_boolean is_discarded)
+print_input_section (asection *i, bool is_discarded)
 {
   bfd_size_type size = i->size;
   int len;
 {
   bfd_size_type size = i->size;
   int len;
@@ -4683,7 +4858,7 @@ print_input_section (asection *i, bfd_boolean is_discarded)
       && i->output_section->owner == link_info.output_bfd)
     {
       if (link_info.reduce_memory_overheads)
       && 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);
 
       else
        print_all_symbols (i);
 
@@ -4999,7 +5174,7 @@ print_statement (lang_statement_union_type *s,
       print_reloc_statement (&s->reloc_statement);
       break;
     case lang_input_section_enum:
       print_reloc_statement (&s->reloc_statement);
       break;
     case lang_input_section_enum:
-      print_input_section (s->input_section.section, FALSE);
+      print_input_section (s->input_section.section, false);
       break;
     case lang_padding_statement_enum:
       print_padding_statement (&s->padding_statement);
       break;
     case lang_padding_statement_enum:
       print_padding_statement (&s->padding_statement);
@@ -5116,11 +5291,27 @@ size_input_section
   (lang_statement_union_type **this_ptr,
    lang_output_section_statement_type *output_section_statement,
    fill_type *fill,
   (lang_statement_union_type **this_ptr,
    lang_output_section_statement_type *output_section_statement,
    fill_type *fill,
+   bool *removed,
    bfd_vma dot)
 {
   lang_input_section_type *is = &((*this_ptr)->input_section);
   asection *i = is->section;
   asection *o = output_section_statement->bfd_section;
    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;
 
   if (i->sec_info_type == SEC_INFO_TYPE_JUST_SYMS)
     i->output_offset = i->vma - o->vma;
@@ -5152,6 +5343,36 @@ size_input_section
          dot += alignment_needed;
        }
 
          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;
 
       /* Remember where in the output section this input section goes.  */
       i->output_offset = dot - o->vma;
 
@@ -5159,6 +5380,14 @@ size_input_section
       dot += TO_ADDR (i->size);
       if (!(o->flags & SEC_FIXED_SIZE))
        o->size = TO_SIZE (dot - o->vma);
       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;
     }
 
   return dot;
@@ -5167,7 +5396,7 @@ size_input_section
 struct check_sec
 {
   asection *sec;
 struct check_sec
 {
   asection *sec;
-  bfd_boolean warned;
+  bool warned;
 };
 
 static int
 };
 
 static int
@@ -5229,7 +5458,7 @@ lang_check_section_addresses (void)
   bfd_vma p_start = 0;
   bfd_vma p_end = 0;
   lang_memory_region_type *m;
   bfd_vma p_start = 0;
   bfd_vma p_end = 0;
   lang_memory_region_type *m;
-  bfd_boolean overlays;
+  bool overlays;
 
   /* Detect address space overflow on allocated sections.  */
   addr_mask = ((bfd_vma) 1 <<
 
   /* Detect address space overflow on allocated sections.  */
   addr_mask = ((bfd_vma) 1 <<
@@ -5266,7 +5495,7 @@ lang_check_section_addresses (void)
        continue;
 
       sections[count].sec = s;
        continue;
 
       sections[count].sec = s;
-      sections[count].warned = FALSE;
+      sections[count].warned = false;
       count++;
     }
 
       count++;
     }
 
@@ -5301,7 +5530,7 @@ lang_check_section_addresses (void)
              einfo (_("%X%P: section %s LMA [%V,%V]"
                       " overlaps section %s LMA [%V,%V]\n"),
                     s->name, s_start, s_end, p->name, p_start, p_end);
              einfo (_("%X%P: section %s LMA [%V,%V]"
                       " overlaps section %s LMA [%V,%V]\n"),
                     s->name, s_start, s_end, p->name, p_start, p_end);
-             sections[i].warned = TRUE;
+             sections[i].warned = true;
            }
          p = s;
          p_start = s_start;
            }
          p = s;
          p_start = s_start;
@@ -5315,14 +5544,14 @@ lang_check_section_addresses (void)
      this property.  It is possible to intentionally generate overlays
      that fail this test, but it would be unusual.  */
   qsort (sections, count, sizeof (*sections), sort_sections_by_vma);
      this property.  It is possible to intentionally generate overlays
      that fail this test, but it would be unusual.  */
   qsort (sections, count, sizeof (*sections), sort_sections_by_vma);
-  overlays = FALSE;
+  overlays = false;
   p_start = sections[0].sec->vma;
   for (i = 1; i < count; i++)
     {
       s_start = sections[i].sec->vma;
       if (p_start == s_start)
        {
   p_start = sections[0].sec->vma;
   for (i = 1; i < count; i++)
     {
       s_start = sections[i].sec->vma;
       if (p_start == s_start)
        {
-         overlays = TRUE;
+         overlays = true;
          break;
        }
       p_start = s_start;
          break;
        }
       p_start = s_start;
@@ -5399,7 +5628,7 @@ os_region_check (lang_output_section_statement_type *os,
        }
       else if (!region->had_full_message)
        {
        }
       else if (!region->had_full_message)
        {
-         region->had_full_message = TRUE;
+         region->had_full_message = true;
 
          einfo (_("%X%P: %pB section `%s' will not fit in region `%s'\n"),
                 os->bfd_section->owner,
 
          einfo (_("%X%P: %pB section `%s' will not fit in region `%s'\n"),
                 os->bfd_section->owner,
@@ -5441,14 +5670,18 @@ lang_size_sections_1
    lang_output_section_statement_type *output_section_statement,
    fill_type *fill,
    bfd_vma dot,
    lang_output_section_statement_type *output_section_statement,
    fill_type *fill,
    bfd_vma dot,
-   bfd_boolean *relax,
-   bfd_boolean check_regions)
+   bool *relax,
+   bool check_regions)
 {
   lang_statement_union_type *s;
 {
   lang_statement_union_type *s;
+  lang_statement_union_type *prev_s = NULL;
+  bool removed_prev_s = false;
 
   /* Size up the sections from their constituent parts.  */
 
   /* 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)
     {
     {
+      bool removed = false;
+
       switch (s->header.type)
        {
        case lang_output_section_statement_enum:
       switch (s->header.type)
        {
        case lang_output_section_statement_enum:
@@ -5473,7 +5706,7 @@ lang_size_sections_1
              os->addr_tree = exp_intop (0);
            if (os->addr_tree != NULL)
              {
              os->addr_tree = exp_intop (0);
            if (os->addr_tree != NULL)
              {
-               os->processed_vma = FALSE;
+               os->processed_vma = false;
                exp_fold_tree (os->addr_tree, bfd_abs_section_ptr, &dot);
 
                if (expld.result.valid_p)
                exp_fold_tree (os->addr_tree, bfd_abs_section_ptr, &dot);
 
                if (expld.result.valid_p)
@@ -5554,7 +5787,7 @@ lang_size_sections_1
                        && (strcmp (lang_memory_region_list->name_list.name,
                                    DEFAULT_MEMORY_REGION) != 0
                            || lang_memory_region_list->next != NULL)
                        && (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
                      {
                        /* By default this is an error rather than just a
                           warning because if we allocate the section to the
@@ -5586,19 +5819,27 @@ lang_size_sections_1
                if (section_alignment > 0)
                  {
                    bfd_vma savedot = newdot;
                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;
                    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
                        && (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 (os->bfd_section, newdot);
                  }
 
                bfd_set_section_vma (os->bfd_section, newdot);
@@ -5609,7 +5850,7 @@ lang_size_sections_1
            lang_size_sections_1 (&os->children.head, os,
                                  os->fill, newdot, relax, check_regions);
 
            lang_size_sections_1 (&os->children.head, os,
                                  os->fill, newdot, relax, check_regions);
 
-           os->processed_vma = TRUE;
+           os->processed_vma = true;
 
            if (bfd_is_abs_section (os->bfd_section) || os->ignored)
              /* Except for some special linker created sections,
 
            if (bfd_is_abs_section (os->bfd_section) || os->ignored)
              /* Except for some special linker created sections,
@@ -5637,7 +5878,7 @@ lang_size_sections_1
            /* Set section lma.  */
            r = os->region;
            if (r == NULL)
            /* Set section lma.  */
            r = os->region;
            if (r == NULL)
-             r = lang_memory_region_lookup (DEFAULT_MEMORY_REGION, FALSE);
+             r = lang_memory_region_lookup (DEFAULT_MEMORY_REGION, false);
 
            if (os->load_base)
              {
 
            if (os->load_base)
              {
@@ -5708,7 +5949,7 @@ lang_size_sections_1
                    os->bfd_section->lma = lma;
                  }
              }
                    os->bfd_section->lma = lma;
                  }
              }
-           os->processed_lma = TRUE;
+           os->processed_lma = true;
 
            /* Keep track of normal sections using the default
               lma region.  We use this to set the lma for
 
            /* Keep track of normal sections using the default
               lma region.  We use this to set the lma for
@@ -5866,15 +6107,15 @@ lang_size_sections_1
            i = s->input_section.section;
            if (relax)
              {
            i = s->input_section.section;
            if (relax)
              {
-               bfd_boolean again;
+               bool again;
 
                if (!bfd_relax_section (i->owner, i, &link_info, &again))
                  einfo (_("%F%P: can't relax section: %E\n"));
                if (again)
 
                if (!bfd_relax_section (i->owner, i, &link_info, &again))
                  einfo (_("%F%P: can't relax section: %E\n"));
                if (again)
-                 *relax = TRUE;
+                 *relax = true;
              }
            dot = size_input_section (prev, output_section_statement,
              }
            dot = size_input_section (prev, output_section_statement,
-                                     fill, dot);
+                                     fill, &removed, dot);
          }
          break;
 
          }
          break;
 
@@ -5917,7 +6158,7 @@ lang_size_sections_1
                    /* If we don't have an output section, then just adjust
                       the default memory address.  */
                    lang_memory_region_lookup (DEFAULT_MEMORY_REGION,
                    /* If we don't have an output section, then just adjust
                       the default memory address.  */
                    lang_memory_region_lookup (DEFAULT_MEMORY_REGION,
-                                              FALSE)->current = newdot;
+                                              false)->current = newdot;
                  }
                else if (newdot != dot)
                  {
                  }
                else if (newdot != dot)
                  {
@@ -5979,7 +6220,43 @@ lang_size_sections_1
          FAIL ();
          break;
        }
          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;
 }
     }
   return dot;
 }
@@ -5989,12 +6266,12 @@ lang_size_sections_1
    CURRENT_SECTION and PREVIOUS_SECTION ought to be placed into different
    segments.  We are allowed an opportunity to override this decision.  */
 
    CURRENT_SECTION and PREVIOUS_SECTION ought to be placed into different
    segments.  We are allowed an opportunity to override this decision.  */
 
-bfd_boolean
+bool
 ldlang_override_segment_assignment (struct bfd_link_info *info ATTRIBUTE_UNUSED,
                                    bfd *abfd ATTRIBUTE_UNUSED,
                                    asection *current_section,
                                    asection *previous_section,
 ldlang_override_segment_assignment (struct bfd_link_info *info ATTRIBUTE_UNUSED,
                                    bfd *abfd ATTRIBUTE_UNUSED,
                                    asection *current_section,
                                    asection *previous_section,
-                                   bfd_boolean new_segment)
+                                   bool new_segment)
 {
   lang_output_section_statement_type *cur;
   lang_output_section_statement_type *prev;
 {
   lang_output_section_statement_type *cur;
   lang_output_section_statement_type *prev;
@@ -6002,7 +6279,7 @@ ldlang_override_segment_assignment (struct bfd_link_info *info ATTRIBUTE_UNUSED,
   /* The checks below are only necessary when the BFD library has decided
      that the two sections ought to be placed into the same segment.  */
   if (new_segment)
   /* The checks below are only necessary when the BFD library has decided
      that the two sections ought to be placed into the same segment.  */
   if (new_segment)
-    return TRUE;
+    return true;
 
   /* Paranoia checks.  */
   if (current_section == NULL || previous_section == NULL)
 
   /* Paranoia checks.  */
   if (current_section == NULL || previous_section == NULL)
@@ -6012,7 +6289,7 @@ ldlang_override_segment_assignment (struct bfd_link_info *info ATTRIBUTE_UNUSED,
      sections comingled in the same segment.  */
   if (config.separate_code
       && ((current_section->flags ^ previous_section->flags) & SEC_CODE))
      sections comingled in the same segment.  */
   if (config.separate_code
       && ((current_section->flags ^ previous_section->flags) & SEC_CODE))
-    return TRUE;
+    return true;
 
   /* Find the memory regions associated with the two sections.
      We call lang_output_section_find() here rather than scanning the list
 
   /* Find the memory regions associated with the two sections.
      We call lang_output_section_find() here rather than scanning the list
@@ -6033,14 +6310,16 @@ ldlang_override_segment_assignment (struct bfd_link_info *info ATTRIBUTE_UNUSED,
 }
 
 void
 }
 
 void
-one_lang_size_sections_pass (bfd_boolean *relax, bfd_boolean check_regions)
+one_lang_size_sections_pass (bool *relax, bool check_regions)
 {
   lang_statement_iteration++;
 {
   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);
 }
 
   lang_size_sections_1 (&statement_list.head, abs_output_section,
                        0, 0, relax, check_regions);
 }
 
-static bfd_boolean
+static bool
 lang_size_segment (seg_align_type *seg)
 {
   /* If XXX_SEGMENT_ALIGN XXX_SEGMENT_END pair was seen, check whether
 lang_size_segment (seg_align_type *seg)
 {
   /* If XXX_SEGMENT_ALIGN XXX_SEGMENT_END pair was seen, check whether
@@ -6055,11 +6334,11 @@ lang_size_segment (seg_align_type *seg)
       && first + last <= seg->pagesize)
     {
       seg->phase = exp_seg_adjust;
       && first + last <= seg->pagesize)
     {
       seg->phase = exp_seg_adjust;
-      return TRUE;
+      return true;
     }
 
   seg->phase = exp_seg_done;
     }
 
   seg->phase = exp_seg_done;
-  return FALSE;
+  return false;
 }
 
 static bfd_vma
 }
 
 static bfd_vma
@@ -6103,22 +6382,22 @@ lang_size_relro_segment_1 (seg_align_type *seg)
   return relro_end;
 }
 
   return relro_end;
 }
 
-static bfd_boolean
-lang_size_relro_segment (bfd_boolean *relax, bfd_boolean check_regions)
+static bool
+lang_size_relro_segment (bool *relax, bool check_regions)
 {
 {
-  bfd_boolean do_reset = FALSE;
-  bfd_boolean do_data_relro;
+  bool do_reset = false;
+  bool do_data_relro;
   bfd_vma data_initial_base, data_relro_end;
 
   if (link_info.relro && expld.dataseg.relro_end)
     {
   bfd_vma data_initial_base, data_relro_end;
 
   if (link_info.relro && expld.dataseg.relro_end)
     {
-      do_data_relro = TRUE;
+      do_data_relro = true;
       data_initial_base = expld.dataseg.base;
       data_relro_end = lang_size_relro_segment_1 (&expld.dataseg);
     }
   else
     {
       data_initial_base = expld.dataseg.base;
       data_relro_end = lang_size_relro_segment_1 (&expld.dataseg);
     }
   else
     {
-      do_data_relro = FALSE;
+      do_data_relro = false;
       data_initial_base = data_relro_end = 0;
     }
 
       data_initial_base = data_relro_end = 0;
     }
 
@@ -6132,18 +6411,18 @@ lang_size_relro_segment (bfd_boolean *relax, bfd_boolean check_regions)
       if (do_data_relro && expld.dataseg.relro_end > data_relro_end)
        {
          expld.dataseg.base = data_initial_base;;
       if (do_data_relro && expld.dataseg.relro_end > data_relro_end)
        {
          expld.dataseg.base = data_initial_base;;
-         do_reset = TRUE;
+         do_reset = true;
        }
     }
 
   if (!do_data_relro && lang_size_segment (&expld.dataseg))
        }
     }
 
   if (!do_data_relro && lang_size_segment (&expld.dataseg))
-    do_reset = TRUE;
+    do_reset = true;
 
   return do_reset;
 }
 
 void
 
   return do_reset;
 }
 
 void
-lang_size_sections (bfd_boolean *relax, bfd_boolean check_regions)
+lang_size_sections (bool *relax, bool check_regions)
 {
   expld.phase = lang_allocating_phase_enum;
   expld.dataseg.phase = exp_seg_none;
 {
   expld.phase = lang_allocating_phase_enum;
   expld.dataseg.phase = exp_seg_none;
@@ -6155,7 +6434,7 @@ lang_size_sections (bfd_boolean *relax, bfd_boolean check_regions)
 
   if (expld.dataseg.phase == exp_seg_end_seen)
     {
 
   if (expld.dataseg.phase == exp_seg_end_seen)
     {
-      bfd_boolean do_reset
+      bool do_reset
        = lang_size_relro_segment (relax, check_regions);
 
       if (do_reset)
        = lang_size_relro_segment (relax, check_regions);
 
       if (do_reset)
@@ -6174,7 +6453,7 @@ lang_size_sections (bfd_boolean *relax, bfd_boolean check_regions)
 
 static lang_output_section_statement_type *current_section;
 static lang_assignment_statement_type *current_assign;
 
 static lang_output_section_statement_type *current_section;
 static lang_assignment_statement_type *current_assign;
-static bfd_boolean prefer_next_section;
+static bool prefer_next_section;
 
 /* Worker function for lang_do_assignments.  Recursiveness goes here.  */
 
 
 /* Worker function for lang_do_assignments.  Recursiveness goes here.  */
 
@@ -6183,7 +6462,7 @@ lang_do_assignments_1 (lang_statement_union_type *s,
                       lang_output_section_statement_type *current_os,
                       fill_type *fill,
                       bfd_vma dot,
                       lang_output_section_statement_type *current_os,
                       fill_type *fill,
                       bfd_vma dot,
-                      bfd_boolean *found_end)
+                      bool *found_end)
 {
   for (; s != NULL; s = s->header.next)
     {
 {
   for (; s != NULL; s = s->header.next)
     {
@@ -6207,7 +6486,7 @@ lang_do_assignments_1 (lang_statement_union_type *s,
                if ((os->bfd_section->flags & SEC_ALLOC) != 0)
                  {
                    current_section = os;
                if ((os->bfd_section->flags & SEC_ALLOC) != 0)
                  {
                    current_section = os;
-                   prefer_next_section = FALSE;
+                   prefer_next_section = false;
                  }
                dot = os->bfd_section->vma;
              }
                  }
                dot = os->bfd_section->vma;
              }
@@ -6312,12 +6591,12 @@ lang_do_assignments_1 (lang_statement_union_type *s,
              const char *p = current_assign->exp->assign.dst;
 
              if (current_os == abs_output_section && p[0] == '.' && p[1] == 0)
              const char *p = current_assign->exp->assign.dst;
 
              if (current_os == abs_output_section && p[0] == '.' && p[1] == 0)
-               prefer_next_section = TRUE;
+               prefer_next_section = true;
 
              while (*p == '_')
                ++p;
              if (strcmp (p, "end") == 0)
 
              while (*p == '_')
                ++p;
              if (strcmp (p, "end") == 0)
-               *found_end = TRUE;
+               *found_end = true;
            }
          exp_fold_tree (s->assignment_statement.exp,
                         (current_os->bfd_section != NULL
            }
          exp_fold_tree (s->assignment_statement.exp,
                         (current_os->bfd_section != NULL
@@ -6351,10 +6630,10 @@ lang_do_assignments_1 (lang_statement_union_type *s,
 void
 lang_do_assignments (lang_phase_type phase)
 {
 void
 lang_do_assignments (lang_phase_type phase)
 {
-  bfd_boolean found_end = FALSE;
+  bool found_end = false;
 
   current_section = NULL;
 
   current_section = NULL;
-  prefer_next_section = FALSE;
+  prefer_next_section = false;
   expld.phase = phase;
   lang_statement_iteration++;
   lang_do_assignments_1 (statement_list.head,
   expld.phase = phase;
   lang_statement_iteration++;
   lang_do_assignments_1 (statement_list.head,
@@ -6549,6 +6828,19 @@ undef_start_stop (struct bfd_link_hash_entry *h)
        }
       h->type = bfd_link_hash_undefined;
       h->u.undef.abfd = NULL;
        }
       h->type = bfd_link_hash_undefined;
       h->u.undef.abfd = NULL;
+      if (is_elf_hash_table (link_info.hash))
+       {
+         const struct elf_backend_data *bed;
+         struct elf_link_hash_entry *eh = (struct elf_link_hash_entry *) h;
+         unsigned int was_forced = eh->forced_local;
+
+         bed = get_elf_backend_data (link_info.output_bfd);
+         (*bed->elf_backend_hide_symbol) (&link_info, eh, true);
+         if (!eh->ref_regular_nonweak)
+           h->type = bfd_link_hash_undefweak;
+         eh->def_regular = 0;
+         eh->forced_local = was_forced;
+       }
     }
 }
 
     }
 }
 
@@ -6625,33 +6917,47 @@ static void
 lang_end (void)
 {
   struct bfd_link_hash_entry *h;
 lang_end (void)
 {
   struct bfd_link_hash_entry *h;
-  bfd_boolean warn;
+  bool warn;
 
   if ((bfd_link_relocatable (&link_info) && !link_info.gc_sections)
       || bfd_link_dll (&link_info))
     warn = entry_from_cmdline;
   else
 
   if ((bfd_link_relocatable (&link_info) && !link_info.gc_sections)
       || bfd_link_dll (&link_info))
     warn = entry_from_cmdline;
   else
-    warn = TRUE;
+    warn = true;
 
   /* Force the user to specify a root when generating a relocatable with
      --gc-sections, unless --gc-keep-exported was also given.  */
   if (bfd_link_relocatable (&link_info)
       && link_info.gc_sections
 
   /* Force the user to specify a root when generating a relocatable with
      --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)
     {
       /* No entry has been specified.  Look for the default entry, but
         don't warn if we don't find it.  */
       entry_symbol.name = entry_symbol_default;
 
   if (entry_symbol.name == NULL)
     {
       /* No entry has been specified.  Look for the default entry, but
         don't warn if we don't find it.  */
       entry_symbol.name = entry_symbol_default;
-      warn = FALSE;
+      warn = false;
     }
 
   h = bfd_link_hash_lookup (link_info.hash, entry_symbol.name,
     }
 
   h = bfd_link_hash_lookup (link_info.hash, entry_symbol.name,
-                           FALSE, FALSE, TRUE);
+                           false, false, true);
   if (h != NULL
       && (h->type == bfd_link_hash_defined
          || h->type == bfd_link_hash_defweak)
   if (h != NULL
       && (h->type == bfd_link_hash_defined
          || h->type == bfd_link_hash_defweak)
@@ -6678,7 +6984,8 @@ lang_end (void)
          if (!bfd_set_start_address (link_info.output_bfd, val))
            einfo (_("%F%P: can't set start address\n"));
        }
          if (!bfd_set_start_address (link_info.output_bfd, val))
            einfo (_("%F%P: can't set start address\n"));
        }
-      else
+      /* BZ 2004952: Only use the start of the entry section for executables.  */
+      else if bfd_link_executable (&link_info)
        {
          asection *ts;
 
        {
          asection *ts;
 
@@ -6704,6 +7011,13 @@ lang_end (void)
                       entry_symbol.name);
            }
        }
                       entry_symbol.name);
            }
        }
+      else
+       {
+         if (warn)
+           einfo (_("%P: warning: cannot find entry symbol %s;"
+                    " not setting start address\n"),
+                  entry_symbol.name);
+       }
     }
 }
 
     }
 }
 
@@ -6728,15 +7042,15 @@ lang_check (void)
   bfd *input_bfd;
   const bfd_arch_info_type *compatible;
 
   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)
     {
        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;
       /* 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,
       input_bfd = file->the_bfd;
       compatible
        = bfd_arch_get_compatible (input_bfd, link_info.output_bfd,
@@ -6748,8 +7062,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).  */
         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)))
          && (compatible == NULL
              || (bfd_get_flavour (input_bfd)
                  != bfd_get_flavour (link_info.output_bfd)))
@@ -6770,11 +7085,13 @@ lang_check (void)
                   bfd_printable_name (input_bfd), input_bfd,
                   bfd_printable_name (link_info.output_bfd));
        }
                   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
          bfd_error_handler_type pfn = NULL;
 
          /* If we aren't supposed to warn about mismatched input
@@ -6836,7 +7153,7 @@ lang_common (void)
 
 /* Place one common symbol in the correct section.  */
 
 
 /* Place one common symbol in the correct section.  */
 
-static bfd_boolean
+static bool
 lang_one_common (struct bfd_link_hash_entry *h, void *info)
 {
   unsigned int power_of_two;
 lang_one_common (struct bfd_link_hash_entry *h, void *info)
 {
   unsigned int power_of_two;
@@ -6844,17 +7161,17 @@ lang_one_common (struct bfd_link_hash_entry *h, void *info)
   asection *section;
 
   if (h->type != bfd_link_hash_common)
   asection *section;
 
   if (h->type != bfd_link_hash_common)
-    return TRUE;
+    return true;
 
   size = h->u.c.size;
   power_of_two = h->u.c.p->alignment_power;
 
   if (config.sort_common == sort_descending
       && power_of_two < *(unsigned int *) info)
 
   size = h->u.c.size;
   power_of_two = h->u.c.p->alignment_power;
 
   if (config.sort_common == sort_descending
       && power_of_two < *(unsigned int *) info)
-    return TRUE;
+    return true;
   else if (config.sort_common == sort_ascending
           && power_of_two > *(unsigned int *) info)
   else if (config.sort_common == sort_ascending
           && power_of_two > *(unsigned int *) info)
-    return TRUE;
+    return true;
 
   section = h->u.c.p->section;
   if (!bfd_define_common_symbol (link_info.output_bfd, &link_info, h))
 
   section = h->u.c.p->section;
   if (!bfd_define_common_symbol (link_info.output_bfd, &link_info, h))
@@ -6863,7 +7180,7 @@ lang_one_common (struct bfd_link_hash_entry *h, void *info)
 
   if (config.map_file != NULL)
     {
 
   if (config.map_file != NULL)
     {
-      static bfd_boolean header_printed;
+      static bool header_printed;
       int len;
       char *name;
       char buf[50];
       int len;
       char *name;
       char buf[50];
@@ -6872,7 +7189,7 @@ lang_one_common (struct bfd_link_hash_entry *h, void *info)
        {
          minfo (_("\nAllocating common symbols\n"));
          minfo (_("Common symbol       size              file\n\n"));
        {
          minfo (_("\nAllocating common symbols\n"));
          minfo (_("Common symbol       size              file\n\n"));
-         header_printed = TRUE;
+         header_printed = true;
        }
 
       name = bfd_demangle (link_info.output_bfd, h->root.string,
        }
 
       name = bfd_demangle (link_info.output_bfd, h->root.string,
@@ -6917,7 +7234,7 @@ lang_one_common (struct bfd_link_hash_entry *h, void *info)
       minfo ("%pB\n", section->owner);
     }
 
       minfo ("%pB\n", section->owner);
     }
 
-  return TRUE;
+  return true;
 }
 
 /* Handle a single orphan section S, placing the orphan into an appropriate
 }
 
 /* Handle a single orphan section S, placing the orphan into an appropriate
@@ -6930,13 +7247,12 @@ ldlang_place_orphan (asection *s)
   if (config.orphan_handling == orphan_handling_discard)
     {
       lang_output_section_statement_type *os;
   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))
        os->addr_tree = exp_intop (0);
       if (os->addr_tree == NULL
          && (bfd_link_relocatable (&link_info)
              || (s->flags & (SEC_LOAD | SEC_ALLOC)) == 0))
        os->addr_tree = exp_intop (0);
-      lang_add_section (&os->children, s, NULL, os);
+      lang_add_section (&os->children, s, NULL, NULL, os);
     }
   else
     {
     }
   else
     {
@@ -6954,12 +7270,12 @@ ldlang_place_orphan (asection *s)
       os = ldemul_place_orphan (s, name, constraint);
       if (os == NULL)
        {
       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))
            os->addr_tree = exp_intop (0);
          if (os->addr_tree == NULL
              && (bfd_link_relocatable (&link_info)
                  || (s->flags & (SEC_LOAD | SEC_ALLOC)) == 0))
            os->addr_tree = exp_intop (0);
-         lang_add_section (&os->children, s, NULL, os);
+         lang_add_section (&os->children, s, NULL, NULL, os);
        }
 
       if (config.orphan_handling == orphan_handling_warn)
        }
 
       if (config.orphan_handling == orphan_handling_warn)
@@ -7001,10 +7317,9 @@ lang_place_orphans (void)
                    {
                      if (default_common_section == NULL)
                        default_common_section
                    {
                      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,
                      lang_add_section (&default_common_section->children, s,
-                                       NULL, default_common_section);
+                                       NULL, NULL, default_common_section);
                    }
                }
              else
                    }
                }
              else
@@ -7070,7 +7385,7 @@ lang_for_each_input_file (void (*func) (lang_input_statement_type *))
 {
   lang_input_statement_type *f;
 
 {
   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)
     if (f->flags.real)
        f != NULL;
        f = f->next_real_file)
     if (f->flags.real)
@@ -7098,7 +7413,8 @@ ldlang_add_file (lang_input_statement_type *entry)
 
   /* The BFD linker needs to have a list of all input BFDs involved in
      a link.  */
 
   /* 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;
   ASSERT (entry->the_bfd != link_info.output_bfd);
 
   *link_info.input_bfds_tail = entry->the_bfd;
@@ -7126,7 +7442,7 @@ lang_add_output (const char *name, int from_script)
   if (!had_output_filename || !from_script)
     {
       output_filename = name;
   if (!had_output_filename || !from_script)
     {
       output_filename = name;
-      had_output_filename = TRUE;
+      had_output_filename = true;
     }
 }
 
     }
 }
 
@@ -7143,7 +7459,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,
   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)
   current_section = os;
 
   if (os->addr_tree == NULL)
@@ -7196,12 +7512,12 @@ lang_reset_memory_regions (void)
       p->last_os = NULL;
     }
 
       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)
     {
        os != NULL;
        os = os->next)
     {
-      os->processed_vma = FALSE;
-      os->processed_lma = FALSE;
+      os->processed_vma = false;
+      os->processed_lma = false;
     }
 
   for (o = link_info.output_bfd->sections; o != NULL; o = o->next)
     }
 
   for (o = link_info.output_bfd->sections; o != NULL; o = o->next)
@@ -7219,7 +7535,6 @@ static void
 gc_section_callback (lang_wild_statement_type *ptr,
                     struct wildcard_list *sec ATTRIBUTE_UNUSED,
                     asection *section,
 gc_section_callback (lang_wild_statement_type *ptr,
                     struct wildcard_list *sec ATTRIBUTE_UNUSED,
                     asection *section,
-                    struct flag_info *sflag_info ATTRIBUTE_UNUSED,
                     lang_input_statement_type *file ATTRIBUTE_UNUSED,
                     void *data ATTRIBUTE_UNUSED)
 {
                     lang_input_statement_type *file ATTRIBUTE_UNUSED,
                     void *data ATTRIBUTE_UNUSED)
 {
@@ -7263,19 +7578,20 @@ lang_gc_sections (void)
   lang_gc_sections_1 (statement_list.head);
 
   /* SEC_EXCLUDE is ignored when doing a relocatable link, except in
   lang_gc_sections_1 (statement_list.head);
 
   /* SEC_EXCLUDE is ignored when doing a relocatable link, except in
-     the special case of debug info.  (See bfd/stabs.c)
+     the special case of .stabstr debug info.  (See bfd/stabs.c)
      Twiddle the flag here, to simplify later linker code.  */
   if (bfd_link_relocatable (&link_info))
     {
       LANG_FOR_EACH_INPUT_STATEMENT (f)
        {
          asection *sec;
      Twiddle the flag here, to simplify later linker code.  */
   if (bfd_link_relocatable (&link_info))
     {
       LANG_FOR_EACH_INPUT_STATEMENT (f)
        {
          asection *sec;
-#ifdef ENABLE_PLUGINS
+#if BFD_SUPPORTS_PLUGINS
          if (f->flags.claimed)
            continue;
 #endif
          for (sec = f->the_bfd->sections; sec != NULL; sec = sec->next)
          if (f->flags.claimed)
            continue;
 #endif
          for (sec = f->the_bfd->sections; sec != NULL; sec = sec->next)
-           if ((sec->flags & SEC_DEBUGGING) == 0)
+           if ((sec->flags & SEC_DEBUGGING) == 0
+               || strcmp (sec->name, ".stabstr") != 0)
              sec->flags &= ~SEC_EXCLUDE;
        }
     }
              sec->flags &= ~SEC_EXCLUDE;
        }
     }
@@ -7290,7 +7606,6 @@ static void
 find_relro_section_callback (lang_wild_statement_type *ptr ATTRIBUTE_UNUSED,
                             struct wildcard_list *sec ATTRIBUTE_UNUSED,
                             asection *section,
 find_relro_section_callback (lang_wild_statement_type *ptr ATTRIBUTE_UNUSED,
                             struct wildcard_list *sec ATTRIBUTE_UNUSED,
                             asection *section,
-                            struct flag_info *sflag_info ATTRIBUTE_UNUSED,
                             lang_input_statement_type *file ATTRIBUTE_UNUSED,
                             void *data)
 {
                             lang_input_statement_type *file ATTRIBUTE_UNUSED,
                             void *data)
 {
@@ -7302,8 +7617,8 @@ find_relro_section_callback (lang_wild_statement_type *ptr ATTRIBUTE_UNUSED,
       && !IGNORE_SECTION (section)
       && section->size != 0)
     {
       && !IGNORE_SECTION (section)
       && section->size != 0)
     {
-      bfd_boolean *has_relro_section = (bfd_boolean *) data;
-      *has_relro_section = TRUE;
+      bool *has_relro_section = (bool *) data;
+      *has_relro_section = true;
     }
 }
 
     }
 }
 
@@ -7312,7 +7627,7 @@ 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,
 static void
 lang_find_relro_sections_1 (lang_statement_union_type *s,
                            seg_align_type *seg,
-                           bfd_boolean *has_relro_section)
+                           bool *has_relro_section)
 {
   if (*has_relro_section)
     return;
 {
   if (*has_relro_section)
     return;
@@ -7350,7 +7665,7 @@ lang_find_relro_sections_1 (lang_statement_union_type *s,
 static void
 lang_find_relro_sections (void)
 {
 static void
 lang_find_relro_sections (void)
 {
-  bfd_boolean has_relro_section = FALSE;
+  bool has_relro_section = false;
 
   /* Check all sections in the link script.  */
 
 
   /* Check all sections in the link script.  */
 
@@ -7358,13 +7673,13 @@ lang_find_relro_sections (void)
                              &expld.dataseg, &has_relro_section);
 
   if (!has_relro_section)
                              &expld.dataseg, &has_relro_section);
 
   if (!has_relro_section)
-    link_info.relro = FALSE;
+    link_info.relro = false;
 }
 
 /* Relax all sections until bfd_relax_section gives up.  */
 
 void
 }
 
 /* Relax all sections until bfd_relax_section gives up.  */
 
 void
-lang_relax_sections (bfd_boolean need_layout)
+lang_relax_sections (bool need_layout)
 {
   if (RELAXATION_ENABLED)
     {
 {
   if (RELAXATION_ENABLED)
     {
@@ -7377,7 +7692,7 @@ lang_relax_sections (bfd_boolean need_layout)
       while (i--)
        {
          /* Keep relaxing until bfd_relax_section gives up.  */
       while (i--)
        {
          /* Keep relaxing until bfd_relax_section gives up.  */
-         bfd_boolean relax_again;
+         bool relax_again;
 
          link_info.relax_trip = -1;
          do
 
          link_info.relax_trip = -1;
          do
@@ -7398,14 +7713,14 @@ lang_relax_sections (bfd_boolean need_layout)
 
              /* Perform another relax pass - this time we know where the
                 globals are, so can make a better guess.  */
 
              /* Perform another relax pass - this time we know where the
                 globals are, so can make a better guess.  */
-             relax_again = FALSE;
-             lang_size_sections (&relax_again, FALSE);
+             relax_again = false;
+             lang_size_sections (&relax_again, false);
            }
          while (relax_again);
 
          link_info.relax_pass++;
        }
            }
          while (relax_again);
 
          link_info.relax_pass++;
        }
-      need_layout = TRUE;
+      need_layout = true;
     }
 
   if (need_layout)
     }
 
   if (need_layout)
@@ -7413,11 +7728,11 @@ lang_relax_sections (bfd_boolean need_layout)
       /* Final extra sizing to report errors.  */
       lang_do_assignments (lang_assigning_phase_enum);
       lang_reset_memory_regions ();
       /* Final extra sizing to report errors.  */
       lang_do_assignments (lang_assigning_phase_enum);
       lang_reset_memory_regions ();
-      lang_size_sections (NULL, TRUE);
+      lang_size_sections (NULL, true);
     }
 }
 
     }
 }
 
-#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
 /* 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
@@ -7430,11 +7745,11 @@ lang_relax_sections (bfd_boolean need_layout)
    inserted at the head of the file_chain.  */
 
 static lang_input_statement_type *
    inserted at the head of the file_chain.  */
 
 static lang_input_statement_type *
-find_replacements_insert_point (bfd_boolean *before)
+find_replacements_insert_point (bool *before)
 {
   lang_input_statement_type *claim1, *lastobject;
 {
   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)
     {
        claim1 != NULL;
        claim1 = claim1->next)
     {
@@ -7450,7 +7765,7 @@ find_replacements_insert_point (bfd_boolean *before)
   /* No files were claimed by the plugin.  Choose the last object
      file found on the list (maybe the first, dummy entry) as the
      insert point.  */
   /* No files were claimed by the plugin.  Choose the last object
      file found on the list (maybe the first, dummy entry) as the
      insert point.  */
-  *before = FALSE;
+  *before = false;
   return lastobject;
 }
 
   return lastobject;
 }
 
@@ -7476,7 +7791,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.  */
      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)
     {
        f != NULL;
        f = f->next_real_file)
     {
@@ -7560,7 +7875,7 @@ find_next_input_statement (lang_statement_union_type **s)
     }
   return s;
 }
     }
   return s;
 }
-#endif /* ENABLE_PLUGINS */
+#endif /* BFD_SUPPORTS_PLUGINS */
 
 /* Add NAME to the list of garbage collection entry points.  */
 
 
 /* Add NAME to the list of garbage collection entry points.  */
 
@@ -7593,7 +7908,7 @@ lang_check_relocs (void)
        if (!bfd_link_check_relocs (abfd, &link_info))
          {
            /* No object output, fail return.  */
        if (!bfd_link_check_relocs (abfd, &link_info))
          {
            /* No object output, fail return.  */
-           config.make_executable = FALSE;
+           config.make_executable = false;
            /* Note: we do not abort the loop, but rather
               continue the scan in case there are other
               bad relocations to report.  */
            /* Note: we do not abort the loop, but rather
               continue the scan in case there are other
               bad relocations to report.  */
@@ -7609,7 +7924,7 @@ lang_propagate_lma_regions (void)
 {
   lang_output_section_statement_type *os;
 
 {
   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)
     {
        os != NULL;
        os = os->next)
     {
@@ -7643,15 +7958,24 @@ lang_process (void)
   if (!bfd_section_already_linked_table_init ())
     einfo (_("%F%P: can not create hash table: %E\n"));
 
   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);
   /* 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;
   if (link_info.lto_plugin_active)
     {
       lang_statement_list_type added;
@@ -7670,6 +7994,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 ());
       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);
       /* Open any newly added files, updating the file chains.  */
       plugin_undefs = link_info.hash->undefs_tail;
       open_input_bfds (*added.tail, OPEN_BFD_NORMAL);
@@ -7687,7 +8012,7 @@ lang_process (void)
             after the first input file that was claimed by the plugin,
             unless that file was an archive in which case it is inserted
             immediately before.  */
             after the first input file that was claimed by the plugin,
             unless that file was an archive in which case it is inserted
             immediately before.  */
-         bfd_boolean before;
+         bool before;
          lang_statement_union_type **prev;
          plugin_insert = find_replacements_insert_point (&before);
          /* If a plugin adds input files without having claimed any, we
          lang_statement_union_type **prev;
          plugin_insert = find_replacements_insert_point (&before);
          /* If a plugin adds input files without having claimed any, we
@@ -7754,7 +8079,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.  */
 
   /* Make sure that nobody has tried to add a symbol to this list
      before now.  */
@@ -7820,6 +8145,8 @@ lang_process (void)
   /* Remove unreferenced sections if asked to.  */
   lang_gc_sections ();
 
   /* Remove unreferenced sections if asked to.  */
   lang_gc_sections ();
 
+  lang_mark_undefineds ();
+
   /* Check relocations.  */
   lang_check_relocs ();
 
   /* Check relocations.  */
   lang_check_relocs ();
 
@@ -7837,6 +8164,8 @@ lang_process (void)
      output statement, so that it isn't reordered.  */
   process_insert_statements (&lang_os_list.head->header.next);
 
      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 ();
 
   /* Find any sections not attached explicitly and handle them.  */
   lang_place_orphans ();
 
@@ -7933,7 +8262,7 @@ lang_process (void)
 void
 lang_add_wild (struct wildcard_spec *filespec,
               struct wildcard_list *section_list,
 void
 lang_add_wild (struct wildcard_spec *filespec,
               struct wildcard_list *section_list,
-              bfd_boolean keep_sections)
+              bool keep_sections)
 {
   struct wildcard_list *curr, *next;
   lang_wild_statement_type *new_stmt;
 {
   struct wildcard_list *curr, *next;
   lang_wild_statement_type *new_stmt;
@@ -7952,12 +8281,12 @@ lang_add_wild (struct wildcard_spec *filespec,
       if (strcmp (filespec->name, "*") == 0)
        filespec->name = NULL;
       else if (!wildcardp (filespec->name))
       if (strcmp (filespec->name, "*") == 0)
        filespec->name = NULL;
       else if (!wildcardp (filespec->name))
-       lang_has_input_file = TRUE;
+       lang_has_input_file = true;
     }
 
   new_stmt = new_stat (lang_wild_statement, stat_ptr);
   new_stmt->filename = NULL;
     }
 
   new_stmt = new_stat (lang_wild_statement, stat_ptr);
   new_stmt->filename = NULL;
-  new_stmt->filenames_sorted = FALSE;
+  new_stmt->filenames_sorted = false;
   new_stmt->section_flag_list = NULL;
   new_stmt->exclude_name_list = NULL;
   if (filespec != NULL)
   new_stmt->section_flag_list = NULL;
   new_stmt->exclude_name_list = NULL;
   if (filespec != NULL)
@@ -7991,7 +8320,7 @@ lang_section_start (const char *name, etree_type *address,
    precedence.  */
 
 void
    precedence.  */
 
 void
-lang_add_entry (const char *name, bfd_boolean cmdline)
+lang_add_entry (const char *name, bool cmdline)
 {
   if (entry_symbol.name == NULL
       || cmdline
 {
   if (entry_symbol.name == NULL
       || cmdline
@@ -8029,7 +8358,7 @@ lang_add_map (const char *name)
       switch (*name)
        {
        case 'F':
       switch (*name)
        {
        case 'F':
-         map_option_f = TRUE;
+         map_option_f = true;
          break;
        }
       name++;
          break;
        }
       name++;
@@ -8107,11 +8436,11 @@ lang_startup (const char *name)
     }
   first_file->filename = name;
   first_file->local_sym_name = name;
     }
   first_file->filename = name;
   first_file->local_sym_name = name;
-  first_file->flags.real = TRUE;
+  first_file->flags.real = true;
 }
 
 void
 }
 
 void
-lang_float (bfd_boolean maybe)
+lang_float (bool maybe)
 {
   lang_float_flag = maybe;
 }
 {
   lang_float_flag = maybe;
 }
@@ -8133,10 +8462,10 @@ lang_get_regions (lang_memory_region_type **region,
                  lang_memory_region_type **lma_region,
                  const char *memspec,
                  const char *lma_memspec,
                  lang_memory_region_type **lma_region,
                  const char *memspec,
                  const char *lma_memspec,
-                 bfd_boolean have_lma,
-                 bfd_boolean have_vma)
+                 bool have_lma,
+                 bool have_vma)
 {
 {
-  *lma_region = lang_memory_region_lookup (lma_memspec, FALSE);
+  *lma_region = lang_memory_region_lookup (lma_memspec, false);
 
   /* If no runtime region or VMA has been specified, but the load region
      has been specified, then use the load region for the runtime region
 
   /* If no runtime region or VMA has been specified, but the load region
      has been specified, then use the load region for the runtime region
@@ -8146,7 +8475,7 @@ lang_get_regions (lang_memory_region_type **region,
       && strcmp (memspec, DEFAULT_MEMORY_REGION) == 0)
     *region = *lma_region;
   else
       && strcmp (memspec, DEFAULT_MEMORY_REGION) == 0)
     *region = *lma_region;
   else
-    *region = lang_memory_region_lookup (memspec, FALSE);
+    *region = lang_memory_region_lookup (memspec, false);
 
   if (have_lma && lma_memspec != 0)
     einfo (_("%X%P:%pS: section has both a load address and a load region\n"),
 
   if (have_lma && lma_memspec != 0)
     einfo (_("%X%P:%pS: section has both a load address and a load region\n"),
@@ -8231,13 +8560,13 @@ lang_leave_group (void)
 void
 lang_new_phdr (const char *name,
               etree_type *type,
 void
 lang_new_phdr (const char *name,
               etree_type *type,
-              bfd_boolean filehdr,
-              bfd_boolean phdrs,
+              bool filehdr,
+              bool phdrs,
               etree_type *at,
               etree_type *flags)
 {
   struct lang_phdr *n, **pp;
               etree_type *at,
               etree_type *flags)
 {
   struct lang_phdr *n, **pp;
-  bfd_boolean hdrs;
+  bool hdrs;
 
   n = stat_alloc (sizeof (struct lang_phdr));
   n->next = NULL;
 
   n = stat_alloc (sizeof (struct lang_phdr));
   n->next = NULL;
@@ -8257,7 +8586,7 @@ lang_new_phdr (const char *name,
       {
        einfo (_("%X%P:%pS: PHDRS and FILEHDR are not supported"
                 " when prior PT_LOAD headers lack them\n"), NULL);
       {
        einfo (_("%X%P:%pS: PHDRS and FILEHDR are not supported"
                 " when prior PT_LOAD headers lack them\n"), NULL);
-       hdrs = FALSE;
+       hdrs = false;
       }
 
   *pp = n;
       }
 
   *pp = n;
@@ -8286,7 +8615,7 @@ lang_record_phdrs (void)
       bfd_vma at;
 
       c = 0;
       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)
        {
           os != NULL;
           os = os->next)
        {
@@ -8348,7 +8677,7 @@ lang_record_phdrs (void)
                    }
                  secs[c] = os->bfd_section;
                  ++c;
                    }
                  secs[c] = os->bfd_section;
                  ++c;
-                 pl->used = TRUE;
+                 pl->used = true;
                }
            }
        }
                }
            }
        }
@@ -8372,7 +8701,7 @@ lang_record_phdrs (void)
   free (secs);
 
   /* Make sure all the phdr assignments succeeded.  */
   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)
     {
        os != NULL;
        os = os->next)
     {
@@ -8401,11 +8730,11 @@ lang_add_nocrossref (lang_nocrossref_type *l)
   n = (struct lang_nocrossrefs *) xmalloc (sizeof *n);
   n->next = nocrossref_list;
   n->list = l;
   n = (struct lang_nocrossrefs *) xmalloc (sizeof *n);
   n->next = nocrossref_list;
   n->list = l;
-  n->onlyfirst = FALSE;
+  n->onlyfirst = false;
   nocrossref_list = n;
 
   /* Set notice_all so that we get informed about all symbols.  */
   nocrossref_list = n;
 
   /* Set notice_all so that we get informed about all symbols.  */
-  link_info.notice_all = TRUE;
+  link_info.notice_all = true;
 }
 
 /* Record a section that cannot be referenced from a list of sections.  */
 }
 
 /* Record a section that cannot be referenced from a list of sections.  */
@@ -8414,7 +8743,7 @@ void
 lang_add_nocrossref_to (lang_nocrossref_type *l)
 {
   lang_add_nocrossref (l);
 lang_add_nocrossref_to (lang_nocrossref_type *l)
 {
   lang_add_nocrossref (l);
-  nocrossref_list->onlyfirst = TRUE;
+  nocrossref_list->onlyfirst = true;
 }
 \f
 /* Overlay handling.  We handle overlays with some static variables.  */
 }
 \f
 /* Overlay handling.  We handle overlays with some static variables.  */
@@ -8517,7 +8846,7 @@ lang_leave_overlay_section (fill_type *fill,
   sprintf (buf, "__load_start_%s", clean);
   lang_add_assignment (exp_provide (buf,
                                    exp_nameop (LOADADDR, name),
   sprintf (buf, "__load_start_%s", clean);
   lang_add_assignment (exp_provide (buf,
                                    exp_nameop (LOADADDR, name),
-                                   FALSE));
+                                   false));
 
   buf = (char *) xmalloc (strlen (clean) + sizeof "__load_stop_");
   sprintf (buf, "__load_stop_%s", clean);
 
   buf = (char *) xmalloc (strlen (clean) + sizeof "__load_stop_");
   sprintf (buf, "__load_stop_%s", clean);
@@ -8525,7 +8854,7 @@ lang_leave_overlay_section (fill_type *fill,
                                    exp_binop ('+',
                                               exp_nameop (LOADADDR, name),
                                               exp_nameop (SIZEOF, name)),
                                    exp_binop ('+',
                                               exp_nameop (LOADADDR, name),
                                               exp_nameop (SIZEOF, name)),
-                                   FALSE));
+                                   false));
 
   free (clean);
 }
 
   free (clean);
 }
@@ -8548,7 +8877,7 @@ lang_leave_overlay (etree_type *lma_expr,
 
   lang_get_regions (&region, &lma_region,
                    memspec, lma_memspec,
 
   lang_get_regions (&region, &lma_region,
                    memspec, lma_memspec,
-                   lma_expr != NULL, FALSE);
+                   lma_expr != NULL, false);
 
   nocrossref = NULL;
 
 
   nocrossref = NULL;
 
@@ -8558,7 +8887,7 @@ lang_leave_overlay (etree_type *lma_expr,
     {
       overlay_list->os->update_dot = 1;
       overlay_list->os->update_dot_tree
     {
       overlay_list->os->update_dot = 1;
       overlay_list->os->update_dot_tree
-       = exp_assign (".", exp_binop ('+', overlay_vma, overlay_max), FALSE);
+       = exp_assign (".", exp_binop ('+', overlay_vma, overlay_max), false);
     }
 
   l = overlay_list;
     }
 
   l = overlay_list;
@@ -8738,7 +9067,7 @@ static const char *
 realsymbol (const char *pattern)
 {
   const char *p;
 realsymbol (const char *pattern)
 {
   const char *p;
-  bfd_boolean changed = FALSE, backslash = FALSE;
+  bool changed = false, backslash = false;
   char *s, *symbol = (char *) xmalloc (strlen (pattern) + 1);
 
   for (p = pattern, s = symbol; *p != '\0'; ++p)
   char *s, *symbol = (char *) xmalloc (strlen (pattern) + 1);
 
   for (p = pattern, s = symbol; *p != '\0'; ++p)
@@ -8749,8 +9078,8 @@ realsymbol (const char *pattern)
        {
          /* Remove the preceding backslash.  */
          *(s - 1) = *p;
        {
          /* Remove the preceding backslash.  */
          *(s - 1) = *p;
-         backslash = FALSE;
-         changed = TRUE;
+         backslash = false;
+         changed = true;
        }
       else
        {
        }
       else
        {
@@ -8785,7 +9114,7 @@ struct bfd_elf_version_expr *
 lang_new_vers_pattern (struct bfd_elf_version_expr *orig,
                       const char *new_name,
                       const char *lang,
 lang_new_vers_pattern (struct bfd_elf_version_expr *orig,
                       const char *new_name,
                       const char *lang,
-                      bfd_boolean literal_p)
+                      bool literal_p)
 {
   struct bfd_elf_version_expr *ret;
 
 {
   struct bfd_elf_version_expr *ret;
 
@@ -8793,12 +9122,12 @@ lang_new_vers_pattern (struct bfd_elf_version_expr *orig,
   ret->next = orig;
   ret->symver = 0;
   ret->script = 0;
   ret->next = orig;
   ret->symver = 0;
   ret->script = 0;
-  ret->literal = TRUE;
+  ret->literal = true;
   ret->pattern = literal_p ? new_name : realsymbol (new_name);
   if (ret->pattern == NULL)
     {
       ret->pattern = new_name;
   ret->pattern = literal_p ? new_name : realsymbol (new_name);
   if (ret->pattern == NULL)
     {
       ret->pattern = new_name;
-      ret->literal = FALSE;
+      ret->literal = false;
     }
 
   if (lang == NULL || strcasecmp (lang, "C") == 0)
     }
 
   if (lang == NULL || strcasecmp (lang, "C") == 0)
@@ -9089,7 +9418,7 @@ lang_do_version_exports_section (void)
       p = contents;
       while (p < contents + len)
        {
       p = contents;
       while (p < contents + len)
        {
-         greg = lang_new_vers_pattern (greg, p, NULL, FALSE);
+         greg = lang_new_vers_pattern (greg, p, NULL, false);
          p = strchr (p, '\0') + 1;
        }
 
          p = strchr (p, '\0') + 1;
        }
 
@@ -9099,15 +9428,21 @@ lang_do_version_exports_section (void)
       sec->flags |= SEC_EXCLUDE | SEC_KEEP;
     }
 
       sec->flags |= SEC_EXCLUDE | SEC_KEEP;
     }
 
-  lreg = lang_new_vers_pattern (NULL, "*", NULL, FALSE);
+  lreg = lang_new_vers_pattern (NULL, "*", NULL, false);
   lang_register_vers_node (command_line.version_exports_section,
                           lang_new_vers_node (greg, lreg), NULL);
 }
 
   lang_register_vers_node (command_line.version_exports_section,
                           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
 
 static void
-lang_do_memory_regions (void)
+lang_do_memory_regions (bool update_regions_p)
 {
   lang_memory_region_type *r = lang_memory_region_list;
 
 {
   lang_memory_region_type *r = lang_memory_region_list;
 
@@ -9116,24 +9451,30 @@ lang_do_memory_regions (void)
       if (r->origin_exp)
        {
          exp_fold_tree_no_dot (r->origin_exp);
       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 (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);
+            }
+        }
     }
 }
 
     }
 }
 
@@ -9155,15 +9496,16 @@ lang_add_unique (const char *name)
 /* Append the list of dynamic symbols to the existing one.  */
 
 void
 /* 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)
        ;
     {
       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
     {
     }
   else
     {
@@ -9172,7 +9514,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;
       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;
     }
 }
 
     }
 }
 
@@ -9192,9 +9534,9 @@ lang_append_dynamic_list_cpp_typeinfo (void)
 
   for (i = 0; i < ARRAY_SIZE (symbols); i++)
     dynamic = lang_new_vers_pattern (dynamic, symbols [i], "C++",
 
   for (i = 0; i < ARRAY_SIZE (symbols); i++)
     dynamic = lang_new_vers_pattern (dynamic, symbols [i], "C++",
-                                    FALSE);
+                                    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
 }
 
 /* Append the list of C++ operator new and delete dynamic symbols to the
@@ -9213,9 +9555,9 @@ lang_append_dynamic_list_cpp_new (void)
 
   for (i = 0; i < ARRAY_SIZE (symbols); i++)
     dynamic = lang_new_vers_pattern (dynamic, symbols [i], "C++",
 
   for (i = 0; i < ARRAY_SIZE (symbols); i++)
     dynamic = lang_new_vers_pattern (dynamic, symbols [i], "C++",
-                                    FALSE);
+                                    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.  */
 }
 
 /* Scan a space and/or comma separated string of features.  */
@@ -9239,7 +9581,7 @@ lang_ld_feature (char *str)
       sep = *q;
       *q = 0;
       if (strcasecmp (p, "SANE_EXPR") == 0)
       sep = *q;
       *q = 0;
       if (strcasecmp (p, "SANE_EXPR") == 0)
-       config.sane_expr = TRUE;
+       config.sane_expr = true;
       else
        einfo (_("%X%P: unknown feature `%s'\n"), p);
       *q = sep;
       else
        einfo (_("%X%P: unknown feature `%s'\n"), p);
       *q = sep;