x86: Also check x86 linker_def for non-shared definition
[deliverable/binutils-gdb.git] / ld / ldlang.c
index 419caa1ea5b1f30d51dfa49a32ae36d4ac04066b..898735efab59a0d3a0494d4a54efcee62c042153 100644 (file)
@@ -1,5 +1,5 @@
 /* Linker command language support.
-   Copyright (C) 1991-2014 Free Software Foundation, Inc.
+   Copyright (C) 1991-2019 Free Software Foundation, Inc.
 
    This file is part of the GNU Binutils.
 
@@ -39,7 +39,6 @@
 #include "fnmatch.h"
 #include "demangle.h"
 #include "hashtab.h"
-#include "libbfd.h"
 #include "elf-bfd.h"
 #ifdef ENABLE_PLUGINS
 #include "plugin.h"
 #define offsetof(TYPE, MEMBER) ((size_t) & (((TYPE*) 0)->MEMBER))
 #endif
 
-/* Locals variables.  */
+/* Convert between addresses in bytes and sizes in octets.
+   For currently supported targets, octets_per_byte is always a power
+   of two, so we can use shifts.  */
+#define TO_ADDR(X) ((X) >> opb_shift)
+#define TO_SIZE(X) ((X) << opb_shift)
+
+/* Local variables.  */
 static struct obstack stat_obstack;
 static struct obstack map_obstack;
 
 #define obstack_chunk_alloc xmalloc
 #define obstack_chunk_free free
 static const char *entry_symbol_default = "start";
-static bfd_boolean placed_commons = FALSE;
-static bfd_boolean stripped_excluded_sections = FALSE;
+static bfd_boolean map_head_is_link_order = FALSE;
 static lang_output_section_statement_type *default_common_section;
 static bfd_boolean map_option_f;
 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 struct bfd_hash_table lang_definedness_table;
 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 struct asneeded_minfo *asneeded_list_head;
+static unsigned int opb_shift = 0;
 
 /* Forward declarations.  */
 static void exp_init_os (etree_type *);
 static lang_input_statement_type *lookup_name (const char *);
-static struct bfd_hash_entry *lang_definedness_newfunc
- (struct bfd_hash_entry *, struct bfd_hash_table *, const char *);
 static void insert_undefined (const char *);
 static bfd_boolean sort_def_symbol (struct bfd_link_hash_entry *, void *);
 static void print_statement (lang_statement_union_type *,
@@ -88,13 +96,24 @@ 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);
 
 /* Exported variables.  */
 const char *output_target;
 lang_output_section_statement_type *abs_output_section;
 lang_statement_list_type lang_output_section_statement;
 lang_statement_list_type *stat_ptr = &statement_list;
+/* Header for list of statements corresponding to files used in the final
+   executable.  This can be either object file specified on the command-line
+   or library member resolving an undefined reference.  Next pointer is in next
+   field of a lang_input_statement_type (reached via input_statement field in a
+   lang_statement_union).  */
 lang_statement_list_type file_chain = { NULL, NULL };
+/* Header for list of statements corresponding to files specified on the
+   command-line for linking.  It thus contains real object files and archive
+   but not archive members.  Next pointer is in next_real_file field of a
+   lang_input_statement_type statement (reached via input_statement field in a
+   lang_statement_union).  */
 lang_statement_list_type input_file_chain;
 struct bfd_sym_chain entry_symbol = { NULL, NULL };
 const char *entry_section = ".text";
@@ -203,7 +222,7 @@ unique_section_p (const asection *sec,
   struct unique_sections *unam;
   const char *secnam;
 
-  if (link_info.relocatable
+  if (!link_info.resolve_section_groups
       && sec->owner != NULL
       && bfd_is_group_section (sec->owner, sec))
     return !(os != NULL
@@ -219,23 +238,16 @@ unique_section_p (const asection *sec,
 
 /* Generic traversal routines for finding matching sections.  */
 
-/* Try processing a section against a wildcard.  This just calls
-   the callback unless the filename exclusion list is present
-   and excludes the file.  It's hardly ever present so this
-   function is very fast.  */
+/* Return true if FILE matches a pattern in EXCLUDE_LIST, otherwise return
+   false.  */
 
-static void
-walk_wild_consider_section (lang_wild_statement_type *ptr,
-                           lang_input_statement_type *file,
-                           asection *s,
-                           struct wildcard_list *sec,
-                           callback_t callback,
-                           void *data)
+static bfd_boolean
+walk_wild_file_in_exclude_list (struct name_list *exclude_list,
+                               lang_input_statement_type *file)
 {
   struct name_list *list_tmp;
 
-  /* Don't process sections from files which were excluded.  */
-  for (list_tmp = sec->spec.exclude_name_list;
+  for (list_tmp = exclude_list;
        list_tmp;
        list_tmp = list_tmp->next)
     {
@@ -244,11 +256,11 @@ walk_wild_consider_section (lang_wild_statement_type *ptr,
       if (p != NULL)
        {
          if (input_statement_is_archive_path (list_tmp->name, p, file))
-           return;
+           return TRUE;
        }
 
       else if (name_match (list_tmp->name, file->filename) == 0)
-       return;
+       return TRUE;
 
       /* FIXME: Perhaps remove the following at some stage?  Matching
         unadorned archives like this was never documented and has
@@ -257,9 +269,29 @@ walk_wild_consider_section (lang_wild_statement_type *ptr,
               && file->the_bfd->my_archive != NULL
               && name_match (list_tmp->name,
                              file->the_bfd->my_archive->filename) == 0)
-       return;
+       return TRUE;
     }
 
+  return FALSE;
+}
+
+/* Try processing a section against a wildcard.  This just calls
+   the callback unless the filename exclusion list is present
+   and excludes the file.  It's hardly ever present so this
+   function is very fast.  */
+
+static void
+walk_wild_consider_section (lang_wild_statement_type *ptr,
+                           lang_input_statement_type *file,
+                           asection *s,
+                           struct wildcard_list *sec,
+                           callback_t callback,
+                           void *data)
+{
+  /* Don't process sections from files which were excluded.  */
+  if (walk_wild_file_in_exclude_list (sec->spec.exclude_name_list, file))
+    return;
+
   (*callback) (ptr, sec, s, ptr->section_flag_list, file, data);
 }
 
@@ -856,8 +888,11 @@ walk_wild_file (lang_wild_statement_type *s,
                callback_t callback,
                void *data)
 {
+  if (walk_wild_file_in_exclude_list (s->exclude_name_list, f))
+    return;
+
   if (f->the_bfd == NULL
-      || ! bfd_check_format (f->the_bfd, bfd_archive))
+      || !bfd_check_format (f->the_bfd, bfd_archive))
     walk_wild_section (s, f, callback, data);
   else
     {
@@ -1076,12 +1111,12 @@ new_afile (const char *name,
       break;
     case lang_input_file_is_l_enum:
       if (name[0] == ':' && name[1] != '\0')
-        {
-          p->filename = name + 1;
-          p->flags.full_name_provided = TRUE;
-        }
+       {
+         p->filename = name + 1;
+         p->flags.full_name_provided = TRUE;
+       }
       else
-        p->filename = name;
+       p->filename = name;
       p->local_sym_name = concat ("-l", name, (const char *) NULL);
       p->flags.maybe_archive = TRUE;
       p->flags.real = TRUE;
@@ -1118,6 +1153,29 @@ lang_add_input_file (const char *name,
                     lang_input_file_enum_type file_type,
                     const char *target)
 {
+  if (name != NULL
+      && (*name == '=' || CONST_STRNEQ (name, "$SYSROOT")))
+    {
+      lang_input_statement_type *ret;
+      char *sysrooted_name
+       = concat (ld_sysroot,
+                 name + (*name == '=' ? 1 : strlen ("$SYSROOT")),
+                 (const char *) NULL);
+
+      /* We've now forcibly prepended the sysroot, making the input
+        file independent of the context.  Therefore, temporarily
+        force a non-sysrooted context for this statement, so it won't
+        get the sysroot prepended again when opened.  (N.B. if it's a
+        script, any child nodes with input files starting with "/"
+        will be handled as "sysrooted" as they'll be found to be
+        within the sysroot subdirectory.)  */
+      unsigned int outer_sysrooted = input_flags.sysrooted;
+      input_flags.sysrooted = 0;
+      ret = new_afile (sysrooted_name, file_type, target, TRUE);
+      input_flags.sysrooted = outer_sysrooted;
+      return ret;
+    }
+
   return new_afile (name, file_type, target, TRUE);
 }
 
@@ -1157,8 +1215,8 @@ output_section_statement_newfunc (struct bfd_hash_entry *entry,
   ret = (struct out_section_hash_entry *) entry;
   memset (&ret->s, 0, sizeof (ret->s));
   ret->s.header.type = lang_output_section_statement_enum;
-  ret->s.output_section_statement.subsection_alignment = -1;
-  ret->s.output_section_statement.section_alignment = -1;
+  ret->s.output_section_statement.subsection_alignment = NULL;
+  ret->s.output_section_statement.section_alignment = NULL;
   ret->s.output_section_statement.block_value = 1;
   lang_list_init (&ret->s.output_section_statement.children);
   lang_statement_append (stat_ptr, &ret->s, &ret->s.header.next);
@@ -1189,7 +1247,7 @@ output_section_statement_table_init (void)
                              output_section_statement_newfunc,
                              sizeof (struct out_section_hash_entry),
                              61))
-    einfo (_("%P%F: can not create hash table: %E\n"));
+    einfo (_("%F%P: can not create hash table: %E\n"));
 }
 
 static void
@@ -1221,14 +1279,6 @@ lang_init (void)
 
   abs_output_section->bfd_section = bfd_abs_section_ptr;
 
-  /* The value "13" is ad-hoc, somewhat related to the expected number of
-     assignments in a linker script.  */
-  if (!bfd_hash_table_init_n (&lang_definedness_table,
-                             lang_definedness_newfunc,
-                             sizeof (struct lang_definedness_hash_entry),
-                             13))
-    einfo (_("%P%F: can not create hash table: %E\n"));
-
   asneeded_list_head = NULL;
   asneeded_list_tail = &asneeded_list_head;
 }
@@ -1236,7 +1286,6 @@ lang_init (void)
 void
 lang_finish (void)
 {
-  bfd_hash_table_free (&lang_definedness_table);
   output_section_statement_table_free ();
 }
 
@@ -1282,13 +1331,13 @@ lang_memory_region_lookup (const char *const name, bfd_boolean create)
       if (strcmp (n->name, name) == 0)
        {
          if (create)
-           einfo (_("%P:%S: warning: redeclaration of memory region `%s'\n"),
+           einfo (_("%P:%pS: warning: redeclaration of memory region `%s'\n"),
                   NULL, name);
          return r;
        }
 
   if (!create && strcmp (name, DEFAULT_MEMORY_REGION))
-    einfo (_("%P:%S: warning: memory region `%s' not declared\n"),
+    einfo (_("%P:%pS: warning: memory region `%s' not declared\n"),
           NULL, name);
 
   new_region = (lang_memory_region_type *)
@@ -1297,7 +1346,9 @@ lang_memory_region_lookup (const char *const name, bfd_boolean create)
   new_region->name_list.name = xstrdup (name);
   new_region->name_list.next = NULL;
   new_region->next = NULL;
+  new_region->origin_exp = NULL;
   new_region->origin = 0;
+  new_region->length_exp = NULL;
   new_region->length = ~(bfd_size_type) 0;
   new_region->current = 0;
   new_region->last_os = NULL;
@@ -1312,18 +1363,18 @@ lang_memory_region_lookup (const char *const name, bfd_boolean create)
 }
 
 void
-lang_memory_region_alias (const char * alias, const char * region_name)
+lang_memory_region_alias (const char *alias, const char *region_name)
 {
-  lang_memory_region_name * n;
-  lang_memory_region_type * r;
-  lang_memory_region_type * region;
+  lang_memory_region_name *n;
+  lang_memory_region_type *r;
+  lang_memory_region_type *region;
 
   /* The default region must be unique.  This ensures that it is not necessary
      to iterate through the name list if someone wants the check if a region is
      the default memory region.  */
   if (strcmp (region_name, DEFAULT_MEMORY_REGION) == 0
       || strcmp (alias, DEFAULT_MEMORY_REGION) == 0)
-    einfo (_("%F%P:%S: error: alias for default memory region\n"), NULL);
+    einfo (_("%F%P:%pS: error: alias for default memory region\n"), NULL);
 
   /* Look for the target region and check if the alias is not already
      in use.  */
@@ -1334,14 +1385,14 @@ lang_memory_region_alias (const char * alias, const char * region_name)
        if (region == NULL && strcmp (n->name, region_name) == 0)
          region = r;
        if (strcmp (n->name, alias) == 0)
-         einfo (_("%F%P:%S: error: redefinition of memory region "
+         einfo (_("%F%P:%pS: error: redefinition of memory region "
                   "alias `%s'\n"),
                 NULL, alias);
       }
 
   /* Check if the target region exists.  */
   if (region == NULL)
-    einfo (_("%F%P:%S: error: memory region `%s' "
+    einfo (_("%F%P:%pS: error: memory region `%s' "
             "for alias `%s' does not exist\n"),
           NULL, region_name, alias);
 
@@ -1353,7 +1404,7 @@ lang_memory_region_alias (const char * alias, const char * region_name)
 }
 
 static lang_memory_region_type *
-lang_memory_default (asection * section)
+lang_memory_default (asection *section)
 {
   lang_memory_region_type *p;
 
@@ -1400,7 +1451,7 @@ lang_output_section_statement_lookup (const char *name,
   if (entry == NULL)
     {
       if (create)
-       einfo (_("%P%F: failed creating section `%s': %E\n"), name);
+       einfo (_("%F%P: failed creating section `%s': %E\n"), name);
       return NULL;
     }
 
@@ -1439,7 +1490,7 @@ lang_output_section_statement_lookup (const char *name,
                                             name));
       if (entry == NULL)
        {
-         einfo (_("%P%F: failed creating section `%s': %E\n"), name);
+         einfo (_("%F%P: failed creating section `%s': %E\n"), name);
          return NULL;
        }
       entry->root = last_ent->root;
@@ -1488,11 +1539,12 @@ next_matching_output_section_statement (lang_output_section_statement_type *os,
 
 lang_output_section_statement_type *
 lang_output_section_find_by_flags (const asection *sec,
+                                  flagword sec_flags,
                                   lang_output_section_statement_type **exact,
                                   lang_match_sec_type_func match_type)
 {
   lang_output_section_statement_type *first, *look, *found;
-  flagword look_flags, sec_flags, differ;
+  flagword look_flags, differ;
 
   /* We know the first statement on this list is *ABS*.  May as well
      skip it.  */
@@ -1500,7 +1552,6 @@ lang_output_section_find_by_flags (const asection *sec,
   first = first->next;
 
   /* First try for an exact match.  */
-  sec_flags = sec->flags;
   found = NULL;
   for (look = first; look; look = look->next)
     {
@@ -1684,7 +1735,7 @@ lang_output_section_find_by_flags (const asection *sec,
   if (found || !match_type)
     return found;
 
-  return lang_output_section_find_by_flags (sec, NULL, NULL);
+  return lang_output_section_find_by_flags (sec, sec_flags, NULL, NULL);
 }
 
 /* Find the last output section before given output statement.
@@ -1742,11 +1793,13 @@ insert_os_after (lang_output_section_statement_type *after)
              ass = &(*where)->assignment_statement;
              if (ass->exp->type.node_class != etree_assert
                  && ass->exp->assign.dst[0] == '.'
-                 && ass->exp->assign.dst[1] == 0
-                 && !ignore_first)
-               assign = where;
+                 && ass->exp->assign.dst[1] == 0)
+               {
+                 if (!ignore_first)
+                   assign = where;
+                 ignore_first = FALSE;
+               }
            }
-         ignore_first = FALSE;
          continue;
        case lang_wild_statement_enum:
        case lang_input_section_enum:
@@ -1757,6 +1810,7 @@ insert_os_after (lang_output_section_statement_type *after)
        case lang_padding_statement_enum:
        case lang_constructors_statement_enum:
          assign = NULL;
+         ignore_first = FALSE;
          continue;
        case lang_output_section_statement_enum:
          if (assign != NULL)
@@ -1793,7 +1847,6 @@ lang_insert_orphan (asection *s,
                    lang_statement_list_type *add_child)
 {
   lang_statement_list_type add;
-  const char *ps;
   lang_output_section_statement_type *os;
   lang_output_section_statement_type **os_tail;
 
@@ -1806,7 +1859,8 @@ lang_insert_orphan (asection *s,
       push_stat_ptr (&add);
     }
 
-  if (link_info.relocatable || (s->flags & (SEC_LOAD | SEC_ALLOC)) == 0)
+  if (bfd_link_relocatable (&link_info)
+      || (s->flags & (SEC_LOAD | SEC_ALLOC)) == 0)
     address = exp_intop (0);
 
   os_tail = ((lang_output_section_statement_type **)
@@ -1814,27 +1868,6 @@ lang_insert_orphan (asection *s,
   os = lang_enter_output_section_statement (secname, address, normal_section,
                                            NULL, NULL, NULL, constraint, 0);
 
-  ps = NULL;
-  if (config.build_constructors && *os_tail == os)
-    {
-      /* If the name of the section is representable in C, then create
-        symbols to mark the start and the end of the section.  */
-      for (ps = secname; *ps != '\0'; ps++)
-       if (! ISALNUM ((unsigned char) *ps) && *ps != '_')
-         break;
-      if (*ps == '\0')
-       {
-         char *symname;
-
-         symname = (char *) xmalloc (ps - secname + sizeof "__start_" + 1);
-         symname[0] = bfd_get_symbol_leading_char (link_info.output_bfd);
-         sprintf (symname + (symname[0] != 0), "__start_%s", secname);
-         lang_add_assignment (exp_provide (symname,
-                                           exp_nameop (NAME, "."),
-                                           FALSE));
-       }
-    }
-
   if (add_child == NULL)
     add_child = &os->children;
   lang_add_section (add_child, s, NULL, os);
@@ -1854,18 +1887,6 @@ lang_insert_orphan (asection *s,
     lang_leave_output_section_statement (NULL, DEFAULT_MEMORY_REGION, NULL,
                                         NULL);
 
-  if (ps != NULL && *ps == '\0')
-    {
-      char *symname;
-
-      symname = (char *) xmalloc (ps - secname + sizeof "__stop_" + 1);
-      symname[0] = bfd_get_symbol_leading_char (link_info.output_bfd);
-      sprintf (symname + (symname[0] != 0), "__stop_%s", secname);
-      lang_add_assignment (exp_provide (symname,
-                                       exp_nameop (NAME, "."),
-                                       FALSE));
-    }
-
   /* Restore the global list pointer.  */
   if (after != NULL)
     pop_stat_ptr ();
@@ -1873,6 +1894,8 @@ lang_insert_orphan (asection *s,
   if (after != NULL && os->bfd_section != NULL)
     {
       asection *snew, *as;
+      bfd_boolean place_after = place->stmt == NULL;
+      bfd_boolean insert_after = TRUE;
 
       snew = os->bfd_section;
 
@@ -1910,6 +1933,181 @@ lang_insert_orphan (asection *s,
          /* Now tack it back on in the right place.  */
          bfd_section_list_append (link_info.output_bfd, snew);
        }
+      else if ((bfd_get_flavour (link_info.output_bfd)
+               == bfd_target_elf_flavour)
+              && (bfd_get_flavour (s->owner)
+                  == bfd_target_elf_flavour)
+              && ((elf_section_type (s) == SHT_NOTE
+                   && (s->flags & SEC_LOAD) != 0)
+                  || (elf_section_type (as) == SHT_NOTE
+                      && (as->flags & SEC_LOAD) != 0)))
+       {
+         /* Make sure that output note sections are grouped and sorted
+            by alignments when inserting a note section or insert a
+            section after a note section,  */
+         asection *sec;
+         /* A specific section after which the output note section
+            should be placed.  */
+         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;
+
+         static asection *first_orphan_note = NULL;
+
+         /* Group and sort output note section by alignments in
+            ascending order.  */
+         after_sec = NULL;
+         if (elf_section_type (s) == SHT_NOTE
+             && (s->flags & SEC_LOAD) != 0)
+           {
+             /* Search from the beginning for the last output note
+                section with equal or larger alignments.  NB: Don't
+                place orphan note section after non-note sections.  */
+
+             first_orphan_note = NULL;
+             for (sec = link_info.output_bfd->sections;
+                  (sec != NULL
+                   && !bfd_is_abs_section (sec));
+                  sec = sec->next)
+               if (sec != snew
+                   && elf_section_type (sec) == SHT_NOTE
+                   && (sec->flags & SEC_LOAD) != 0)
+                 {
+                   if (!first_orphan_note)
+                     first_orphan_note = sec;
+                   if (sec->alignment_power >= s->alignment_power)
+                     after_sec = sec;
+                 }
+               else if (first_orphan_note)
+                 {
+                   /* Stop if there is non-note section after the first
+                      orphan note section.  */
+                   break;
+                 }
+
+             /* If this will be the first orphan note section, it can
+                be placed at the default location.  */
+             after_sec_note = first_orphan_note != NULL;
+             if (after_sec == NULL && after_sec_note)
+               {
+                 /* If all output note sections have smaller
+                    alignments, place the section before all
+                    output orphan note sections.  */
+                 after_sec = first_orphan_note;
+                 insert_after = FALSE;
+               }
+           }
+         else if (first_orphan_note)
+           {
+             /* Don't place non-note sections in the middle of orphan
+                note sections.  */
+             after_sec_note = TRUE;
+             after_sec = as;
+             for (sec = as->next;
+                  (sec != NULL
+                   && !bfd_is_abs_section (sec));
+                  sec = sec->next)
+               if (elf_section_type (sec) == SHT_NOTE
+                   && (sec->flags & SEC_LOAD) != 0)
+                 after_sec = sec;
+           }
+
+         if (after_sec_note)
+           {
+             if (after_sec)
+               {
+                 /* Search forward to insert OS after AFTER_SEC output
+                    statement.  */
+                 lang_output_section_statement_type *stmt, *next;
+                 bfd_boolean found = FALSE;
+                 for (stmt = after; stmt != NULL; stmt = next)
+                   {
+                     next = stmt->next;
+                     if (insert_after)
+                       {
+                         if (stmt->bfd_section == after_sec)
+                           {
+                             place_after = TRUE;
+                             found = TRUE;
+                             after = stmt;
+                             break;
+                           }
+                       }
+                     else
+                       {
+                         /* If INSERT_AFTER is FALSE, place OS before
+                            AFTER_SEC output statement.  */
+                         if (next && next->bfd_section == after_sec)
+                           {
+                             place_after = TRUE;
+                             found = TRUE;
+                             after = stmt;
+                             break;
+                           }
+                       }
+                   }
+
+                 /* Search backward to insert OS after AFTER_SEC output
+                    statement.  */
+                 if (!found)
+                   for (stmt = after; stmt != NULL; stmt = stmt->prev)
+                     {
+                       if (insert_after)
+                         {
+                           if (stmt->bfd_section == after_sec)
+                             {
+                               place_after = TRUE;
+                               after = stmt;
+                               break;
+                             }
+                         }
+                       else
+                         {
+                           /* If INSERT_AFTER is FALSE, place OS before
+                              AFTER_SEC output statement.  */
+                           if (stmt->next->bfd_section == after_sec)
+                             {
+                               place_after = TRUE;
+                               after = stmt;
+                               break;
+                             }
+                         }
+                     }
+               }
+
+             if (after_sec == NULL
+                 || (insert_after && after_sec->next != snew)
+                 || (!insert_after && after_sec->prev != snew))
+               {
+                 /* Unlink the section.  */
+                 bfd_section_list_remove (link_info.output_bfd, snew);
+
+                 /* Place SNEW after AFTER_SEC.  If AFTER_SEC is NULL,
+                    prepend SNEW.  */
+                 if (after_sec)
+                   {
+                     if (insert_after)
+                       bfd_section_list_insert_after (link_info.output_bfd,
+                                                      after_sec, snew);
+                     else
+                       bfd_section_list_insert_before (link_info.output_bfd,
+                                                      after_sec, snew);
+                   }
+                 else
+                   bfd_section_list_prepend (link_info.output_bfd, snew);
+               }
+           }
+         else if (as != snew && as->prev != snew)
+           {
+             /* Unlink the section.  */
+             bfd_section_list_remove (link_info.output_bfd, snew);
+
+             /* Now tack it back on in the right place.  */
+             bfd_section_list_insert_before (link_info.output_bfd,
+                                             as, snew);
+           }
+       }
       else if (as != snew && as->prev != snew)
        {
          /* Unlink the section.  */
@@ -1936,7 +2134,8 @@ lang_insert_orphan (asection *s,
        {
          lang_output_section_statement_type *newly_added_os;
 
-         if (place->stmt == NULL)
+         /* Place OS after AFTER if AFTER_NOTE is TRUE.  */
+         if (place_after)
            {
              lang_statement_union_type **where = insert_os_after (after);
 
@@ -1989,14 +2188,11 @@ static void
 lang_print_asneeded (void)
 {
   struct asneeded_minfo *m;
-  char buf[100];
 
   if (asneeded_list_head == NULL)
     return;
 
-  sprintf (buf, _("\nAs-needed library included "
-                 "to satisfy reference by file (symbol)\n\n"));
-  minfo ("%s", buf);
+  minfo (_("\nAs-needed library included to satisfy reference by file (symbol)\n\n"));
 
   for (m = asneeded_list_head; m != NULL; m = m->next)
     {
@@ -2017,8 +2213,8 @@ lang_print_asneeded (void)
        }
 
       if (m->ref != NULL)
-       minfo ("%B ", m->ref);
-      minfo ("(%T)\n", m->name);
+       minfo ("%pB ", m->ref);
+      minfo ("(%pT)\n", m->name);
     }
 }
 
@@ -2055,19 +2251,20 @@ lang_map (void)
          || file->flags.just_syms)
        continue;
 
-      for (s = file->the_bfd->sections; s != NULL; s = s->next)
-       if ((s->output_section == NULL
-            || s->output_section->owner != link_info.output_bfd)
-           && (s->flags & (SEC_LINKER_CREATED | SEC_KEEP)) == 0)
-         {
-           if (! dis_header_printed)
-             {
-               fprintf (config.map_file, _("\nDiscarded input sections\n\n"));
-               dis_header_printed = TRUE;
-             }
+      if (config.print_map_discarded)
+       for (s = file->the_bfd->sections; s != NULL; s = s->next)
+         if ((s->output_section == NULL
+              || s->output_section->owner != link_info.output_bfd)
+             && (s->flags & (SEC_LINKER_CREATED | SEC_KEEP)) == 0)
+           {
+             if (! dis_header_printed)
+               {
+                 fprintf (config.map_file, _("\nDiscarded input sections\n\n"));
+                 dis_header_printed = TRUE;
+               }
 
-           print_input_section (s, TRUE);
-         }
+             print_input_section (s, TRUE);
+           }
     }
 
   minfo (_("\nMemory Configuration\n\n"));
@@ -2114,15 +2311,17 @@ lang_map (void)
 
   fprintf (config.map_file, _("\nLinker script and memory map\n\n"));
 
-  if (! link_info.reduce_memory_overheads)
+  if (!link_info.reduce_memory_overheads)
     {
       obstack_begin (&map_obstack, 1000);
       bfd_link_hash_traverse (link_info.hash, sort_def_symbol, 0);
     }
+  expld.phase = lang_fixed_phase_enum;
   lang_statement_iteration++;
   print_statements ();
 
-  ldemul_extra_map_file_text (link_info.output_bfd, &link_info, config.map_file);
+  ldemul_extra_map_file_text (link_info.output_bfd, &link_info,
+                             config.map_file);
 }
 
 static bfd_boolean
@@ -2164,7 +2363,7 @@ static void
 init_os (lang_output_section_statement_type *s, flagword flags)
 {
   if (strcmp (s->name, DISCARD_SECTION_NAME) == 0)
-    einfo (_("%P%F: Illegal use of `%s' section\n"), DISCARD_SECTION_NAME);
+    einfo (_("%F%P: illegal use of `%s' section\n"), DISCARD_SECTION_NAME);
 
   if (s->constraint != SPECIAL)
     s->bfd_section = bfd_get_section_by_name (link_info.output_bfd, s->name);
@@ -2173,7 +2372,8 @@ init_os (lang_output_section_statement_type *s, flagword flags)
                                                         s->name, flags);
   if (s->bfd_section == NULL)
     {
-      einfo (_("%P%F: output format %s cannot represent section called %s\n"),
+      einfo (_("%F%P: output format %s cannot represent section"
+              " called %s: %E\n"),
             link_info.output_bfd->xvec->name, s->name);
     }
   s->bfd_section->output_section = s->bfd_section;
@@ -2192,8 +2392,9 @@ init_os (lang_output_section_statement_type *s, flagword flags)
     exp_init_os (s->load_base);
 
   /* If supplied an alignment, set it.  */
-  if (s->section_alignment != -1)
-    s->bfd_section->alignment_power = s->section_alignment;
+  if (s->section_alignment != NULL)
+    s->bfd_section->alignment_power = exp_get_power (s->section_alignment,
+                                                    "section alignment");
 }
 
 /* Make sure that all output sections mentioned in an expression are
@@ -2206,6 +2407,7 @@ exp_init_os (etree_type *exp)
     {
     case etree_assign:
     case etree_provide:
+    case etree_provided:
       exp_init_os (exp->assign.src);
       break;
 
@@ -2262,10 +2464,44 @@ section_already_linked (bfd *abfd, asection *sec, void *data)
       return;
     }
 
+  /* Deal with SHF_EXCLUDE ELF sections.  */
+  if (!bfd_link_relocatable (&link_info)
+      && (abfd->flags & BFD_PLUGIN) == 0
+      && (sec->flags & (SEC_GROUP | SEC_KEEP | SEC_EXCLUDE)) == SEC_EXCLUDE)
+    sec->output_section = bfd_abs_section_ptr;
+
   if (!(abfd->flags & DYNAMIC))
     bfd_section_already_linked (abfd, sec, &link_info);
 }
 \f
+
+/* Returns true if SECTION is one we know will be discarded based on its
+   section flags, otherwise returns false.  */
+
+static bfd_boolean
+lang_discard_section_p (asection *section)
+{
+  bfd_boolean discard;
+  flagword flags = section->flags;
+
+  /* Discard sections marked with SEC_EXCLUDE.  */
+  discard = (flags & SEC_EXCLUDE) != 0;
+
+  /* Discard the group descriptor sections when we're finally placing the
+     sections from within the group.  */
+  if ((flags & SEC_GROUP) != 0
+      && link_info.resolve_section_groups)
+    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 = TRUE;
+
+  return discard;
+}
+
 /* The wild routines.
 
    These expand statements like *(.text) and foo.o to a list of
@@ -2287,20 +2523,14 @@ lang_add_section (lang_statement_list_type *ptr,
   lang_input_section_type *new_section;
   bfd *abfd = link_info.output_bfd;
 
-  /* Discard sections marked with SEC_EXCLUDE.  */
-  discard = (flags & SEC_EXCLUDE) != 0;
+  /* Is this section one we know should be discarded?  */
+  discard = lang_discard_section_p (section);
 
   /* Discard input sections which are assigned to a section named
      DISCARD_SECTION_NAME.  */
   if (strcmp (output->name, DISCARD_SECTION_NAME) == 0)
     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 = TRUE;
-
   if (discard)
     {
       if (section->output_section == NULL)
@@ -2335,8 +2565,14 @@ lang_add_section (lang_statement_list_type *ptr,
      already been processed.  One reason to do this is that on pe
      format targets, .text$foo sections go into .text and it's odd
      to see .text with SEC_LINK_ONCE set.  */
-
-  if (!link_info.relocatable)
+  if ((flags & (SEC_LINK_ONCE | SEC_GROUP)) == (SEC_LINK_ONCE | SEC_GROUP))
+    {
+      if (link_info.resolve_section_groups)
+       flags &= ~(SEC_LINK_ONCE | SEC_LINK_DUPLICATES | SEC_RELOC);
+      else
+       flags &= ~(SEC_LINK_DUPLICATES | SEC_RELOC);
+    }
+  else if (!bfd_link_relocatable (&link_info))
     flags &= ~(SEC_LINK_ONCE | SEC_LINK_DUPLICATES | SEC_RELOC);
 
   switch (output->sectype)
@@ -2411,8 +2647,7 @@ lang_add_section (lang_statement_list_type *ptr,
 
   section->output_section = output->bfd_section;
 
-  if (!link_info.relocatable
-      && !stripped_excluded_sections)
+  if (!map_head_is_link_order)
     {
       asection *s = output->bfd_section->map_tail.s;
       output->bfd_section->map_tail.s = section;
@@ -2469,9 +2704,9 @@ wild_sort (lang_wild_statement_type *wild,
             archive.  */
 
          if (file->the_bfd != NULL
-             && bfd_my_archive (file->the_bfd) != NULL)
+             && file->the_bfd->my_archive != NULL)
            {
-             fn = bfd_get_filename (bfd_my_archive (file->the_bfd));
+             fn = bfd_get_filename (file->the_bfd->my_archive);
              fa = TRUE;
            }
          else
@@ -2480,9 +2715,9 @@ wild_sort (lang_wild_statement_type *wild,
              fa = FALSE;
            }
 
-         if (bfd_my_archive (ls->section->owner) != NULL)
+         if (ls->section->owner->my_archive != NULL)
            {
-             ln = bfd_get_filename (bfd_my_archive (ls->section->owner));
+             ln = bfd_get_filename (ls->section->owner->my_archive);
              la = TRUE;
            }
          else
@@ -2634,7 +2869,7 @@ lookup_name (const char *name)
   if (search->flags.loaded || !search->flags.real)
     return search;
 
-  if (! load_symbols (search, NULL))
+  if (!load_symbols (search, NULL))
     return NULL;
 
   return search;
@@ -2718,8 +2953,11 @@ load_symbols (lang_input_statement_type *entry,
   if (entry->flags.missing_file)
     return TRUE;
 
-  if (! bfd_check_format (entry->the_bfd, bfd_archive)
-      && ! bfd_check_format_matches (entry->the_bfd, bfd_object, &matching))
+  if (trace_files || verbose)
+    info_msg ("%pI\n", entry);
+
+  if (!bfd_check_format (entry->the_bfd, bfd_archive)
+      && !bfd_check_format_matches (entry->the_bfd, bfd_object, &matching))
     {
       bfd_error_type err;
       struct lang_input_statement_flags save_flags;
@@ -2735,15 +2973,15 @@ load_symbols (lang_input_statement_type *entry,
        {
          char **p;
 
-         einfo (_("%B: file not recognized: %E\n"), entry->the_bfd);
-         einfo (_("%B: matching formats:"), entry->the_bfd);
+         einfo (_("%P: %pB: file not recognized: %E;"
+                  " matching formats:"), entry->the_bfd);
          for (p = matching; *p != NULL; p++)
            einfo (" %s", *p);
          einfo ("%F\n");
        }
       else if (err != bfd_error_file_not_recognized
               || place == NULL)
-       einfo (_("%F%B: file not recognized: %E\n"), entry->the_bfd);
+       einfo (_("%F%P: %pB: file not recognized: %E\n"), entry->the_bfd);
 
       bfd_close (entry->the_bfd);
       entry->the_bfd = NULL;
@@ -2793,13 +3031,12 @@ load_symbols (lang_input_statement_type *entry,
     case bfd_object:
       if (!entry->flags.reload)
        ldlang_add_file (entry);
-      if (trace_files || verbose)
-       info_msg ("%I\n", entry);
       break;
 
     case bfd_archive:
       check_excluded_libs (entry->the_bfd);
 
+      entry->the_bfd->usrdata = entry;
       if (entry->flags.whole_archive)
        {
          bfd *member = NULL;
@@ -2813,9 +3050,9 @@ load_symbols (lang_input_statement_type *entry,
              if (member == NULL)
                break;
 
-             if (! bfd_check_format (member, bfd_object))
+             if (!bfd_check_format (member, bfd_object))
                {
-                 einfo (_("%F%B: member %B in archive is not an object\n"),
+                 einfo (_("%F%P: %pB: member %pB in archive is not an object\n"),
                         entry->the_bfd, member);
                  loaded = FALSE;
                }
@@ -2830,7 +3067,7 @@ load_symbols (lang_input_statement_type *entry,
                 substitute BFD for us.  */
              if (!bfd_link_add_symbols (subsbfd, &link_info))
                {
-                 einfo (_("%F%B: error adding symbols: %E\n"), member);
+                 einfo (_("%F%P: %pB: error adding symbols: %E\n"), member);
                  loaded = FALSE;
                }
            }
@@ -2844,7 +3081,7 @@ load_symbols (lang_input_statement_type *entry,
   if (bfd_link_add_symbols (entry->the_bfd, &link_info))
     entry->flags.loaded = TRUE;
   else
-    einfo (_("%F%B: error adding symbols: %E\n"), entry->the_bfd);
+    einfo (_("%F%P: %pB: error adding symbols: %E\n"), entry->the_bfd);
 
   return entry->flags.loaded;
 }
@@ -3082,15 +3319,15 @@ open_output (const char *name)
      line?  */
   if (command_line.endian != ENDIAN_UNSET)
     {
-      const bfd_target *target;
-      enum bfd_endian desired_endian;
-
       /* Get the chosen target.  */
-      target = bfd_search_for_target (get_target, (void *) output_target);
+      const bfd_target *target
+       = bfd_iterate_over_targets (get_target, (void *) output_target);
 
       /* If the target is not supported, we cannot do anything.  */
       if (target != NULL)
        {
+         enum bfd_endian desired_endian;
+
          if (command_line.endian == ENDIAN_BIG)
            desired_endian = BFD_ENDIAN_BIG;
          else
@@ -3112,8 +3349,8 @@ open_output (const char *name)
                  /* Try to find a target as similar as possible to
                     the default target, but which has the desired
                     endian characteristic.  */
-                 bfd_search_for_target (closest_target_match,
-                                        (void *) target);
+                 bfd_iterate_over_targets (closest_target_match,
+                                           (void *) target);
 
                  /* Oh dear - we could not find any targets that
                     satisfy our requirements.  */
@@ -3132,23 +3369,23 @@ open_output (const char *name)
   if (link_info.output_bfd == NULL)
     {
       if (bfd_get_error () == bfd_error_invalid_target)
-       einfo (_("%P%F: target %s not found\n"), output_target);
+       einfo (_("%F%P: target %s not found\n"), output_target);
 
-      einfo (_("%P%F: 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;
 
-  if (! bfd_set_format (link_info.output_bfd, bfd_object))
-    einfo (_("%P%F:%s: can not make object file: %E\n"), name);
-  if (! bfd_set_arch_mach (link_info.output_bfd,
+  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_arch_mach (link_info.output_bfd,
                           ldfile_output_architecture,
                           ldfile_output_machine))
-    einfo (_("%P%F:%s: can not set architecture: %E\n"), name);
+    einfo (_("%F%P: %s: can not set architecture: %E\n"), name);
 
   link_info.hash = bfd_link_hash_table_create (link_info.output_bfd);
   if (link_info.hash == NULL)
-    einfo (_("%P%F: can not create hash table: %E\n"));
+    einfo (_("%F%P: can not create hash table: %E\n"));
 
   bfd_set_gp_size (link_info.output_bfd, g_switch_value);
 }
@@ -3162,7 +3399,8 @@ ldlang_open_output (lang_statement_union_type *statement)
       ASSERT (link_info.output_bfd == NULL);
       open_output (statement->output_statement.name);
       ldemul_set_output_arch ();
-      if (config.magic_demand_paged && !link_info.relocatable)
+      if (config.magic_demand_paged
+         && !bfd_link_relocatable (&link_info))
        link_info.output_bfd->flags |= D_PAGED;
       else
        link_info.output_bfd->flags &= ~D_PAGED;
@@ -3184,15 +3422,6 @@ ldlang_open_output (lang_statement_union_type *statement)
     }
 }
 
-/* Convert between addresses in bytes and sizes in octets.
-   For currently supported targets, octets_per_byte is always a power
-   of two, so we can use shifts.  */
-#define TO_ADDR(X) ((X) >> opb_shift)
-#define TO_SIZE(X) ((X) << opb_shift)
-
-/* Support the above.  */
-static unsigned int opb_shift = 0;
-
 static void
 init_opb (void)
 {
@@ -3298,7 +3527,7 @@ open_input_bfds (lang_statement_union_type *s, enum open_bfd_mode mode)
              os_tail = lang_output_section_statement.tail;
              lang_list_init (&add);
 
-             if (! load_symbols (&s->input_statement, &add))
+             if (!load_symbols (&s->input_statement, &add))
                config.make_executable = FALSE;
 
              if (add.head != NULL)
@@ -3332,8 +3561,7 @@ open_input_bfds (lang_statement_union_type *s, enum open_bfd_mode mode)
 #endif
          break;
        case lang_assignment_statement_enum:
-         if (s->assignment_statement.exp->assign.defsym)
-           /* This is from a --defsym on the command line.  */
+         if (s->assignment_statement.exp->type.node_class != etree_assert)
            exp_fold_tree_no_dot (s->assignment_statement.exp);
          break;
        default:
@@ -3346,65 +3574,6 @@ open_input_bfds (lang_statement_union_type *s, enum open_bfd_mode mode)
     einfo ("%F");
 }
 
-/* New-function for the definedness hash table.  */
-
-static struct bfd_hash_entry *
-lang_definedness_newfunc (struct bfd_hash_entry *entry,
-                         struct bfd_hash_table *table ATTRIBUTE_UNUSED,
-                         const char *name ATTRIBUTE_UNUSED)
-{
-  struct lang_definedness_hash_entry *ret
-    = (struct lang_definedness_hash_entry *) entry;
-
-  if (ret == NULL)
-    ret = (struct lang_definedness_hash_entry *)
-      bfd_hash_allocate (table, sizeof (struct lang_definedness_hash_entry));
-
-  if (ret == NULL)
-    einfo (_("%P%F: bfd_hash_allocate failed creating symbol %s\n"), name);
-
-  ret->by_object = 0;
-  ret->by_script = 0;
-  ret->iteration = 0;
-  return &ret->root;
-}
-
-/* Called during processing of linker script script expressions.
-   For symbols assigned in a linker script, return a struct describing
-   where the symbol is defined relative to the current expression,
-   otherwise return NULL.  */
-
-struct lang_definedness_hash_entry *
-lang_symbol_defined (const char *name)
-{
-  return ((struct lang_definedness_hash_entry *)
-         bfd_hash_lookup (&lang_definedness_table, name, FALSE, FALSE));
-}
-
-/* Update the definedness state of NAME.  */
-
-void
-lang_update_definedness (const char *name, struct bfd_link_hash_entry *h)
-{
-  struct lang_definedness_hash_entry *defentry
-    = (struct lang_definedness_hash_entry *)
-    bfd_hash_lookup (&lang_definedness_table, name, TRUE, FALSE);
-
-  if (defentry == NULL)
-    einfo (_("%P%F: bfd_hash_lookup failed creating symbol %s\n"), name);
-
-  /* If the symbol was already defined, and not by a script, then it
-     must be defined by an object file.  */
-  if (!defentry->by_script
-      && h->type != bfd_link_hash_undefined
-      && h->type != bfd_link_hash_common
-      && h->type != bfd_link_hash_new)
-    defentry->by_object = 1;
-
-  defentry->by_script = 1;
-  defentry->iteration = lang_statement_iteration;
-}
-
 /* Add the supplied name to the symbol table as an undefined reference.
    This is a two step process as the symbol table doesn't even exist at
    the time the ld command line is processed.  First we put the name
@@ -3440,11 +3609,14 @@ insert_undefined (const char *name)
 
   h = bfd_link_hash_lookup (link_info.hash, name, TRUE, FALSE, TRUE);
   if (h == NULL)
-    einfo (_("%P%F: bfd_link_hash_lookup failed: %E\n"));
+    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;
       bfd_link_add_undef (link_info.hash, h);
     }
 }
@@ -3462,6 +3634,55 @@ lang_place_undefineds (void)
     insert_undefined (ptr->name);
 }
 
+/* Structure used to build the list of symbols that the user has required
+   be defined.  */
+
+struct require_defined_symbol
+{
+  const char *name;
+  struct require_defined_symbol *next;
+};
+
+/* The list of symbols that the user has required be defined.  */
+
+static struct require_defined_symbol *require_defined_symbol_list;
+
+/* Add a new symbol NAME to the list of symbols that are required to be
+   defined.  */
+
+void
+ldlang_add_require_defined (const char *const name)
+{
+  struct require_defined_symbol *ptr;
+
+  ldlang_add_undef (name, TRUE);
+  ptr = (struct require_defined_symbol *) stat_alloc (sizeof (*ptr));
+  ptr->next = require_defined_symbol_list;
+  ptr->name = strdup (name);
+  require_defined_symbol_list = ptr;
+}
+
+/* Check that all symbols the user required to be defined, are defined,
+   raise an error if we find a symbol that is not defined.  */
+
+static void
+ldlang_check_require_defined_symbols (void)
+{
+  struct require_defined_symbol *ptr;
+
+  for (ptr = require_defined_symbol_list; ptr != NULL; ptr = ptr->next)
+    {
+      struct bfd_link_hash_entry *h;
+
+      h = bfd_link_hash_lookup (link_info.hash, ptr->name,
+                               FALSE, FALSE, TRUE);
+      if (h == NULL
+         || (h->type != bfd_link_hash_defined
+             && h->type != bfd_link_hash_defweak))
+       einfo(_("%X%P: required symbol `%s' not defined\n"), ptr->name);
+    }
+}
+
 /* Check for all readonly or some readwrite sections.  */
 
 static void
@@ -3476,19 +3697,19 @@ check_input_sections
        case lang_wild_statement_enum:
          walk_wild (&s->wild_statement, check_section_callback,
                     output_section_statement);
-         if (! output_section_statement->all_input_readonly)
+         if (!output_section_statement->all_input_readonly)
            return;
          break;
        case lang_constructors_statement_enum:
          check_input_sections (constructor_list.head,
                                output_section_statement);
-         if (! output_section_statement->all_input_readonly)
+         if (!output_section_statement->all_input_readonly)
            return;
          break;
        case lang_group_statement_enum:
          check_input_sections (s->group_statement.children.head,
                                output_section_statement);
-         if (! output_section_statement->all_input_readonly)
+         if (!output_section_statement->all_input_readonly)
            return;
          break;
        default:
@@ -3524,7 +3745,9 @@ update_wild_statements (lang_statement_union_type *s)
            case lang_wild_statement_enum:
              for (sec = s->wild_statement.section_list; sec != NULL;
                   sec = sec->next)
-               {
+               /* Don't sort .init/.fini sections.  */
+               if (strcmp (sec->spec.name, ".init") != 0
+                   && strcmp (sec->spec.name, ".fini") != 0)
                  switch (sec->spec.sorted)
                    {
                    case none:
@@ -3541,7 +3764,6 @@ update_wild_statements (lang_statement_union_type *s)
                    default:
                      break;
                    }
-               }
              break;
 
            case lang_constructors_statement_enum:
@@ -3549,11 +3771,8 @@ update_wild_statements (lang_statement_union_type *s)
              break;
 
            case lang_output_section_statement_enum:
-             /* Don't sort .init/.fini sections.  */
-             if (strcmp (s->output_section_statement.name, ".init") != 0
-                 && strcmp (s->output_section_statement.name, ".fini") != 0)
-               update_wild_statements
-                 (s->output_section_statement.children.head);
+             update_wild_statements
+               (s->output_section_statement.children.head);
              break;
 
            case lang_group_statement_enum:
@@ -3669,7 +3888,7 @@ map_input_to_output_sections
             processed the segment marker.  Originally, the linker
             treated segment directives (like -Ttext on the
             command-line) as section directives.  We honor the
-            section directive semantics for backwards compatibilty;
+            section directive semantics for backwards compatibility;
             linker scripts that do not specifically check for
             SEGMENT_START automatically get the old semantics.  */
          if (!s->address_statement.segment
@@ -3870,7 +4089,7 @@ strip_excluded_output_sections (void)
   if (expld.phase != lang_mark_phase_enum)
     {
       expld.phase = lang_mark_phase_enum;
-      expld.dataseg.phase = exp_dataseg_none;
+      expld.dataseg.phase = exp_seg_none;
       one_lang_size_sections_pass (NULL, FALSE);
       lang_reset_memory_regions ();
     }
@@ -3912,10 +4131,6 @@ strip_excluded_output_sections (void)
              }
        }
 
-      /* TODO: Don't just junk map_head.s, turn them into link_orders.  */
-      output_section->map_head.link_order = NULL;
-      output_section->map_tail.link_order = NULL;
-
       if (exclude)
        {
          /* We don't set bfd_section to NULL since bfd_section of the
@@ -3927,10 +4142,40 @@ strip_excluded_output_sections (void)
          link_info.output_bfd->section_count--;
        }
     }
+}
+
+/* Called from ldwrite to clear out asection.map_head and
+   asection.map_tail for use as link_orders in ldwrite.  */
+
+void
+lang_clear_os_map (void)
+{
+  lang_output_section_statement_type *os;
+
+  if (map_head_is_link_order)
+    return;
+
+  for (os = &lang_output_section_statement.head->output_section_statement;
+       os != NULL;
+       os = os->next)
+    {
+      asection *output_section;
+
+      if (os->constraint < 0)
+       continue;
+
+      output_section = os->bfd_section;
+      if (output_section == NULL)
+       continue;
+
+      /* TODO: Don't just junk map_head.s, turn them into link_orders.  */
+      output_section->map_head.link_order = NULL;
+      output_section->map_tail.link_order = NULL;
+    }
 
   /* Stop future calls to lang_add_section from messing with map_head
      and map_tail link_order fields.  */
-  stripped_excluded_sections = TRUE;
+  map_head_is_link_order = TRUE;
 }
 
 static void
@@ -3960,7 +4205,7 @@ print_output_section_statement
              ++len;
            }
 
-         minfo ("0x%V %W", section->vma, section->size);
+         minfo ("0x%V %W", section->vma, TO_ADDR (section->size));
 
          if (section->vma != section->lma)
            minfo (_(" load address 0x%V"), section->lma);
@@ -3999,15 +4244,18 @@ print_assignment (lang_assignment_statement_type *assignment,
       const char *dst = assignment->exp->assign.dst;
 
       is_dot = (dst[0] == '.' && dst[1] == 0);
-      if (!is_dot)
-       expld.assign_name = dst;
-      tree = assignment->exp->assign.src;
+      tree = assignment->exp;
     }
 
   osec = output_section->bfd_section;
   if (osec == NULL)
     osec = bfd_abs_section_ptr;
-  exp_fold_tree (tree, osec, &print_dot);
+
+  if (assignment->exp->type.node_class != etree_provide)
+    exp_fold_tree (tree, osec, &print_dot);
+  else
+    expld.result.valid_p = FALSE;
+
   if (expld.result.valid_p)
     {
       bfd_vma value;
@@ -4031,7 +4279,9 @@ print_assignment (lang_assignment_statement_type *assignment,
 
          h = bfd_link_hash_lookup (link_info.hash, assignment->exp->assign.dst,
                                    FALSE, FALSE, TRUE);
-         if (h)
+         if (h != NULL
+             && (h->type == bfd_link_hash_defined
+                 || h->type == bfd_link_hash_defweak))
            {
              value = h->u.def.value;
              value += h->u.def.section->output_section->vma;
@@ -4045,7 +4295,10 @@ print_assignment (lang_assignment_statement_type *assignment,
     }
   else
     {
-      minfo ("*undef*   ");
+      if (assignment->exp->type.node_class == etree_provide)
+       minfo ("[!provide]");
+      else
+       minfo ("*undef*   ");
 #ifdef BFD64
       minfo ("        ");
 #endif
@@ -4087,7 +4340,7 @@ print_one_symbol (struct bfd_link_hash_entry *hash_entry, void *ptr)
              + hash_entry->u.def.section->output_offset
              + hash_entry->u.def.section->output_section->vma));
 
-      minfo ("             %T\n", hash_entry->root.string);
+      minfo ("             %pT\n", hash_entry->root.string);
     }
 
   return TRUE;
@@ -4123,7 +4376,8 @@ print_all_symbols (asection *sec)
 
   /* Sort the symbols by address.  */
   entries = (struct bfd_link_hash_entry **)
-      obstack_alloc (&map_obstack, ud->map_symbol_def_count * sizeof (*entries));
+      obstack_alloc (&map_obstack,
+                    ud->map_symbol_def_count * sizeof (*entries));
 
   for (i = 0, def = ud->map_symbol_def_head; def; def = def->next, i++)
     entries[i] = def->entry;
@@ -4174,7 +4428,7 @@ print_input_section (asection *i, bfd_boolean is_discarded)
        size = 0;
     }
 
-  minfo ("0x%V %W %B\n", addr, TO_ADDR (size), i->owner);
+  minfo ("0x%V %W %pB\n", addr, size, i->owner);
 
   if (size != i->rawsize && i->rawsize != 0)
     {
@@ -4262,7 +4516,9 @@ print_data_statement (lang_data_statement_type *data)
       break;
     }
 
-  minfo ("0x%V %W %s 0x%v", addr, size, name, data->value);
+  if (size < TO_SIZE ((unsigned) 1))
+    size = TO_SIZE ((unsigned) 1);
+  minfo ("0x%V %W %s 0x%v", addr, TO_ADDR (size), name, data->value);
 
   if (data->exp->type.node_class != etree_value)
     {
@@ -4305,7 +4561,7 @@ print_reloc_statement (lang_reloc_statement_type *reloc)
 
   size = bfd_get_reloc_size (reloc->howto);
 
-  minfo ("0x%V %W RELOC %s ", addr, size, reloc->howto->name);
+  minfo ("0x%V %W RELOC %s ", addr, TO_ADDR (size), reloc->howto->name);
 
   if (reloc->name != NULL)
     minfo ("%s+", reloc->name);
@@ -4338,7 +4594,7 @@ print_padding_statement (lang_padding_statement_type *s)
   addr = s->output_offset;
   if (s->output_section != NULL)
     addr += s->output_section->vma;
-  minfo ("0x%V %W ", addr, (bfd_vma) s->size);
+  minfo ("0x%V %W ", addr, TO_ADDR (s->size));
 
   if (s->fill->size != 0)
     {
@@ -4361,8 +4617,17 @@ print_wild_statement (lang_wild_statement_type *w,
 
   print_space ();
 
+  if (w->exclude_name_list)
+    {
+      name_list *tmp;
+      minfo ("EXCLUDE_FILE(%s", w->exclude_name_list->name);
+      for (tmp = w->exclude_name_list->next; tmp; tmp = tmp->next)
+       minfo (" %s", tmp->name);
+      minfo (") ");
+    }
+
   if (w->filenames_sorted)
-    minfo ("SORT(");
+    minfo ("SORT_BY_NAME(");
   if (w->filename != NULL)
     minfo ("%s", w->filename);
   else
@@ -4373,21 +4638,57 @@ print_wild_statement (lang_wild_statement_type *w,
   minfo ("(");
   for (sec = w->section_list; sec; sec = sec->next)
     {
-      if (sec->spec.sorted)
-       minfo ("SORT(");
-      if (sec->spec.exclude_name_list != NULL)
+      int closing_paren = 0;
+
+      switch (sec->spec.sorted)
        {
-         name_list *tmp;
-         minfo ("EXCLUDE_FILE(%s", sec->spec.exclude_name_list->name);
-         for (tmp = sec->spec.exclude_name_list->next; tmp; tmp = tmp->next)
-           minfo (" %s", tmp->name);
-         minfo (") ");
-       }
+       case none:
+         break;
+
+       case by_name:
+         minfo ("SORT_BY_NAME(");
+         closing_paren = 1;
+         break;
+
+       case by_alignment:
+         minfo ("SORT_BY_ALIGNMENT(");
+         closing_paren = 1;
+         break;
+
+       case by_name_alignment:
+         minfo ("SORT_BY_NAME(SORT_BY_ALIGNMENT(");
+         closing_paren = 2;
+         break;
+
+       case by_alignment_name:
+         minfo ("SORT_BY_ALIGNMENT(SORT_BY_NAME(");
+         closing_paren = 2;
+         break;
+
+       case by_none:
+         minfo ("SORT_NONE(");
+         closing_paren = 1;
+         break;
+
+       case by_init_priority:
+         minfo ("SORT_BY_INIT_PRIORITY(");
+         closing_paren = 1;
+         break;
+       }
+
+      if (sec->spec.exclude_name_list != NULL)
+       {
+         name_list *tmp;
+         minfo ("EXCLUDE_FILE(%s", sec->spec.exclude_name_list->name);
+         for (tmp = sec->spec.exclude_name_list->next; tmp; tmp = tmp->next)
+           minfo (" %s", tmp->name);
+         minfo (") ");
+       }
       if (sec->spec.name != NULL)
        minfo ("%s", sec->spec.name);
       else
        minfo ("*");
-      if (sec->spec.sorted)
+      for (;closing_paren > 0; closing_paren--)
        minfo (")");
       if (sec->next)
        minfo (" ");
@@ -4572,8 +4873,9 @@ insert_pad (lang_statement_union_type **ptr,
     }
   pad->padding_statement.output_offset = dot - output_section->vma;
   pad->padding_statement.size = alignment_needed;
-  output_section->size = TO_SIZE (dot + TO_ADDR (alignment_needed)
-                                 - output_section->vma);
+  if (!(output_section->flags & SEC_FIXED_SIZE))
+    output_section->size = TO_SIZE (dot + TO_ADDR (alignment_needed)
+                                   - output_section->vma);
 }
 
 /* Work out how much this section will move the dot point.  */
@@ -4591,7 +4893,8 @@ size_input_section
 
   if (i->sec_info_type == SEC_INFO_TYPE_JUST_SYMS)
     i->output_offset = i->vma - o->vma;
-  else if ((i->flags & SEC_EXCLUDE) != 0)
+  else if (((i->flags & SEC_EXCLUDE) != 0)
+          || output_section_statement->ignored)
     i->output_offset = dot - o->vma;
   else
     {
@@ -4602,8 +4905,10 @@ size_input_section
         is greater than any seen before, then record it too.  Perform
         the alignment by inserting a magic 'padding' statement.  */
 
-      if (output_section_statement->subsection_alignment != -1)
-       i->alignment_power = output_section_statement->subsection_alignment;
+      if (output_section_statement->subsection_alignment != NULL)
+       i->alignment_power
+         = exp_get_power (output_section_statement->subsection_alignment,
+                          "subsection alignment");
 
       if (o->alignment_power < i->alignment_power)
        o->alignment_power = i->alignment_power;
@@ -4621,23 +4926,28 @@ size_input_section
 
       /* Mark how big the output section must be to contain this now.  */
       dot += TO_ADDR (i->size);
-      o->size = TO_SIZE (dot - o->vma);
+      if (!(o->flags & SEC_FIXED_SIZE))
+       o->size = TO_SIZE (dot - o->vma);
     }
 
   return dot;
 }
 
+struct check_sec
+{
+  asection *sec;
+  bfd_boolean warned;
+};
+
 static int
 sort_sections_by_lma (const void *arg1, const void *arg2)
 {
-  const asection *sec1 = *(const asection **) arg1;
-  const asection *sec2 = *(const asection **) arg2;
+  const asection *sec1 = ((const struct check_sec *) arg1)->sec;
+  const asection *sec2 = ((const struct check_sec *) arg2)->sec;
 
-  if (bfd_section_lma (sec1->owner, sec1)
-      < bfd_section_lma (sec2->owner, sec2))
+  if (sec1->lma < sec2->lma)
     return -1;
-  else if (bfd_section_lma (sec1->owner, sec1)
-          > bfd_section_lma (sec2->owner, sec2))
+  else if (sec1->lma > sec2->lma)
     return 1;
   else if (sec1->id < sec2->id)
     return -1;
@@ -4647,10 +4957,29 @@ sort_sections_by_lma (const void *arg1, const void *arg2)
   return 0;
 }
 
+static int
+sort_sections_by_vma (const void *arg1, const void *arg2)
+{
+  const asection *sec1 = ((const struct check_sec *) arg1)->sec;
+  const asection *sec2 = ((const struct check_sec *) arg2)->sec;
+
+  if (sec1->vma < sec2->vma)
+    return -1;
+  else if (sec1->vma > sec2->vma)
+    return 1;
+  else if (sec1->id < sec2->id)
+    return -1;
+  else if (sec1->id > sec2->id)
+    return 1;
+
+  return 0;
+}
+
+#define IS_TBSS(s) \
+  ((s->flags & (SEC_LOAD | SEC_THREAD_LOCAL)) == SEC_THREAD_LOCAL)
+
 #define IGNORE_SECTION(s) \
-  ((s->flags & SEC_ALLOC) == 0                         \
-   || ((s->flags & SEC_THREAD_LOCAL) != 0              \
-       && (s->flags & SEC_LOAD) == 0))
+  ((s->flags & SEC_ALLOC) == 0 || IS_TBSS (s))
 
 /* Check to see if any allocated sections overlap with other allocated
    sections.  This can happen if a linker script specifies the output
@@ -4661,66 +4990,132 @@ static void
 lang_check_section_addresses (void)
 {
   asection *s, *p;
-  asection **sections, **spp;
-  unsigned int count;
+  struct check_sec *sections;
+  size_t i, count;
+  bfd_vma addr_mask;
   bfd_vma s_start;
   bfd_vma s_end;
-  bfd_vma p_start;
-  bfd_vma p_end;
-  bfd_size_type amt;
+  bfd_vma p_start = 0;
+  bfd_vma p_end = 0;
   lang_memory_region_type *m;
+  bfd_boolean overlays;
+
+  /* Detect address space overflow on allocated sections.  */
+  addr_mask = ((bfd_vma) 1 <<
+              (bfd_arch_bits_per_address (link_info.output_bfd) - 1)) - 1;
+  addr_mask = (addr_mask << 1) + 1;
+  for (s = link_info.output_bfd->sections; s != NULL; s = s->next)
+    if ((s->flags & SEC_ALLOC) != 0)
+      {
+       s_end = (s->vma + s->size) & addr_mask;
+       if (s_end != 0 && s_end < (s->vma & addr_mask))
+         einfo (_("%X%P: section %s VMA wraps around address space\n"),
+                s->name);
+       else
+         {
+           s_end = (s->lma + s->size) & addr_mask;
+           if (s_end != 0 && s_end < (s->lma & addr_mask))
+             einfo (_("%X%P: section %s LMA wraps around address space\n"),
+                    s->name);
+         }
+      }
 
   if (bfd_count_sections (link_info.output_bfd) <= 1)
     return;
 
-  amt = bfd_count_sections (link_info.output_bfd) * sizeof (asection *);
-  sections = (asection **) xmalloc (amt);
+  count = bfd_count_sections (link_info.output_bfd);
+  sections = XNEWVEC (struct check_sec, count);
 
   /* Scan all sections in the output list.  */
   count = 0;
   for (s = link_info.output_bfd->sections; s != NULL; s = s->next)
     {
-      /* Only consider loadable sections with real contents.  */
-      if (!(s->flags & SEC_LOAD)
-         || !(s->flags & SEC_ALLOC)
+      if (IGNORE_SECTION (s)
          || s->size == 0)
        continue;
 
-      sections[count] = s;
+      sections[count].sec = s;
+      sections[count].warned = FALSE;
       count++;
     }
 
   if (count <= 1)
-    return;
+    {
+      free (sections);
+      return;
+    }
 
-  qsort (sections, (size_t) count, sizeof (asection *),
-        sort_sections_by_lma);
+  qsort (sections, count, sizeof (*sections), sort_sections_by_lma);
 
-  spp = sections;
-  s = *spp++;
-  s_start = s->lma;
-  s_end = s_start + TO_ADDR (s->size) - 1;
-  for (count--; count; count--)
+  /* First check section LMAs.  There should be no overlap of LMAs on
+     loadable sections, even with overlays.  */
+  for (p = NULL, i = 0; i < count; i++)
     {
-      /* We must check the sections' LMA addresses not their VMA
-        addresses because overlay sections can have overlapping VMAs
-        but they must have distinct LMAs.  */
-      p = s;
+      s = sections[i].sec;
+      if ((s->flags & SEC_LOAD) != 0)
+       {
+         s_start = s->lma;
+         s_end = s_start + TO_ADDR (s->size) - 1;
+
+         /* Look for an overlap.  We have sorted sections by lma, so
+            we know that s_start >= p_start.  Besides the obvious
+            case of overlap when the current section starts before
+            the previous one ends, we also must have overlap if the
+            previous section wraps around the address space.  */
+         if (p != NULL
+             && (s_start <= p_end
+                 || p_end < p_start))
+           {
+             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;
+           }
+         p = s;
+         p_start = s_start;
+         p_end = s_end;
+       }
+    }
+
+  /* If any non-zero size allocated section (excluding tbss) starts at
+     exactly the same VMA as another such section, then we have
+     overlays.  Overlays generated by the OVERLAY keyword will have
+     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;
+  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;
+         break;
+       }
       p_start = s_start;
-      p_end = s_end;
-      s = *spp++;
-      s_start = s->lma;
-      s_end = s_start + TO_ADDR (s->size) - 1;
-
-      /* Look for an overlap.  We have sorted sections by lma, so we
-        know that s_start >= p_start.  Besides the obvious case of
-        overlap when the current section starts before the previous
-        one ends, we also must have overlap if the previous section
-        wraps around the address space.  */
-      if (s_start <= p_end
-         || p_end < p_start)
-       einfo (_("%X%P: section %s loaded at [%V,%V] overlaps section %s loaded at [%V,%V]\n"),
-              s->name, s_start, s_end, p->name, p_start, p_end);
+    }
+
+  /* Now check section VMAs if no overlays were detected.  */
+  if (!overlays)
+    {
+      for (p = NULL, i = 0; i < count; i++)
+       {
+         s = sections[i].sec;
+         s_start = s->vma;
+         s_end = s_start + TO_ADDR (s->size) - 1;
+
+         if (p != NULL
+             && !sections[i].warned
+             && (s_start <= p_end
+                 || p_end < p_start))
+           einfo (_("%X%P: section %s VMA [%V,%V]"
+                    " overlaps section %s VMA [%V,%V]\n"),
+                  s->name, s_start, s_end, p->name, p_start, p_end);
+         p = s;
+         p_start = s_start;
+         p_end = s_end;
+       }
     }
 
   free (sections);
@@ -4735,9 +5130,13 @@ lang_check_section_addresses (void)
      a bfd_vma quantity in decimal.  */
   for (m = lang_memory_region_list; m; m = m->next)
     if (m->had_full_message)
-      einfo (_("%X%P: region `%s' overflowed by %ld bytes\n"),
-            m->name_list.name, (long)(m->current - (m->origin + m->length)));
-
+      {
+       unsigned long over = m->current - (m->origin + m->length);
+       einfo (ngettext ("%X%P: region `%s' overflowed by %lu byte\n",
+                        "%X%P: region `%s' overflowed by %lu bytes\n",
+                        over),
+              m->name_list.name, over);
+      }
 }
 
 /* Make sure the new address is within the region.  We explicitly permit the
@@ -4758,7 +5157,7 @@ os_region_check (lang_output_section_statement_type *os,
     {
       if (tree != NULL)
        {
-         einfo (_("%X%P: address 0x%v of %B section `%s'"
+         einfo (_("%X%P: address 0x%v of %pB section `%s'"
                   " is not within region `%s'\n"),
                 region->current,
                 os->bfd_section->owner,
@@ -4769,7 +5168,7 @@ os_region_check (lang_output_section_statement_type *os,
        {
          region->had_full_message = TRUE;
 
-         einfo (_("%X%P: %B section `%s' will not fit in region `%s'\n"),
+         einfo (_("%X%P: %pB section `%s' will not fit in region `%s'\n"),
                 os->bfd_section->owner,
                 os->bfd_section->name,
                 region->name_list.name);
@@ -4777,6 +5176,30 @@ os_region_check (lang_output_section_statement_type *os,
     }
 }
 
+static void
+ldlang_check_relro_region (lang_statement_union_type *s,
+                          seg_align_type *seg)
+{
+  if (seg->relro == exp_seg_relro_start)
+    {
+      if (!seg->relro_start_stat)
+       seg->relro_start_stat = s;
+      else
+       {
+         ASSERT (seg->relro_start_stat == s);
+       }
+    }
+  else if (seg->relro == exp_seg_relro_end)
+    {
+      if (!seg->relro_end_stat)
+       seg->relro_end_stat = s;
+      else
+       {
+         ASSERT (seg->relro_end_stat == s);
+       }
+    }
+}
+
 /* Set the sizes for all the output sections.  */
 
 static bfd_vma
@@ -4810,7 +5233,7 @@ lang_size_sections_1
               here, in lang_insert_orphan, or in the default linker scripts.
               This is covering for coff backend linker bugs.  See PR6945.  */
            if (os->addr_tree == NULL
-               && link_info.relocatable
+               && bfd_link_relocatable (&link_info)
                && (bfd_get_flavour (link_info.output_bfd)
                    == bfd_target_coff_flavour))
              os->addr_tree = exp_intop (0);
@@ -4826,7 +5249,7 @@ lang_size_sections_1
                      dot += expld.result.section->vma;
                  }
                else if (expld.phase != lang_mark_phase_enum)
-                 einfo (_("%F%S: non constant or forward reference"
+                 einfo (_("%F%P:%pS: non constant or forward reference"
                           " address expression for section %s\n"),
                         os->addr_tree, os->name);
              }
@@ -4851,14 +5274,15 @@ lang_size_sections_1
                    || os->children.head->header.next != NULL
                    || (os->children.head->header.type
                        != lang_input_section_enum))
-                 einfo (_("%P%X: Internal error on COFF shared library"
+                 einfo (_("%X%P: internal error on COFF shared library"
                           " section %s\n"), os->name);
 
                input = os->children.head->input_section.section;
                bfd_set_section_vma (os->bfd_section->owner,
                                     os->bfd_section,
                                     bfd_section_vma (input->owner, input));
-               os->bfd_section->size = input->size;
+               if (!(os->bfd_section->flags & SEC_FIXED_SIZE))
+                 os->bfd_section->size = input->size;
                break;
              }
 
@@ -4889,7 +5313,7 @@ lang_size_sections_1
                       defined, issue an error message.  */
                    if (!os->ignored
                        && !IGNORE_SECTION (os->bfd_section)
-                       && ! link_info.relocatable
+                       && !bfd_link_relocatable (&link_info)
                        && check_regions
                        && strcmp (os->region->name_list.name,
                                   DEFAULT_MEMORY_REGION) == 0
@@ -4909,7 +5333,7 @@ lang_size_sections_1
                           overridden by the using the --no-check-sections
                           switch.  */
                        if (command_line.check_section_addresses)
-                         einfo (_("%P%F: error: no memory region specified"
+                         einfo (_("%F%P: error: no memory region specified"
                                   " for loadable section `%s'\n"),
                                 bfd_get_section_name (link_info.output_bfd,
                                                       os->bfd_section));
@@ -4924,7 +5348,8 @@ lang_size_sections_1
                    section_alignment = os->bfd_section->alignment_power;
                  }
                else
-                 section_alignment = os->section_alignment;
+                 section_alignment = exp_get_power (os->section_alignment,
+                                                    "section alignment");
 
                /* Align to what the section needs.  */
                if (section_alignment > 0)
@@ -4937,8 +5362,11 @@ lang_size_sections_1
                        && (config.warn_section_align
                            || os->addr_tree != NULL)
                        && expld.phase != lang_mark_phase_enum)
-                     einfo (_("%P: warning: changing start of section"
-                              " %s by %lu bytes\n"),
+                     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);
                  }
 
@@ -4970,7 +5398,9 @@ lang_size_sections_1
                          + os->block_value - 1)
                         & - (bfd_vma) os->block_value);
 
-               os->bfd_section->size = TO_SIZE (after - os->bfd_section->vma);
+               if (!(os->bfd_section->flags & SEC_FIXED_SIZE))
+                 os->bfd_section->size = TO_SIZE (after
+                                                  - os->bfd_section->vma);
              }
 
            /* Set section lma.  */
@@ -4997,7 +5427,8 @@ lang_size_sections_1
                       only align according to the value in the output
                       statement.  */
                    if (os->lma_region != os->region)
-                     section_alignment = os->section_alignment;
+                     section_alignment = exp_get_power (os->section_alignment,
+                                                        "section alignment");
                    if (section_alignment > 0)
                      lma = align_power (lma, section_alignment);
                  }
@@ -5017,7 +5448,7 @@ lang_size_sections_1
                   create overlapping LMAs.  */
                if (dot < last->vma
                    && os->bfd_section->size != 0
-                   && dot + os->bfd_section->size <= last->vma)
+                   && dot + TO_ADDR (os->bfd_section->size) <= last->vma)
                  {
                    /* If dot moved backwards then leave lma equal to
                       vma.  This is the old default lma, which might
@@ -5026,15 +5457,15 @@ lang_size_sections_1
                       so people can fix their linker scripts.  */
 
                    if (last->vma != last->lma)
-                     einfo (_("%P: warning: dot moved backwards before `%s'\n"),
-                            os->name);
+                     einfo (_("%P: warning: dot moved backwards "
+                              "before `%s'\n"), os->name);
                  }
                else
                  {
                    /* If this is an overlay, set the current lma to that
                       at the end of the previous section.  */
                    if (os->sectype == overlay_section)
-                     lma = last->lma + last->size;
+                     lma = last->lma + TO_ADDR (last->size);
 
                    /* Otherwise, keep the same lma to vma relationship
                       as the previous section.  */
@@ -5048,9 +5479,6 @@ lang_size_sections_1
              }
            os->processed_lma = TRUE;
 
-           if (bfd_is_abs_section (os->bfd_section) || os->ignored)
-             break;
-
            /* Keep track of normal sections using the default
               lma region.  We use this to set the lma for
               following sections.  Overlays or other linker
@@ -5058,10 +5486,14 @@ lang_size_sections_1
               default lma == vma is incorrect.
               To avoid warnings about dot moving backwards when using
               -Ttext, don't start tracking sections until we find one
-              of non-zero size or with lma set differently to vma.  */
-           if (((os->bfd_section->flags & SEC_HAS_CONTENTS) != 0
-                || (os->bfd_section->flags & SEC_THREAD_LOCAL) == 0)
-               && (os->bfd_section->flags & SEC_ALLOC) != 0
+              of non-zero size or with lma set differently to vma.
+              Do this tracking before we short-cut the loop so that we
+              track changes for the case where the section size is zero,
+              but the lma is set differently to the vma.  This is
+              important, if an orphan section is placed after an
+              otherwise empty output section that has an explicit lma
+              set, we want that lma reflected in the orphans lma.  */
+           if (!IGNORE_SECTION (os->bfd_section)
                && (os->bfd_section->size != 0
                    || (r->last_os == NULL
                        && os->bfd_section->vma != os->bfd_section->lma)
@@ -5069,13 +5501,15 @@ lang_size_sections_1
                        && dot >= (r->last_os->output_section_statement
                                   .bfd_section->vma)))
                && os->lma_region == NULL
-               && !link_info.relocatable)
+               && !bfd_link_relocatable (&link_info))
              r->last_os = s;
 
+           if (bfd_is_abs_section (os->bfd_section) || os->ignored)
+             break;
+
            /* .tbss sections effectively have zero size.  */
-           if ((os->bfd_section->flags & SEC_HAS_CONTENTS) != 0
-               || (os->bfd_section->flags & SEC_THREAD_LOCAL) == 0
-               || link_info.relocatable)
+           if (!IS_TBSS (os->bfd_section)
+               || bfd_link_relocatable (&link_info))
              dotdelta = TO_ADDR (os->bfd_section->size);
            else
              dotdelta = 0;
@@ -5152,8 +5586,10 @@ lang_size_sections_1
            if (size < TO_SIZE ((unsigned) 1))
              size = TO_SIZE ((unsigned) 1);
            dot += TO_ADDR (size);
-           output_section_statement->bfd_section->size
-             = TO_SIZE (dot - output_section_statement->bfd_section->vma);
+           if (!(output_section_statement->bfd_section->flags
+                 & SEC_FIXED_SIZE))
+             output_section_statement->bfd_section->size
+               = TO_SIZE (dot - output_section_statement->bfd_section->vma);
 
          }
          break;
@@ -5168,8 +5604,10 @@ lang_size_sections_1
              output_section_statement->bfd_section;
            size = bfd_get_reloc_size (s->reloc_statement.howto);
            dot += TO_ADDR (size);
-           output_section_statement->bfd_section->size
-             = TO_SIZE (dot - output_section_statement->bfd_section->vma);
+           if (!(output_section_statement->bfd_section->flags
+                 & SEC_FIXED_SIZE))
+             output_section_statement->bfd_section->size
+               = TO_SIZE (dot - output_section_statement->bfd_section->vma);
          }
          break;
 
@@ -5180,8 +5618,9 @@ lang_size_sections_1
          break;
 
        case lang_object_symbols_statement_enum:
-         link_info.create_object_symbols_section =
-           output_section_statement->bfd_section;
+         link_info.create_object_symbols_section
+           = output_section_statement->bfd_section;
+         output_section_statement->bfd_section->flags |= SEC_KEEP;
          break;
 
        case lang_output_statement_enum:
@@ -5197,8 +5636,8 @@ lang_size_sections_1
              {
                bfd_boolean again;
 
-               if (! bfd_relax_section (i->owner, i, &link_info, &again))
-                 einfo (_("%P%F: can't relax section: %E\n"));
+               if (!bfd_relax_section (i->owner, i, &link_info, &again))
+                 einfo (_("%F%P: can't relax section: %E\n"));
                if (again)
                  *relax = TRUE;
              }
@@ -5222,31 +5661,15 @@ lang_size_sections_1
            bfd_vma newdot = dot;
            etree_type *tree = s->assignment_statement.exp;
 
-           expld.dataseg.relro = exp_dataseg_relro_none;
+           expld.dataseg.relro = exp_seg_relro_none;
 
            exp_fold_tree (tree,
                           output_section_statement->bfd_section,
                           &newdot);
 
-           if (expld.dataseg.relro == exp_dataseg_relro_start)
-             {
-               if (!expld.dataseg.relro_start_stat)
-                 expld.dataseg.relro_start_stat = s;
-               else
-                 {
-                   ASSERT (expld.dataseg.relro_start_stat == s);
-                 }
-             }
-           else if (expld.dataseg.relro == exp_dataseg_relro_end)
-             {
-               if (!expld.dataseg.relro_end_stat)
-                 expld.dataseg.relro_end_stat = s;
-               else
-                 {
-                   ASSERT (expld.dataseg.relro_end_stat == s);
-                 }
-             }
-           expld.dataseg.relro = exp_dataseg_relro_none;
+           ldlang_check_relro_region (s, &expld.dataseg);
+
+           expld.dataseg.relro = exp_seg_relro_none;
 
            /* This symbol may be relative to this section.  */
            if ((tree->type.node_class == etree_provided
@@ -5335,14 +5758,14 @@ lang_size_sections_1
    segments.  We are allowed an opportunity to override this decision.  */
 
 bfd_boolean
-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)
 {
-  lang_output_section_statement_type * cur;
-  lang_output_section_statement_type * prev;
+  lang_output_section_statement_type *cur;
+  lang_output_section_statement_type *prev;
 
   /* The checks below are only necessary when the BFD library has decided
      that the two sections ought to be placed into the same segment.  */
@@ -5385,90 +5808,136 @@ one_lang_size_sections_pass (bfd_boolean *relax, bfd_boolean check_regions)
                        0, 0, relax, check_regions);
 }
 
+static bfd_boolean
+lang_size_segment (seg_align_type *seg)
+{
+  /* If XXX_SEGMENT_ALIGN XXX_SEGMENT_END pair was seen, check whether
+     a page could be saved in the data segment.  */
+  bfd_vma first, last;
+
+  first = -seg->base & (seg->pagesize - 1);
+  last = seg->end & (seg->pagesize - 1);
+  if (first && last
+      && ((seg->base & ~(seg->pagesize - 1))
+         != (seg->end & ~(seg->pagesize - 1)))
+      && first + last <= seg->pagesize)
+    {
+      seg->phase = exp_seg_adjust;
+      return TRUE;
+    }
+
+  seg->phase = exp_seg_done;
+  return FALSE;
+}
+
+static bfd_vma
+lang_size_relro_segment_1 (seg_align_type *seg)
+{
+  bfd_vma relro_end, desired_end;
+  asection *sec;
+
+  /* Compute the expected PT_GNU_RELRO/PT_LOAD segment end.  */
+  relro_end = ((seg->relro_end + seg->pagesize - 1)
+              & ~(seg->pagesize - 1));
+
+  /* Adjust by the offset arg of XXX_SEGMENT_RELRO_END.  */
+  desired_end = relro_end - seg->relro_offset;
+
+  /* For sections in the relro segment..  */
+  for (sec = link_info.output_bfd->section_last; sec; sec = sec->prev)
+    if ((sec->flags & SEC_ALLOC) != 0
+       && sec->vma >= seg->base
+       && sec->vma < seg->relro_end - seg->relro_offset)
+      {
+       /* Where do we want to put this section so that it ends as
+          desired?  */
+       bfd_vma start, end, bump;
+
+       end = start = sec->vma;
+       if (!IS_TBSS (sec))
+         end += TO_ADDR (sec->size);
+       bump = desired_end - end;
+       /* We'd like to increase START by BUMP, but we must heed
+          alignment so the increase might be less than optimum.  */
+       start += bump;
+       start &= ~(((bfd_vma) 1 << sec->alignment_power) - 1);
+       /* This is now the desired end for the previous section.  */
+       desired_end = start;
+      }
+
+  seg->phase = exp_seg_relro_adjust;
+  ASSERT (desired_end >= seg->base);
+  seg->base = desired_end;
+  return relro_end;
+}
+
+static bfd_boolean
+lang_size_relro_segment (bfd_boolean *relax, bfd_boolean check_regions)
+{
+  bfd_boolean do_reset = FALSE;
+  bfd_boolean do_data_relro;
+  bfd_vma data_initial_base, data_relro_end;
+
+  if (link_info.relro && expld.dataseg.relro_end)
+    {
+      do_data_relro = TRUE;
+      data_initial_base = expld.dataseg.base;
+      data_relro_end = lang_size_relro_segment_1 (&expld.dataseg);
+    }
+  else
+    {
+      do_data_relro = FALSE;
+      data_initial_base = data_relro_end = 0;
+    }
+
+  if (do_data_relro)
+    {
+      lang_reset_memory_regions ();
+      one_lang_size_sections_pass (relax, check_regions);
+
+      /* Assignments to dot, or to output section address in a user
+        script have increased padding over the original.  Revert.  */
+      if (do_data_relro && expld.dataseg.relro_end > data_relro_end)
+       {
+         expld.dataseg.base = data_initial_base;;
+         do_reset = TRUE;
+       }
+    }
+
+  if (!do_data_relro && lang_size_segment (&expld.dataseg))
+    do_reset = TRUE;
+
+  return do_reset;
+}
+
 void
 lang_size_sections (bfd_boolean *relax, bfd_boolean check_regions)
 {
   expld.phase = lang_allocating_phase_enum;
-  expld.dataseg.phase = exp_dataseg_none;
+  expld.dataseg.phase = exp_seg_none;
 
   one_lang_size_sections_pass (relax, check_regions);
-  if (expld.dataseg.phase == exp_dataseg_end_seen
-      && link_info.relro && expld.dataseg.relro_end)
-    {
-      /* If DATA_SEGMENT_ALIGN DATA_SEGMENT_RELRO_END pair was seen, try
-        to put expld.dataseg.relro_end on a (common) page boundary.  */
-      bfd_vma min_base, relro_end, maxpage;
-
-      expld.dataseg.phase = exp_dataseg_relro_adjust;
-      maxpage = expld.dataseg.maxpagesize;
-      /* MIN_BASE is the absolute minimum address we are allowed to start the
-        read-write segment (byte before will be mapped read-only).  */
-      min_base = (expld.dataseg.min_base + maxpage - 1) & ~(maxpage - 1);
-      expld.dataseg.base += (-expld.dataseg.relro_end
-                            & (expld.dataseg.pagesize - 1));
-      /* Compute the expected PT_GNU_RELRO segment end.  */
-      relro_end = ((expld.dataseg.relro_end + expld.dataseg.pagesize - 1)
-                  & ~(expld.dataseg.pagesize - 1));
-      if (min_base + maxpage < expld.dataseg.base)
-       {
-         expld.dataseg.base -= maxpage;
-         relro_end -= maxpage;
-       }
-      lang_reset_memory_regions ();
-      one_lang_size_sections_pass (relax, check_regions);
-      if (expld.dataseg.relro_end > relro_end)
-       {
-         /* The alignment of sections between DATA_SEGMENT_ALIGN
-            and DATA_SEGMENT_RELRO_END can cause excessive padding to
-            be inserted at DATA_SEGMENT_RELRO_END.  Try to start a
-            bit lower so that the section alignments will fit in.  */
-         asection *sec;
-         unsigned int max_alignment_power = 0;
 
-         /* Find maximum alignment power of sections between
-            DATA_SEGMENT_ALIGN and DATA_SEGMENT_RELRO_END.  */
-         for (sec = link_info.output_bfd->sections; sec; sec = sec->next)
-           if (sec->vma >= expld.dataseg.base
-               && sec->vma < expld.dataseg.relro_end
-               && sec->alignment_power > max_alignment_power)
-             max_alignment_power = sec->alignment_power;
+  if (expld.dataseg.phase != exp_seg_end_seen)
+    expld.dataseg.phase = exp_seg_done;
 
-         if (((bfd_vma) 1 << max_alignment_power) < expld.dataseg.pagesize)
-           {
-             /* Aligning the adjusted base guarantees the padding
-                between sections won't change.  This is better than
-                simply subtracting 1 << max_alignment_power which is
-                what we used to do here.  */
-             expld.dataseg.base &= ~((1 << max_alignment_power) - 1);
-             lang_reset_memory_regions ();
-             one_lang_size_sections_pass (relax, check_regions);
-           }
-       }
-      link_info.relro_start = expld.dataseg.base;
-      link_info.relro_end = expld.dataseg.relro_end;
-    }
-  else if (expld.dataseg.phase == exp_dataseg_end_seen)
+  if (expld.dataseg.phase == exp_seg_end_seen)
     {
-      /* If DATA_SEGMENT_ALIGN DATA_SEGMENT_END pair was seen, check whether
-        a page could be saved in the data segment.  */
-      bfd_vma first, last;
+      bfd_boolean do_reset
+       = lang_size_relro_segment (relax, check_regions);
 
-      first = -expld.dataseg.base & (expld.dataseg.pagesize - 1);
-      last = expld.dataseg.end & (expld.dataseg.pagesize - 1);
-      if (first && last
-         && ((expld.dataseg.base & ~(expld.dataseg.pagesize - 1))
-             != (expld.dataseg.end & ~(expld.dataseg.pagesize - 1)))
-         && first + last <= expld.dataseg.pagesize)
+      if (do_reset)
        {
-         expld.dataseg.phase = exp_dataseg_adjust;
          lang_reset_memory_regions ();
          one_lang_size_sections_pass (relax, check_regions);
        }
-      else
-       expld.dataseg.phase = exp_dataseg_done;
+
+      if (link_info.relro && expld.dataseg.relro_end)
+       {
+         link_info.relro_start = expld.dataseg.base;
+         link_info.relro_end = expld.dataseg.relro_end;
+       }
     }
-  else
-    expld.dataseg.phase = exp_dataseg_done;
 }
 
 static lang_output_section_statement_type *current_section;
@@ -5496,6 +5965,7 @@ lang_do_assignments_1 (lang_statement_union_type *s,
        case lang_output_section_statement_enum:
          {
            lang_output_section_statement_type *os;
+           bfd_vma newdot;
 
            os = &(s->output_section_statement);
            os->after_end = *found_end;
@@ -5507,18 +5977,24 @@ lang_do_assignments_1 (lang_statement_union_type *s,
                    prefer_next_section = FALSE;
                  }
                dot = os->bfd_section->vma;
-
-               lang_do_assignments_1 (os->children.head,
-                                      os, os->fill, dot, found_end);
-
-               /* .tbss sections effectively have zero size.  */
-               if ((os->bfd_section->flags & SEC_HAS_CONTENTS) != 0
-                   || (os->bfd_section->flags & SEC_THREAD_LOCAL) == 0
-                   || link_info.relocatable)
-                 dot += TO_ADDR (os->bfd_section->size);
-
-               if (os->update_dot_tree != NULL)
-                 exp_fold_tree (os->update_dot_tree, bfd_abs_section_ptr, &dot);
+             }
+           newdot = lang_do_assignments_1 (os->children.head,
+                                           os, os->fill, dot, found_end);
+           if (!os->ignored)
+             {
+               if (os->bfd_section != NULL)
+                 {
+                   /* .tbss sections effectively have zero size.  */
+                   if (!IS_TBSS (os->bfd_section)
+                       || bfd_link_relocatable (&link_info))
+                     dot += TO_ADDR (os->bfd_section->size);
+
+                   if (os->update_dot_tree != NULL)
+                     exp_fold_tree (os->update_dot_tree,
+                                    bfd_abs_section_ptr, &dot);
+                 }
+               else
+                 dot = newdot;
              }
          }
          break;
@@ -5542,7 +6018,7 @@ lang_do_assignments_1 (lang_statement_union_type *s,
              if (expld.result.section != NULL)
                s->data_statement.value += expld.result.section->vma;
            }
-         else
+         else if (expld.phase == lang_final_phase_enum)
            einfo (_("%F%P: invalid data statement\n"));
          {
            unsigned int size;
@@ -5575,7 +6051,7 @@ lang_do_assignments_1 (lang_statement_union_type *s,
                         bfd_abs_section_ptr, &dot);
          if (expld.result.valid_p)
            s->reloc_statement.addend_value = expld.result.value;
-         else
+         else if (expld.phase == lang_final_phase_enum)
            einfo (_("%F%P: invalid reloc statement\n"));
          dot += TO_ADDR (bfd_get_reloc_size (s->reloc_statement.howto));
          break;
@@ -5611,7 +6087,8 @@ lang_do_assignments_1 (lang_statement_union_type *s,
                *found_end = TRUE;
            }
          exp_fold_tree (s->assignment_statement.exp,
-                        current_os->bfd_section,
+                        (current_os->bfd_section != NULL
+                         ? current_os->bfd_section : bfd_und_section_ptr),
                         &dot);
          break;
 
@@ -5726,69 +6203,210 @@ section_for_dot (void)
   return bfd_abs_section_ptr;
 }
 
-/* Fix any .startof. or .sizeof. symbols.  When the assemblers see the
-   operator .startof. (section_name), it produces an undefined symbol
-   .startof.section_name.  Similarly, when it sees
-   .sizeof. (section_name), it produces an undefined symbol
-   .sizeof.section_name.  For all the output sections, we look for
-   such symbols, and set them to the correct value.  */
+/* Array of __start/__stop/.startof./.sizeof/ symbols.  */
+
+static struct bfd_link_hash_entry **start_stop_syms;
+static size_t start_stop_count = 0;
+static size_t start_stop_alloc = 0;
+
+/* Give start/stop SYMBOL for SEC a preliminary definition, and add it
+   to start_stop_syms.  */
 
 static void
-lang_set_startof (void)
+lang_define_start_stop (const char *symbol, asection *sec)
 {
+  struct bfd_link_hash_entry *h;
+
+  h = bfd_define_start_stop (link_info.output_bfd, &link_info, symbol, sec);
+  if (h != NULL)
+    {
+      if (start_stop_count == start_stop_alloc)
+       {
+         start_stop_alloc = 2 * start_stop_alloc + 10;
+         start_stop_syms
+           = xrealloc (start_stop_syms,
+                       start_stop_alloc * sizeof (*start_stop_syms));
+       }
+      start_stop_syms[start_stop_count++] = h;
+    }
+}
+
+/* Check for input sections whose names match references to
+   __start_SECNAME or __stop_SECNAME symbols.  Give the symbols
+   preliminary definitions.  */
+
+static void
+lang_init_start_stop (void)
+{
+  bfd *abfd;
   asection *s;
+  char leading_char = bfd_get_symbol_leading_char (link_info.output_bfd);
+
+  for (abfd = link_info.input_bfds; abfd != NULL; abfd = abfd->link.next)
+    for (s = abfd->sections; s != NULL; s = s->next)
+      {
+       const char *ps;
+       const char *secname = s->name;
+
+       for (ps = secname; *ps != '\0'; ps++)
+         if (!ISALNUM ((unsigned char) *ps) && *ps != '_')
+           break;
+       if (*ps == '\0')
+         {
+           char *symbol = (char *) xmalloc (10 + strlen (secname));
+
+           symbol[0] = leading_char;
+           sprintf (symbol + (leading_char != 0), "__start_%s", secname);
+           lang_define_start_stop (symbol, s);
+
+           symbol[1] = leading_char;
+           memcpy (symbol + 1 + (leading_char != 0), "__stop", 6);
+           lang_define_start_stop (symbol + 1, s);
+
+           free (symbol);
+         }
+      }
+}
+
+/* Iterate over start_stop_syms.  */
+
+static void
+foreach_start_stop (void (*func) (struct bfd_link_hash_entry *))
+{
+  size_t i;
+
+  for (i = 0; i < start_stop_count; ++i)
+    func (start_stop_syms[i]);
+}
 
-  if (link_info.relocatable)
+/* __start and __stop symbols are only supposed to be defined by the
+   linker for orphan sections, but we now extend that to sections that
+   map to an output section of the same name.  The symbols were
+   defined early for --gc-sections, before we mapped input to output
+   sections, so undo those that don't satisfy this rule.  */
+
+static void
+undef_start_stop (struct bfd_link_hash_entry *h)
+{
+  if (h->ldscript_def)
     return;
 
+  if (h->u.def.section->output_section == NULL
+      || h->u.def.section->output_section->owner != link_info.output_bfd
+      || strcmp (h->u.def.section->name,
+                h->u.def.section->output_section->name) != 0)
+    {
+      asection *sec = bfd_get_section_by_name (link_info.output_bfd,
+                                              h->u.def.section->name);
+      if (sec != NULL)
+       {
+         /* When there are more than one input sections with the same
+            section name, SECNAME, linker picks the first one to define
+            __start_SECNAME and __stop_SECNAME symbols.  When the first
+            input section is removed by comdat group, we need to check
+            if there is still an output section with section name
+            SECNAME.  */
+         asection *i;
+         for (i = sec->map_head.s; i != NULL; i = i->map_head.s)
+           if (strcmp (h->u.def.section->name, i->name) == 0)
+             {
+               h->u.def.section = i;
+               return;
+             }
+       }
+      h->type = bfd_link_hash_undefined;
+      h->u.undef.abfd = NULL;
+    }
+}
+
+static void
+lang_undef_start_stop (void)
+{
+  foreach_start_stop (undef_start_stop);
+}
+
+/* Check for output sections whose names match references to
+   .startof.SECNAME or .sizeof.SECNAME symbols.  Give the symbols
+   preliminary definitions.  */
+
+static void
+lang_init_startof_sizeof (void)
+{
+  asection *s;
+
   for (s = link_info.output_bfd->sections; s != NULL; s = s->next)
     {
-      const char *secname;
-      char *buf;
-      struct bfd_link_hash_entry *h;
+      const char *secname = s->name;
+      char *symbol = (char *) xmalloc (10 + strlen (secname));
 
-      secname = bfd_get_section_name (link_info.output_bfd, s);
-      buf = (char *) xmalloc (10 + strlen (secname));
+      sprintf (symbol, ".startof.%s", secname);
+      lang_define_start_stop (symbol, s);
 
-      sprintf (buf, ".startof.%s", secname);
-      h = bfd_link_hash_lookup (link_info.hash, buf, FALSE, FALSE, TRUE);
-      if (h != NULL && h->type == bfd_link_hash_undefined)
-       {
-         h->type = bfd_link_hash_defined;
-         h->u.def.value = 0;
-         h->u.def.section = s;
-       }
+      memcpy (symbol + 1, ".size", 5);
+      lang_define_start_stop (symbol + 1, s);
+      free (symbol);
+    }
+}
+
+/* Set .startof., .sizeof., __start and __stop symbols final values.  */
 
-      sprintf (buf, ".sizeof.%s", secname);
-      h = bfd_link_hash_lookup (link_info.hash, buf, FALSE, FALSE, TRUE);
-      if (h != NULL && h->type == bfd_link_hash_undefined)
+static void
+set_start_stop (struct bfd_link_hash_entry *h)
+{
+  if (h->ldscript_def
+      || h->type != bfd_link_hash_defined)
+    return;
+
+  if (h->root.string[0] == '.')
+    {
+      /* .startof. or .sizeof. symbol.
+        .startof. already has final value.  */
+      if (h->root.string[2] == 'i')
        {
-         h->type = bfd_link_hash_defined;
-         h->u.def.value = TO_ADDR (s->size);
+         /* .sizeof.  */
+         h->u.def.value = TO_ADDR (h->u.def.section->size);
          h->u.def.section = bfd_abs_section_ptr;
        }
+    }
+  else
+    {
+      /* __start or __stop symbol.  */
+      int has_lead = bfd_get_symbol_leading_char (link_info.output_bfd) != 0;
 
-      free (buf);
+      h->u.def.section = h->u.def.section->output_section;
+      if (h->root.string[4 + has_lead] == 'o')
+       {
+         /* __stop_ */
+         h->u.def.value = TO_ADDR (h->u.def.section->size);
+       }
     }
 }
 
+static void
+lang_finalize_start_stop (void)
+{
+  foreach_start_stop (set_start_stop);
+}
+
 static void
 lang_end (void)
 {
   struct bfd_link_hash_entry *h;
   bfd_boolean warn;
 
-  if ((link_info.relocatable && !link_info.gc_sections)
-      || (link_info.shared && !link_info.executable))
+  if ((bfd_link_relocatable (&link_info) && !link_info.gc_sections)
+      || bfd_link_dll (&link_info))
     warn = entry_from_cmdline;
   else
     warn = TRUE;
 
   /* Force the user to specify a root when generating a relocatable with
-     --gc-sections.  */
-  if (link_info.gc_sections && link_info.relocatable
+     --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 (_("%P%F: gc-sections requires either an entry or "
+    einfo (_("%F%P: gc-sections requires either an entry or "
             "an undefined symbol\n"));
 
   if (entry_symbol.name == NULL)
@@ -5812,8 +6430,8 @@ lang_end (void)
             + bfd_get_section_vma (link_info.output_bfd,
                                    h->u.def.section->output_section)
             + h->u.def.section->output_offset);
-      if (! bfd_set_start_address (link_info.output_bfd, val))
-       einfo (_("%P%F:%s: can't set start address\n"), entry_symbol.name);
+      if (!bfd_set_start_address (link_info.output_bfd, val))
+       einfo (_("%F%P: %s: can't set start address\n"), entry_symbol.name);
     }
   else
     {
@@ -5825,8 +6443,8 @@ lang_end (void)
       val = bfd_scan_vma (entry_symbol.name, &send, 0);
       if (*send == '\0')
        {
-         if (! bfd_set_start_address (link_info.output_bfd, val))
-           einfo (_("%P%F: 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
        {
@@ -5845,7 +6463,7 @@ lang_end (void)
              if (!(bfd_set_start_address
                    (link_info.output_bfd,
                     bfd_get_section_vma (link_info.output_bfd, ts))))
-               einfo (_("%P%F: can't set start address\n"));
+               einfo (_("%F%P: can't set start address\n"));
            }
          else
            {
@@ -5862,7 +6480,8 @@ lang_end (void)
    BFD.  */
 
 static void
-ignore_bfd_errors (const char *s ATTRIBUTE_UNUSED, ...)
+ignore_bfd_errors (const char *fmt ATTRIBUTE_UNUSED,
+                  va_list ap ATTRIBUTE_UNUSED)
 {
   /* Don't do anything.  */
 }
@@ -5896,14 +6515,15 @@ lang_check (void)
         input format may not have equivalent representations in
         the output format (and besides BFD does not translate
         relocs for other link purposes than a final link).  */
-      if ((link_info.relocatable || link_info.emitrelocations)
+      if ((bfd_link_relocatable (&link_info)
+          || link_info.emitrelocations)
          && (compatible == NULL
              || (bfd_get_flavour (input_bfd)
                  != bfd_get_flavour (link_info.output_bfd)))
          && (bfd_get_file_flags (input_bfd) & HAS_RELOC) != 0)
        {
-         einfo (_("%P%F: Relocatable linking with relocations from"
-                  " format %s (%B) to format %s (%B) is not supported\n"),
+         einfo (_("%F%P: relocatable linking with relocations from"
+                  " format %s (%pB) to format %s (%pB) is not supported\n"),
                 bfd_get_target (input_bfd), input_bfd,
                 bfd_get_target (link_info.output_bfd), link_info.output_bfd);
          /* einfo with %F exits.  */
@@ -5912,7 +6532,7 @@ lang_check (void)
       if (compatible == NULL)
        {
          if (command_line.warn_mismatch)
-           einfo (_("%P%X: %s architecture of input file `%B'"
+           einfo (_("%X%P: %s architecture of input file `%pB'"
                     " is incompatible with %s output\n"),
                   bfd_printable_name (input_bfd), input_bfd,
                   bfd_printable_name (link_info.output_bfd));
@@ -5929,15 +6549,15 @@ lang_check (void)
             function which will do nothing.  We still want to call
             bfd_merge_private_bfd_data, since it may set up
             information which is needed in the output file.  */
-         if (! command_line.warn_mismatch)
+         if (!command_line.warn_mismatch)
            pfn = bfd_set_error_handler (ignore_bfd_errors);
-         if (! bfd_merge_private_bfd_data (input_bfd, link_info.output_bfd))
+         if (!bfd_merge_private_bfd_data (input_bfd, &link_info))
            {
              if (command_line.warn_mismatch)
-               einfo (_("%P%X: failed to merge target specific data"
-                        " of file %B\n"), input_bfd);
+               einfo (_("%X%P: failed to merge target specific data"
+                        " of file %pB\n"), input_bfd);
            }
-         if (! command_line.warn_mismatch)
+         if (!command_line.warn_mismatch)
            bfd_set_error_handler (pfn);
        }
     }
@@ -5950,13 +6570,13 @@ lang_check (void)
 static void
 lang_common (void)
 {
-  if (command_line.inhibit_common_definition)
+  if (link_info.inhibit_common_definition)
     return;
-  if (link_info.relocatable
-      && ! command_line.force_common_definition)
+  if (bfd_link_relocatable (&link_info)
+      && !command_line.force_common_definition)
     return;
 
-  if (! config.sort_common)
+  if (!config.sort_common)
     bfd_link_hash_traverse (link_info.hash, lang_one_common, NULL);
   else
     {
@@ -6005,7 +6625,7 @@ lang_one_common (struct bfd_link_hash_entry *h, void *info)
 
   section = h->u.c.p->section;
   if (!bfd_define_common_symbol (link_info.output_bfd, &link_info, h))
-    einfo (_("%P%F: Could not define common symbol `%T': %E\n"),
+    einfo (_("%F%P: could not define common symbol `%pT': %E\n"),
           h->root.string);
 
   if (config.map_file != NULL)
@@ -6015,7 +6635,7 @@ lang_one_common (struct bfd_link_hash_entry *h, void *info)
       char *name;
       char buf[50];
 
-      if (! header_printed)
+      if (!header_printed)
        {
          minfo (_("\nAllocating common symbols\n"));
          minfo (_("Common symbol       size              file\n\n"));
@@ -6061,12 +6681,61 @@ lang_one_common (struct bfd_link_hash_entry *h, void *info)
          ++len;
        }
 
-      minfo ("%B\n", section->owner);
+      minfo ("%pB\n", section->owner);
     }
 
   return TRUE;
 }
 
+/* Handle a single orphan section S, placing the orphan into an appropriate
+   output section.  The effects of the --orphan-handling command line
+   option are handled here.  */
+
+static void
+ldlang_place_orphan (asection *s)
+{
+  if (config.orphan_handling == orphan_handling_discard)
+    {
+      lang_output_section_statement_type *os;
+      os = lang_output_section_statement_lookup (DISCARD_SECTION_NAME, 0,
+                                                TRUE);
+      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);
+    }
+  else
+    {
+      lang_output_section_statement_type *os;
+      const char *name = s->name;
+      int constraint = 0;
+
+      if (config.orphan_handling == orphan_handling_error)
+       einfo (_("%X%P: error: unplaced orphan section `%pA' from `%pB'\n"),
+              s, s->owner);
+
+      if (config.unique_orphan_sections || unique_section_p (s, NULL))
+       constraint = SPECIAL;
+
+      os = ldemul_place_orphan (s, name, constraint);
+      if (os == NULL)
+       {
+         os = lang_output_section_statement_lookup (name, constraint, TRUE);
+         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);
+       }
+
+      if (config.orphan_handling == orphan_handling_warn)
+       einfo (_("%P: warning: orphan section `%pA' from `%pB' being "
+                "placed in section `%s'\n"),
+              s, s->owner, os->name);
+    }
+}
+
 /* Run through the input files and ensure that every input section has
    somewhere to go.  If one is found without a destination then create
    an input request and place it into the statement tree.  */
@@ -6087,14 +6756,14 @@ lang_place_orphans (void)
 
              if (file->flags.just_syms)
                bfd_link_just_syms (file->the_bfd, s, &link_info);
-             else if ((s->flags & SEC_EXCLUDE) != 0)
+             else if (lang_discard_section_p (s))
                s->output_section = bfd_abs_section_ptr;
              else if (strcmp (s->name, "COMMON") == 0)
                {
                  /* This is a lonely common section which must have
                     come from an archive.  We attach to the section
                     with the wildcard.  */
-                 if (! link_info.relocatable
+                 if (!bfd_link_relocatable (&link_info)
                      || command_line.force_common_definition)
                    {
                      if (default_common_section == NULL)
@@ -6106,27 +6775,7 @@ lang_place_orphans (void)
                    }
                }
              else
-               {
-                 const char *name = s->name;
-                 int constraint = 0;
-
-                 if (config.unique_orphan_sections
-                     || unique_section_p (s, NULL))
-                   constraint = SPECIAL;
-
-                 if (!ldemul_place_orphan (s, name, constraint))
-                   {
-                     lang_output_section_statement_type *os;
-                     os = lang_output_section_statement_lookup (name,
-                                                                constraint,
-                                                                TRUE);
-                     if (os->addr_tree == NULL
-                         && (link_info.relocatable
-                             || (s->flags & (SEC_LOAD | SEC_ALLOC)) == 0))
-                       os->addr_tree = exp_intop (0);
-                     lang_add_section (&os->children, s, NULL, os);
-                   }
-               }
+               ldlang_place_orphan (s);
            }
        }
     }
@@ -6138,10 +6787,18 @@ lang_set_flags (lang_memory_region_type *ptr, const char *flags, int invert)
   flagword *ptr_flags;
 
   ptr_flags = invert ? &ptr->not_flags : &ptr->flags;
+
   while (*flags)
     {
       switch (*flags)
        {
+         /* PR 17900: An exclamation mark in the attributes reverses
+            the sense of any of the attributes that follow.  */
+       case '!':
+         invert = !invert;
+         ptr_flags = invert ? &ptr->not_flags : &ptr->flags;
+         break;
+
        case 'A': case 'a':
          *ptr_flags |= SEC_ALLOC;
          break;
@@ -6164,7 +6821,8 @@ lang_set_flags (lang_memory_region_type *ptr, const char *flags, int invert)
          break;
 
        default:
-         einfo (_("%P%F: invalid syntax in flags\n"));
+         einfo (_("%F%P: invalid character %c (%d) in flags\n"),
+                *flags, *flags);
          break;
        }
       flags++;
@@ -6179,9 +6837,9 @@ lang_for_each_input_file (void (*func) (lang_input_statement_type *))
 {
   lang_input_statement_type *f;
 
-  for (f = (lang_input_statement_type *) input_file_chain.head;
+  for (f = &input_file_chain.head->input_statement;
        f != NULL;
-       f = (lang_input_statement_type *) f->next_real_file)
+       f = &f->next_real_file->input_statement)
     func (f);
 }
 
@@ -6239,25 +6897,6 @@ lang_add_output (const char *name, int from_script)
     }
 }
 
-static int
-topower (int x)
-{
-  unsigned int i = 1;
-  int l;
-
-  if (x < 0)
-    return -1;
-
-  for (l = 0; l < 32; l++)
-    {
-      if (i >= (unsigned int) x)
-       return l;
-      i <<= 1;
-    }
-
-  return 0;
-}
-
 lang_output_section_statement_type *
 lang_enter_output_section_statement (const char *output_section_statement_name,
                                     etree_type *address_exp,
@@ -6290,12 +6929,11 @@ lang_enter_output_section_statement (const char *output_section_statement_name,
 
   os->align_lma_with_input = align_with_input == ALIGN_WITH_INPUT;
   if (os->align_lma_with_input && align != NULL)
-    einfo (_("%F%P:%S: error: align with input and explicit align specified\n"), NULL);
+    einfo (_("%F%P:%pS: error: align with input and explicit align specified\n"),
+          NULL);
 
-  os->subsection_alignment =
-    topower (exp_get_value_int (subalign, -1, "subsection alignment"));
-  os->section_alignment =
-    topower (exp_get_value_int (align, -1, "section alignment"));
+  os->subsection_alignment = subalign;
+  os->section_alignment = align;
 
   os->load_base = ebase;
   return os;
@@ -6308,7 +6946,6 @@ lang_final (void)
 
   new_stmt = new_stat (lang_output_statement, stat_ptr);
   new_stmt->name = output_filename;
-
 }
 
 /* Reset the current counters in the regions.  */
@@ -6338,7 +6975,8 @@ lang_reset_memory_regions (void)
     {
       /* Save the last size for possible use by bfd_relax_section.  */
       o->rawsize = o->size;
-      o->size = 0;
+      if (!(o->flags & SEC_FIXED_SIZE))
+       o->size = 0;
     }
 }
 
@@ -6389,13 +7027,12 @@ static void
 lang_gc_sections (void)
 {
   /* Keep all sections so marked in the link script.  */
-
   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)
      Twiddle the flag here, to simplify later linker code.  */
-  if (link_info.relocatable)
+  if (bfd_link_relocatable (&link_info))
     {
       LANG_FOR_EACH_INPUT_STATEMENT (f)
        {
@@ -6441,6 +7078,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,
                            bfd_boolean *has_relro_section)
 {
   if (*has_relro_section)
@@ -6448,7 +7086,7 @@ lang_find_relro_sections_1 (lang_statement_union_type *s,
 
   for (; s != NULL; s = s->header.next)
     {
-      if (s == expld.dataseg.relro_end_stat)
+      if (s == seg->relro_end_stat)
        break;
 
       switch (s->header.type)
@@ -6460,15 +7098,15 @@ lang_find_relro_sections_1 (lang_statement_union_type *s,
          break;
        case lang_constructors_statement_enum:
          lang_find_relro_sections_1 (constructor_list.head,
-                                     has_relro_section);
+                                     seg, has_relro_section);
          break;
        case lang_output_section_statement_enum:
          lang_find_relro_sections_1 (s->output_section_statement.children.head,
-                                     has_relro_section);
+                                     seg, has_relro_section);
          break;
        case lang_group_statement_enum:
          lang_find_relro_sections_1 (s->group_statement.children.head,
-                                     has_relro_section);
+                                     seg, has_relro_section);
          break;
        default:
          break;
@@ -6484,7 +7122,7 @@ lang_find_relro_sections (void)
   /* Check all sections in the link script.  */
 
   lang_find_relro_sections_1 (expld.dataseg.relro_start_stat,
-                             &has_relro_section);
+                             &expld.dataseg, &has_relro_section);
 
   if (!has_relro_section)
     link_info.relro = FALSE;
@@ -6570,7 +7208,7 @@ find_replacements_insert_point (void)
       if (claim1->flags.claimed)
        return claim1->flags.claim_archive ? lastobject : claim1;
       /* Update lastobject if this is a real object file.  */
-      if (claim1->the_bfd && (claim1->the_bfd->my_archive == NULL))
+      if (claim1->the_bfd != NULL && claim1->the_bfd->my_archive == NULL)
        lastobject = claim1;
     }
   /* No files were claimed by the plugin.  Choose the last object
@@ -6579,6 +7217,52 @@ find_replacements_insert_point (void)
   return lastobject;
 }
 
+/* Find where to insert ADD, an archive element or shared library
+   added during a rescan.  */
+
+static lang_statement_union_type **
+find_rescan_insertion (lang_input_statement_type *add)
+{
+  bfd *add_bfd = add->the_bfd;
+  lang_input_statement_type *f;
+  lang_input_statement_type *last_loaded = NULL;
+  lang_input_statement_type *before = NULL;
+  lang_statement_union_type **iter = NULL;
+
+  if (add_bfd->my_archive != NULL)
+    add_bfd = add_bfd->my_archive;
+
+  /* First look through the input file chain, to find an object file
+     before the one we've rescanned.  Normal object files always
+     appear on both the input file chain and the file chain, so this
+     lets us get quickly to somewhere near the correct place on the
+     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;
+       f != NULL;
+       f = &f->next_real_file->input_statement)
+    {
+      if (f->the_bfd == add_bfd)
+       {
+         before = last_loaded;
+         if (f->next != NULL)
+           return &f->next->input_statement.next;
+       }
+      if (f->the_bfd != NULL && f->next != NULL)
+       last_loaded = f;
+    }
+
+  for (iter = before ? &before->next : &file_chain.head->input_statement.next;
+       *iter != NULL;
+       iter = &(*iter)->input_statement.next)
+    if (!(*iter)->input_statement.flags.claim_archive
+       && (*iter)->input_statement.the_bfd->my_archive == NULL)
+      break;
+
+  return iter;
+}
+
 /* Insert SRCLIST into DESTLIST after given element by chaining
    on FIELD as the next-pointer.  (Counterintuitively does not need
    a pointer to the actual after-node itself, just its chain field.)  */
@@ -6612,6 +7296,66 @@ lang_list_remove_tail (lang_statement_list_type *destlist,
 }
 #endif /* ENABLE_PLUGINS */
 
+/* Add NAME to the list of garbage collection entry points.  */
+
+void
+lang_add_gc_name (const char *name)
+{
+  struct bfd_sym_chain *sym;
+
+  if (name == NULL)
+    return;
+
+  sym = (struct bfd_sym_chain *) stat_alloc (sizeof (*sym));
+
+  sym->next = link_info.gc_sym_list;
+  sym->name = name;
+  link_info.gc_sym_list = sym;
+}
+
+/* Check relocations.  */
+
+static void
+lang_check_relocs (void)
+{
+  if (link_info.check_relocs_after_open_input)
+    {
+      bfd *abfd;
+
+      for (abfd = link_info.input_bfds;
+          abfd != (bfd *) NULL; abfd = abfd->link.next)
+       if (!bfd_link_check_relocs (abfd, &link_info))
+         {
+           /* No object output, fail return.  */
+           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.  */
+         }
+    }
+}
+
+/* Look through all output sections looking for places where we can
+   propagate forward the lma region.  */
+
+static void
+lang_propagate_lma_regions (void)
+{
+  lang_output_section_statement_type *os;
+
+  for (os = &lang_output_section_statement.head->output_section_statement;
+       os != NULL;
+       os = os->next)
+    {
+      if (os->prev != NULL
+         && os->lma_region == NULL
+         && os->load_base == NULL
+         && os->addr_tree == NULL
+         && os->region == os->prev->region)
+       os->lma_region = os->prev->lma_region;
+    }
+}
+
 void
 lang_process (void)
 {
@@ -6631,14 +7375,18 @@ lang_process (void)
   lang_place_undefineds ();
 
   if (!bfd_section_already_linked_table_init ())
-    einfo (_("%P%F: Failed to create hash table\n"));
+    einfo (_("%F%P: can not create hash table: %E\n"));
 
   /* 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
-  if (plugin_active_plugins_p ())
+  if (link_info.lto_plugin_active)
     {
       lang_statement_list_type added;
       lang_statement_list_type files, inputfiles;
@@ -6647,17 +7395,16 @@ lang_process (void)
         are any more to be added to the link before we call the
         emulation's after_open hook.  We create a private list of
         input statements for this purpose, which we will eventually
-        insert into the global statment list after the first claimed
+        insert into the global statement list after the first claimed
         file.  */
       added = *stat_ptr;
       /* We need to manipulate all three chains in synchrony.  */
       files = file_chain;
       inputfiles = input_file_chain;
       if (plugin_call_all_symbols_read ())
-       einfo (_("%P%F: %s: plugin reported error after all symbols read\n"),
+       einfo (_("%F%P: %s: plugin reported error after all symbols read\n"),
               plugin_error_plugin ());
       /* Open any newly added files, updating the file chains.  */
-      link_info.loading_lto_outputs = TRUE;
       open_input_bfds (*added.tail, OPEN_BFD_NORMAL);
       /* Restore the global list pointer now they have all been added.  */
       lang_list_remove_tail (stat_ptr, &added);
@@ -6690,14 +7437,64 @@ lang_process (void)
            lang_list_insert_after (&file_chain, &files, &file_chain.head);
 
          /* Rescan archives in case new undefined symbols have appeared.  */
+         files = file_chain;
+         lang_statement_iteration++;
          open_input_bfds (statement_list.head, OPEN_BFD_RESCAN);
+         lang_list_remove_tail (&file_chain, &files);
+         while (files.head != NULL)
+           {
+             lang_statement_union_type **insert;
+             lang_statement_union_type **iter, *temp;
+             bfd *my_arch;
+
+             insert = find_rescan_insertion (&files.head->input_statement);
+             /* All elements from an archive can be added at once.  */
+             iter = &files.head->input_statement.next;
+             my_arch = files.head->input_statement.the_bfd->my_archive;
+             if (my_arch != NULL)
+               for (; *iter != NULL; iter = &(*iter)->input_statement.next)
+                 if ((*iter)->input_statement.the_bfd->my_archive != my_arch)
+                   break;
+             temp = *insert;
+             *insert = files.head;
+             files.head = *iter;
+             *iter = temp;
+             if (my_arch != NULL)
+               {
+                 lang_input_statement_type *parent = my_arch->usrdata;
+                 if (parent != NULL)
+                   parent->next = (lang_statement_union_type *)
+                     ((char *) iter
+                      - offsetof (lang_input_statement_type, next));
+               }
+           }
        }
     }
 #endif /* ENABLE_PLUGINS */
 
+  /* Make sure that nobody has tried to add a symbol to this list
+     before now.  */
+  ASSERT (link_info.gc_sym_list == NULL);
+
   link_info.gc_sym_list = &entry_symbol;
+
   if (entry_symbol.name == NULL)
-    link_info.gc_sym_list = ldlang_undef_chain_list_head;
+    {
+      link_info.gc_sym_list = ldlang_undef_chain_list_head;
+
+      /* entry_symbol is normally initialied by a ENTRY definition in the
+        linker script or the -e command line option.  But if neither of
+        these have been used, the target specific backend may still have
+        provided an entry symbol via a call to lang_default_entry().
+        Unfortunately this value will not be processed until lang_end()
+        is called, long after this function has finished.  So detect this
+        case here and add the target's entry symbol to the list of starting
+        points for garbage collection resolution.  */
+      lang_add_gc_name (entry_symbol_default);
+    }
+
+  lang_add_gc_name (link_info.init_function);
+  lang_add_gc_name (link_info.fini_function);
 
   ldemul_after_open ();
   if (config.map_file != NULL)
@@ -6720,16 +7517,27 @@ lang_process (void)
      files.  */
   ldctor_build_sets ();
 
+  /* Give initial values for __start and __stop symbols, so that  ELF
+     gc_sections will keep sections referenced by these symbols.  Must
+     be done before lang_do_assignments below.  */
+  if (config.build_constructors)
+    lang_init_start_stop ();
+
   /* PR 13683: We must rerun the assignments prior to running garbage
      collection in order to make sure that all symbol aliases are resolved.  */
   lang_do_assignments (lang_mark_phase_enum);
   expld.phase = lang_first_phase_enum;
 
+  /* Size up the common data.  */
+  lang_common ();
+
   /* Remove unreferenced sections if asked to.  */
   lang_gc_sections ();
 
-  /* Size up the common data.  */
-  lang_common ();
+  /* Check relocations.  */
+  lang_check_relocs ();
+
+  ldemul_after_check_relocs ();
 
   /* Update wild statements.  */
   update_wild_statements (statement_list.head);
@@ -6744,7 +7552,7 @@ lang_process (void)
   /* Find any sections not attached explicitly and handle them.  */
   lang_place_orphans ();
 
-  if (! link_info.relocatable)
+  if (!bfd_link_relocatable (&link_info))
     {
       asection *found;
 
@@ -6766,6 +7574,20 @@ lang_process (void)
        }
     }
 
+  /* Copy forward lma regions for output sections in same lma region.  */
+  lang_propagate_lma_regions ();
+
+  /* Defining __start/__stop symbols early for --gc-sections to work
+     around a glibc build problem can result in these symbols being
+     defined when they should not be.  Fix them now.  */
+  if (config.build_constructors)
+    lang_undef_start_stop ();
+
+  /* Define .startof./.sizeof. symbols with preliminary values before
+     dynamic symbols are created.  */
+  if (!bfd_link_relocatable (&link_info))
+    lang_init_startof_sizeof ();
+
   /* Do anything special before sizing sections.  This is where ELF
      and other back-ends size dynamic sections.  */
   ldemul_before_allocation ();
@@ -6775,29 +7597,38 @@ lang_process (void)
   lang_record_phdrs ();
 
   /* Check relro sections.  */
-  if (link_info.relro && ! link_info.relocatable)
+  if (link_info.relro && !bfd_link_relocatable (&link_info))
     lang_find_relro_sections ();
 
   /* Size up the sections.  */
-  lang_size_sections (NULL, ! RELAXATION_ENABLED);
+  lang_size_sections (NULL, !RELAXATION_ENABLED);
 
   /* See if anything special should be done now we know how big
      everything is.  This is where relaxation is done.  */
   ldemul_after_allocation ();
 
-  /* Fix any .startof. or .sizeof. symbols.  */
-  lang_set_startof ();
+  /* Fix any __start, __stop, .startof. or .sizeof. symbols.  */
+  lang_finalize_start_stop ();
 
-  /* Do all the assignments, now that we know the final resting places
-     of all the symbols.  */
+  /* Do all the assignments again, to report errors.  Assignment
+     statements are processed multiple times, updating symbols; In
+     open_input_bfds, lang_do_assignments, and lang_size_sections.
+     Since lang_relax_sections calls lang_do_assignments, symbols are
+     also updated in ldemul_after_allocation.  */
   lang_do_assignments (lang_final_phase_enum);
 
   ldemul_finish ();
 
+  /* Convert absolute symbols to section relative.  */
+  ldexp_finalize_syms ();
+
   /* Make sure that the section addresses make sense.  */
   if (command_line.check_section_addresses)
     lang_check_section_addresses ();
 
+  /* Check any required symbols are known.  */
+  ldlang_check_require_defined_symbols ();
+
   lang_end ();
 }
 
@@ -6816,9 +7647,6 @@ lang_add_wild (struct wildcard_spec *filespec,
        curr != NULL;
        section_list = curr, curr = next)
     {
-      if (curr->spec.name != NULL && strcmp (curr->spec.name, "COMMON") == 0)
-       placed_commons = TRUE;
-
       next = curr->next;
       curr->next = section_list;
     }
@@ -6827,7 +7655,7 @@ lang_add_wild (struct wildcard_spec *filespec,
     {
       if (strcmp (filespec->name, "*") == 0)
        filespec->name = NULL;
-      else if (! wildcardp (filespec->name))
+      else if (!wildcardp (filespec->name))
        lang_has_input_file = TRUE;
     }
 
@@ -6835,11 +7663,13 @@ lang_add_wild (struct wildcard_spec *filespec,
   new_stmt->filename = NULL;
   new_stmt->filenames_sorted = FALSE;
   new_stmt->section_flag_list = NULL;
+  new_stmt->exclude_name_list = NULL;
   if (filespec != NULL)
     {
       new_stmt->filename = filespec->name;
       new_stmt->filenames_sorted = filespec->sorted == by_name;
       new_stmt->section_flag_list = filespec->section_flag_list;
+      new_stmt->exclude_name_list = filespec->exclude_name_list;
     }
   new_stmt->section_list = section_list;
   new_stmt->keep_sections = keep_sections;
@@ -6869,7 +7699,7 @@ lang_add_entry (const char *name, bfd_boolean cmdline)
 {
   if (entry_symbol.name == NULL
       || cmdline
-      || ! entry_from_cmdline)
+      || !entry_from_cmdline)
     {
       entry_symbol.name = name;
       entry_from_cmdline = cmdline;
@@ -6977,7 +7807,7 @@ lang_startup (const char *name)
 {
   if (first_file->filename != NULL)
     {
-      einfo (_("%P%F: multiple STARTUP files\n"));
+      einfo (_("%F%P: multiple STARTUP files\n"));
     }
   first_file->filename = name;
   first_file->local_sym_name = name;
@@ -7016,14 +7846,14 @@ lang_get_regions (lang_memory_region_type **region,
      has been specified, then use the load region for the runtime region
      as well.  */
   if (lma_memspec != NULL
-      && ! have_vma
+      && !have_vma
       && strcmp (memspec, DEFAULT_MEMORY_REGION) == 0)
     *region = *lma_region;
   else
     *region = lang_memory_region_lookup (memspec, FALSE);
 
   if (have_lma && lma_memspec != 0)
-    einfo (_("%X%P:%S: section has both a load address and a load region\n"),
+    einfo (_("%X%P:%pS: section has both a load address and a load region\n"),
           NULL);
 }
 
@@ -7038,16 +7868,6 @@ lang_leave_output_section_statement (fill_type *fill, const char *memspec,
                    current_section->load_base != NULL,
                    current_section->addr_tree != NULL);
 
-  /* If this section has no load region or base, but uses the same
-     region as the previous section, then propagate the previous
-     section's load region.  */
-
-  if (current_section->lma_region == NULL
-      && current_section->load_base == NULL
-      && current_section->addr_tree == NULL
-      && current_section->region == current_section->prev->region)
-    current_section->lma_region = current_section->prev->lma_region;
-
   current_section->fill = fill;
   current_section->phdrs = phdrs;
   pop_stat_ptr ();
@@ -7135,7 +7955,7 @@ lang_new_phdr (const char *name,
   n = (struct lang_phdr *) stat_alloc (sizeof (struct lang_phdr));
   n->next = NULL;
   n->name = name;
-  n->type = exp_get_value_int (type, 0, "program header type");
+  n->type = exp_get_vma (type, 0, "program header type");
   n->filehdr = filehdr;
   n->phdrs = phdrs;
   n->at = at;
@@ -7148,7 +7968,7 @@ lang_new_phdr (const char *name,
        && (*pp)->type == 1
        && !((*pp)->filehdr || (*pp)->phdrs))
       {
-       einfo (_("%X%P:%S: PHDRS and FILEHDR are not supported"
+       einfo (_("%X%P:%pS: PHDRS and FILEHDR are not supported"
                 " when prior PT_LOAD headers lack them\n"), NULL);
        hdrs = FALSE;
       }
@@ -7204,7 +8024,7 @@ lang_record_phdrs (void)
 
              if (last == NULL)
                {
-                 lang_output_section_statement_type * tmp_os;
+                 lang_output_section_statement_type *tmp_os;
 
                  /* If we have not run across a section with a program
                     header assigned to it yet, then scan forwards to find
@@ -7256,9 +8076,9 @@ lang_record_phdrs (void)
       else
        at = exp_get_vma (l->at, 0, "phdr load address");
 
-      if (! bfd_record_phdr (link_info.output_bfd, l->type,
-                            l->flags != NULL, flags, l->at != NULL,
-                            at, l->filehdr, l->phdrs, c, secs))
+      if (!bfd_record_phdr (link_info.output_bfd, l->type,
+                           l->flags != NULL, flags, l->at != NULL,
+                           at, l->filehdr, l->phdrs, c, secs))
        einfo (_("%F%P: bfd_record_phdr failed: %E\n"));
     }
 
@@ -7278,7 +8098,7 @@ lang_record_phdrs (void)
       for (pl = os->phdrs;
           pl != NULL;
           pl = pl->next)
-       if (! pl->used && strcmp (pl->name, "NONE") != 0)
+       if (!pl->used && strcmp (pl->name, "NONE") != 0)
          einfo (_("%X%P: section `%s' assigned to non-existent phdr `%s'\n"),
                 os->name, pl->name);
     }
@@ -7294,11 +8114,21 @@ lang_add_nocrossref (lang_nocrossref_type *l)
   n = (struct lang_nocrossrefs *) xmalloc (sizeof *n);
   n->next = nocrossref_list;
   n->list = l;
+  n->onlyfirst = FALSE;
   nocrossref_list = n;
 
   /* Set notice_all so that we get informed about all symbols.  */
   link_info.notice_all = TRUE;
 }
+
+/* Record a section that cannot be referenced from a list of sections.  */
+
+void
+lang_add_nocrossref_to (lang_nocrossref_type *l)
+{
+  lang_add_nocrossref (l);
+  nocrossref_list->onlyfirst = TRUE;
+}
 \f
 /* Overlay handling.  We handle overlays with some static variables.  */
 
@@ -7488,6 +8318,7 @@ lang_leave_overlay (etree_type *lma_expr,
   overlay_vma = NULL;
   overlay_list = NULL;
   overlay_max = NULL;
+  overlay_subalign = NULL;
 }
 \f
 /* Version handling.  This is only useful for ELF.  */
@@ -7986,6 +8817,39 @@ lang_do_version_exports_section (void)
                           lang_new_vers_node (greg, lreg), NULL);
 }
 
+/* Evaluate LENGTH and ORIGIN parts of MEMORY spec */
+
+static void
+lang_do_memory_regions (void)
+{
+  lang_memory_region_type *r = lang_memory_region_list;
+
+  for (; r != NULL; r = r->next)
+    {
+      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 (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);
+       }
+    }
+}
+
 void
 lang_add_unique (const char *name)
 {
@@ -8031,7 +8895,7 @@ lang_append_dynamic_list (struct bfd_elf_version_expr *dynamic)
 void
 lang_append_dynamic_list_cpp_typeinfo (void)
 {
-  const char * symbols [] =
+  const char *symbols[] =
     {
       "typeinfo name for*",
       "typeinfo for*"
@@ -8052,7 +8916,7 @@ lang_append_dynamic_list_cpp_typeinfo (void)
 void
 lang_append_dynamic_list_cpp_new (void)
 {
-  const char * symbols [] =
+  const char *symbols[] =
     {
       "operator new*",
       "operator delete*"
@@ -8095,3 +8959,41 @@ lang_ld_feature (char *str)
       p = q;
     }
 }
+
+/* Pretty print memory amount.  */
+
+static void
+lang_print_memory_size (bfd_vma sz)
+{
+  if ((sz & 0x3fffffff) == 0)
+    printf ("%10" BFD_VMA_FMT "u GB", sz >> 30);
+  else if ((sz & 0xfffff) == 0)
+    printf ("%10" BFD_VMA_FMT "u MB", sz >> 20);
+  else if ((sz & 0x3ff) == 0)
+    printf ("%10" BFD_VMA_FMT "u KB", sz >> 10);
+  else
+    printf (" %10" BFD_VMA_FMT "u B", sz);
+}
+
+/* Implement --print-memory-usage: disply per region memory usage.  */
+
+void
+lang_print_memory_usage (void)
+{
+  lang_memory_region_type *r;
+
+  printf ("Memory region         Used Size  Region Size  %%age Used\n");
+  for (r = lang_memory_region_list; r->next != NULL; r = r->next)
+    {
+      bfd_vma used_length = r->current - r->origin;
+      double percent;
+
+      printf ("%16s: ",r->name_list.name);
+      lang_print_memory_size (used_length);
+      lang_print_memory_size ((bfd_vma) r->length);
+
+      percent = used_length * 100.0 / r->length;
+
+      printf ("    %6.2f%%\n", percent);
+    }
+}
This page took 0.069064 seconds and 4 git commands to generate.