* gold/testsuite/Makefile.am (justsyms_exec): New testcase.
[deliverable/binutils-gdb.git] / ld / ldlang.c
index bc03374a6dc797bef01dcca3f30466b41199370e..0ffafb66554041d46791017d2ddf63e0ff1863b6 100644 (file)
@@ -1,6 +1,6 @@
 /* Linker command language support.
    Copyright 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
-   2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
+   2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011
    Free Software Foundation, Inc.
 
    This file is part of the GNU Binutils.
@@ -23,6 +23,7 @@
 #include "sysdep.h"
 #include "bfd.h"
 #include "libiberty.h"
+#include "filenames.h"
 #include "safe-ctype.h"
 #include "obstack.h"
 #include "bfdlink.h"
 #include "fnmatch.h"
 #include "demangle.h"
 #include "hashtab.h"
+#include "libbfd.h"
+#ifdef ENABLE_PLUGINS
+#include "plugin.h"
+#endif /* ENABLE_PLUGINS */
 
 #ifndef offsetof
 #define offsetof(TYPE, MEMBER) ((size_t) & (((TYPE*) 0)->MEMBER))
@@ -51,7 +56,7 @@ static struct obstack map_obstack;
 
 #define obstack_chunk_alloc xmalloc
 #define obstack_chunk_free free
-static const char *startup_file;
+static const char *entry_symbol_default = "start";
 static bfd_boolean placed_commons = FALSE;
 static bfd_boolean stripped_excluded_sections = FALSE;
 static lang_output_section_statement_type *default_common_section;
@@ -59,11 +64,12 @@ static bfd_boolean map_option_f;
 static bfd_vma print_dot;
 static lang_input_statement_type *first_file;
 static const char *current_target;
-static const char *output_target;
 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 bfd_boolean ldlang_sysrooted_script = FALSE;
 
 /* Forward declarations.  */
 static void exp_init_os (etree_type *);
@@ -86,23 +92,23 @@ static void lang_finalize_version_expr_head
   (struct bfd_elf_version_expr_head *);
 
 /* 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;
 lang_statement_list_type file_chain = { NULL, NULL };
 lang_statement_list_type input_file_chain;
 struct bfd_sym_chain entry_symbol = { NULL, NULL };
-static const char *entry_symbol_default = "start";
 const char *entry_section = ".text";
 bfd_boolean entry_from_cmdline;
+bfd_boolean undef_from_cmdline;
 bfd_boolean lang_has_input_file = FALSE;
 bfd_boolean had_output_filename = FALSE;
 bfd_boolean lang_float_flag = FALSE;
 bfd_boolean delete_output_file_on_failure = FALSE;
 struct lang_phdr *lang_phdr_list;
 struct lang_nocrossrefs *nocrossref_list;
-static struct unique_sections *unique_section_list;
-static bfd_boolean ldlang_sysrooted_script = FALSE;
+bfd_boolean missing_file = FALSE;
 
  /* Functions that traverse the linker script and might evaluate
     DEFINED() need to increment this.  */
@@ -194,7 +200,8 @@ input_statement_is_archive_path (const char *file_spec, char *sep,
 }
 
 static bfd_boolean
-unique_section_p (const asection *sec)
+unique_section_p (const asection *sec,
+                 const lang_output_section_statement_type *os)
 {
   struct unique_sections *unam;
   const char *secnam;
@@ -202,7 +209,8 @@ unique_section_p (const asection *sec)
   if (link_info.relocatable
       && sec->owner != NULL
       && bfd_is_group_section (sec->owner, sec))
-    return TRUE;
+    return !(os != NULL
+            && strcmp (os->name, DISCARD_SECTION_NAME) == 0);
 
   secnam = sec->name;
   for (unam = unique_section_list; unam; unam = unam->next)
@@ -229,6 +237,9 @@ walk_wild_consider_section (lang_wild_statement_type *ptr,
 {
   struct name_list *list_tmp;
 
+  /* Propagate the section_flag_info from the wild statement to the section.  */
+  s->section_flag_info = ptr->section_flag_list;
+
   /* Don't process sections from files which were excluded.  */
   for (list_tmp = sec->spec.exclude_name_list;
        list_tmp;
@@ -305,9 +316,9 @@ typedef struct
 } section_iterator_callback_data;
 
 static bfd_boolean
-section_iterator_callback (bfd *bfd ATTRIBUTE_UNUSED, asection *s, void *data)
+section_iterator_callback (bfd *abfd ATTRIBUTE_UNUSED, asection *s, void *data)
 {
-  section_iterator_callback_data *d = data;
+  section_iterator_callback_data *d = (section_iterator_callback_data *) data;
 
   if (d->found_section != NULL)
     {
@@ -363,18 +374,70 @@ match_simple_wild (const char *pattern, const char *name)
   return TRUE;
 }
 
+/* Return the numerical value of the init_priority attribute from
+   section name NAME.  */
+
+static unsigned long
+get_init_priority (const char *name)
+{
+  char *end;
+  unsigned long init_priority;
+
+  /* GCC uses the following section names for the init_priority
+     attribute with numerical values 101 and 65535 inclusive. A
+     lower value means a higher priority.
+
+     1: .init_array.NNNN/.fini_array.NNNN: Where NNNN is the
+       decimal numerical value of the init_priority attribute.
+       The order of execution in .init_array is forward and
+       .fini_array is backward.
+     2: .ctors.NNNN/.ctors.NNNN: Where NNNN is 65535 minus the
+       decimal numerical value of the init_priority attribute.
+       The order of execution in .ctors is backward and .dtors
+       is forward.
+   */
+  if (strncmp (name, ".init_array.", 12) == 0
+      || strncmp (name, ".fini_array.", 12) == 0)
+    {
+      init_priority = strtoul (name + 12, &end, 10);
+      return *end ? 0 : init_priority;
+    }
+  else if (strncmp (name, ".ctors.", 7) == 0
+          || strncmp (name, ".dtors.", 7) == 0)
+    {
+      init_priority = strtoul (name + 7, &end, 10);
+      return *end ? 0 : 65535 - init_priority;
+    }
+
+  return 0;
+}
+
 /* Compare sections ASEC and BSEC according to SORT.  */
 
 static int
 compare_section (sort_type sort, asection *asec, asection *bsec)
 {
   int ret;
+  unsigned long ainit_priority, binit_priority;
 
   switch (sort)
     {
     default:
       abort ();
 
+    case by_init_priority:
+      ainit_priority
+       = get_init_priority (bfd_get_section_name (asec->owner, asec));
+      binit_priority
+       = get_init_priority (bfd_get_section_name (bsec->owner, bsec));
+      if (ainit_priority == 0 || binit_priority == 0)
+       goto sort_by_name;
+      ret = ainit_priority - binit_priority;
+      if (ret)
+       break;
+      else
+       goto sort_by_name;
+
     case by_alignment_name:
       ret = (bfd_section_alignment (bsec->owner, bsec)
             - bfd_section_alignment (asec->owner, asec));
@@ -383,6 +446,7 @@ compare_section (sort_type sort, asection *asec, asection *bsec)
       /* Fall through.  */
 
     case by_name:
+sort_by_name:
       ret = strcmp (bfd_get_section_name (asec->owner, asec),
                    bfd_get_section_name (bsec->owner, bsec));
       break;
@@ -444,15 +508,18 @@ output_section_callback_fast (lang_wild_statement_type *ptr,
                              struct wildcard_list *sec,
                              asection *section,
                              lang_input_statement_type *file,
-                             void *output ATTRIBUTE_UNUSED)
+                             void *output)
 {
   lang_section_bst_type *node;
   lang_section_bst_type **tree;
+  lang_output_section_statement_type *os;
 
-  if (unique_section_p (section))
+  os = (lang_output_section_statement_type *) output;
+
+  if (unique_section_p (section, os))
     return;
 
-  node = xmalloc (sizeof (lang_section_bst_type));
+  node = (lang_section_bst_type *) xmalloc (sizeof (lang_section_bst_type));
   node->left = 0;
   node->right = 0;
   node->section = section;
@@ -813,7 +880,9 @@ walk_wild_file (lang_wild_statement_type *s,
             lang_input_statement.  */
          if (member->usrdata != NULL)
            {
-             walk_wild_section (s, member->usrdata, callback, data);
+             walk_wild_section (s,
+                                 (lang_input_statement_type *) member->usrdata,
+                                 callback, data);
            }
 
          member = bfd_openr_next_archived_file (f->the_bfd, member);
@@ -863,9 +932,10 @@ walk_wild (lang_wild_statement_type *s, callback_t callback, void *data)
 }
 
 /* lang_for_each_statement walks the parse tree and calls the provided
-   function for each node.  */
+   function for each node, except those inside output section statements
+   with constraint set to -1.  */
 
-static void
+void
 lang_for_each_statement_worker (void (*func) (lang_statement_union_type *),
                                lang_statement_union_type *s)
 {
@@ -879,8 +949,9 @@ lang_for_each_statement_worker (void (*func) (lang_statement_union_type *),
          lang_for_each_statement_worker (func, constructor_list.head);
          break;
        case lang_output_section_statement_enum:
-         lang_for_each_statement_worker
-           (func, s->output_section_statement.children.head);
+         if (s->output_section_statement.constraint != -1)
+           lang_for_each_statement_worker
+             (func, s->output_section_statement.children.head);
          break;
        case lang_wild_statement_enum:
          lang_for_each_statement_worker (func,
@@ -949,13 +1020,13 @@ new_statement (enum statement_enum type,
               size_t size,
               lang_statement_list_type *list)
 {
-  lang_statement_union_type *new;
+  lang_statement_union_type *new_stmt;
 
-  new = stat_alloc (size);
-  new->header.type = type;
-  new->header.next = NULL;
-  lang_statement_append (list, new, &new->header.next);
-  return new;
+  new_stmt = (lang_statement_union_type *) stat_alloc (size);
+  new_stmt->header.type = type;
+  new_stmt->header.next = NULL;
+  lang_statement_append (list, new_stmt, &new_stmt->header.next);
+  return new_stmt;
 }
 
 /* Build a new input file node for the language.  There are several
@@ -976,10 +1047,11 @@ new_afile (const char *name,
   lang_input_statement_type *p;
 
   if (add_to_list)
-    p = new_stat (lang_input_statement, stat_ptr);
+    p = (lang_input_statement_type *) new_stat (lang_input_statement, stat_ptr);
   else
     {
-      p = stat_alloc (sizeof (lang_input_statement_type));
+      p = (lang_input_statement_type *)
+          stat_alloc (sizeof (lang_input_statement_type));
       p->header.type = lang_input_statement_enum;
       p->header.next = NULL;
     }
@@ -999,7 +1071,7 @@ new_afile (const char *name,
     {
     case lang_input_file_is_symbols_only_enum:
       p->filename = name;
-      p->is_archive = FALSE;
+      p->maybe_archive = FALSE;
       p->real = TRUE;
       p->local_sym_name = name;
       p->just_syms_flag = TRUE;
@@ -1007,14 +1079,14 @@ new_afile (const char *name,
       break;
     case lang_input_file_is_fake_enum:
       p->filename = name;
-      p->is_archive = FALSE;
+      p->maybe_archive = FALSE;
       p->real = FALSE;
       p->local_sym_name = name;
       p->just_syms_flag = FALSE;
       p->search_dirs_flag = FALSE;
       break;
     case lang_input_file_is_l_enum:
-      p->is_archive = TRUE;
+      p->maybe_archive = TRUE;
       p->filename = name;
       p->real = TRUE;
       p->local_sym_name = concat ("-l", name, (const char *) NULL);
@@ -1023,7 +1095,7 @@ new_afile (const char *name,
       break;
     case lang_input_file_is_marker_enum:
       p->filename = name;
-      p->is_archive = FALSE;
+      p->maybe_archive = FALSE;
       p->real = FALSE;
       p->local_sym_name = name;
       p->just_syms_flag = FALSE;
@@ -1032,7 +1104,7 @@ new_afile (const char *name,
     case lang_input_file_is_search_file_enum:
       p->sysrooted = ldlang_sysrooted_script;
       p->filename = name;
-      p->is_archive = FALSE;
+      p->maybe_archive = FALSE;
       p->real = TRUE;
       p->local_sym_name = name;
       p->just_syms_flag = FALSE;
@@ -1040,7 +1112,7 @@ new_afile (const char *name,
       break;
     case lang_input_file_is_file_enum:
       p->filename = name;
-      p->is_archive = FALSE;
+      p->maybe_archive = FALSE;
       p->real = TRUE;
       p->local_sym_name = name;
       p->just_syms_flag = FALSE;
@@ -1053,10 +1125,16 @@ new_afile (const char *name,
   p->next_real_file = NULL;
   p->next = NULL;
   p->dynamic = config.dynamic_link;
-  p->add_needed = add_needed;
-  p->as_needed = as_needed;
+  p->add_DT_NEEDED_for_dynamic = add_DT_NEEDED_for_dynamic;
+  p->add_DT_NEEDED_for_regular = add_DT_NEEDED_for_regular;
   p->whole_archive = whole_archive;
   p->loaded = FALSE;
+  p->missing_file = FALSE;
+#ifdef ENABLE_PLUGINS
+  p->claimed = FALSE;
+  p->claim_archive = FALSE;
+#endif /* ENABLE_PLUGINS */
+
   lang_statement_append (&input_file_chain,
                         (lang_statement_union_type *) p,
                         &p->next_real_file);
@@ -1094,7 +1172,8 @@ output_section_statement_newfunc (struct bfd_hash_entry *entry,
 
   if (entry == NULL)
     {
-      entry = bfd_hash_allocate (table, sizeof (*ret));
+      entry = (struct bfd_hash_entry *) bfd_hash_allocate (table,
+                                                           sizeof (*ret));
       if (entry == NULL)
        return entry;
     }
@@ -1204,7 +1283,7 @@ lang_finish (void)
   already been created.  If we are not inside a MEMORY block it is
   dubious to use an undeclared region name (except DEFAULT_MEMORY_REGION)
   and so we issue a warning.
-  
+
   Each region has at least one name.  The first name is either
   DEFAULT_MEMORY_REGION or the name given in the MEMORY block.  You can add
   alias names to an existing region within a script with
@@ -1220,7 +1299,7 @@ lang_memory_region_lookup (const char *const name, bfd_boolean create)
 {
   lang_memory_region_name *n;
   lang_memory_region_type *r;
-  lang_memory_region_type *new;
+  lang_memory_region_type *new_region;
 
   /* NAME is NULL for LMA memspecs if no region was specified.  */
   if (name == NULL)
@@ -1239,23 +1318,24 @@ lang_memory_region_lookup (const char *const name, bfd_boolean create)
   if (!create && strcmp (name, DEFAULT_MEMORY_REGION))
     einfo (_("%P:%S: warning: memory region `%s' not declared\n"), name);
 
-  new = stat_alloc (sizeof (lang_memory_region_type));
+  new_region = (lang_memory_region_type *)
+      stat_alloc (sizeof (lang_memory_region_type));
 
-  new->name_list.name = xstrdup (name);
-  new->name_list.next = NULL;
-  new->next = NULL;
-  new->origin = 0;
-  new->length = ~(bfd_size_type) 0;
-  new->current = 0;
-  new->last_os = NULL;
-  new->flags = 0;
-  new->not_flags = 0;
-  new->had_full_message = FALSE;
+  new_region->name_list.name = xstrdup (name);
+  new_region->name_list.next = NULL;
+  new_region->next = NULL;
+  new_region->origin = 0;
+  new_region->length = ~(bfd_size_type) 0;
+  new_region->current = 0;
+  new_region->last_os = NULL;
+  new_region->flags = 0;
+  new_region->not_flags = 0;
+  new_region->had_full_message = FALSE;
 
-  *lang_memory_region_list_tail = new;
-  lang_memory_region_list_tail = &new->next;
+  *lang_memory_region_list_tail = new_region;
+  lang_memory_region_list_tail = &new_region->next;
 
-  return new;
+  return new_region;
 }
 
 void
@@ -1294,7 +1374,7 @@ lang_memory_region_alias (const char * alias, const char * region_name)
            alias);
 
   /* Add alias to region name list.  */
-  n = stat_alloc (sizeof (lang_memory_region_name));
+  n = (lang_memory_region_name *) stat_alloc (sizeof (lang_memory_region_name));
   n->name = xstrdup (alias);
   n->next = region->name_list.next;
   region->name_list.next = n;
@@ -1502,8 +1582,14 @@ lang_output_section_find_by_flags (const asection *sec,
            }
          flags ^= sec->flags;
          if (!(flags & (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD
-                        | SEC_READONLY))
-             && !(look->flags & (SEC_SMALL_DATA | SEC_THREAD_LOCAL)))
+                        | SEC_READONLY | SEC_SMALL_DATA))
+             || (!(flags & (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD
+                            | SEC_READONLY))
+                 && !(look->flags & SEC_SMALL_DATA))
+             || (!(flags & (SEC_THREAD_LOCAL | SEC_ALLOC))
+                 && (look->flags & SEC_THREAD_LOCAL)
+                 && (!(flags & SEC_LOAD)
+                     || (look->flags & SEC_LOAD))))
            found = look;
        }
     }
@@ -1715,8 +1801,8 @@ lang_insert_orphan (asection *s,
 
   os_tail = ((lang_output_section_statement_type **)
             lang_output_section_statement.tail);
-  os = lang_enter_output_section_statement (secname, address, 0, NULL, NULL,
-                                           NULL, constraint);
+  os = lang_enter_output_section_statement (secname, address, normal_section,
+                                            NULL, NULL, NULL, constraint);
 
   ps = NULL;
   if (config.build_constructors && *os_tail == os)
@@ -1736,7 +1822,7 @@ lang_insert_orphan (asection *s,
          sprintf (symname + (symname[0] != 0), "__start_%s", secname);
          e_align = exp_unop (ALIGN_K,
                              exp_intop ((bfd_vma) 1 << s->alignment_power));
-         lang_add_assignment (exp_assop ('=', ".", e_align));
+         lang_add_assignment (exp_assign (".", e_align));
          lang_add_assignment (exp_provide (symname,
                                            exp_unop (ABSOLUTE,
                                                      exp_nameop (NAME, ".")),
@@ -1748,7 +1834,20 @@ lang_insert_orphan (asection *s,
     add_child = &os->children;
   lang_add_section (add_child, s, os);
 
-  lang_leave_output_section_statement (0, "*default*", NULL, NULL);
+  if (after && (s->flags & (SEC_LOAD | SEC_ALLOC)) != 0)
+    {
+      const char *region = (after->region
+                           ? after->region->name_list.name
+                           : DEFAULT_MEMORY_REGION);
+      const char *lma_region = (after->lma_region
+                               ? after->lma_region->name_list.name
+                               : NULL);
+      lang_leave_output_section_statement (NULL, region, after->phdrs,
+                                          lma_region);
+    }
+  else
+    lang_leave_output_section_statement (NULL, DEFAULT_MEMORY_REGION, NULL,
+                                        NULL);
 
   if (ps != NULL && *ps == '\0')
     {
@@ -1997,6 +2096,7 @@ init_map_userdata (bfd *abfd ATTRIBUTE_UNUSED,
   ASSERT (get_userdata (sec) == NULL);
   get_userdata (sec) = new_data;
   new_data->map_symbol_def_tail = &new_data->map_symbol_def_head;
+  new_data->map_symbol_def_count = 0;
 }
 
 static bfd_boolean
@@ -2009,21 +2109,24 @@ sort_def_symbol (struct bfd_link_hash_entry *hash_entry,
       struct fat_user_section_struct *ud;
       struct map_symbol_def *def;
 
-      ud = get_userdata (hash_entry->u.def.section);
+      ud = (struct fat_user_section_struct *)
+          get_userdata (hash_entry->u.def.section);
       if  (! ud)
        {
          /* ??? What do we have to do to initialize this beforehand?  */
          /* The first time we get here is bfd_abs_section...  */
          init_map_userdata (0, hash_entry->u.def.section, 0);
-         ud = get_userdata (hash_entry->u.def.section);
+         ud = (struct fat_user_section_struct *)
+              get_userdata (hash_entry->u.def.section);
        }
       else if  (!ud->map_symbol_def_tail)
        ud->map_symbol_def_tail = &ud->map_symbol_def_head;
 
-      def = obstack_alloc (&map_obstack, sizeof *def);
+      def = (struct map_symbol_def *) obstack_alloc (&map_obstack, sizeof *def);
       def->entry = hash_entry;
       *(ud->map_symbol_def_tail) = def;
       ud->map_symbol_def_tail = &def->next;
+      ud->map_symbol_def_count++;
     }
   return TRUE;
 }
@@ -2031,12 +2134,8 @@ sort_def_symbol (struct bfd_link_hash_entry *hash_entry,
 /* Initialize an output section.  */
 
 static void
-init_os (lang_output_section_statement_type *s, asection *isec,
-        flagword flags)
+init_os (lang_output_section_statement_type *s, flagword flags)
 {
-  if (s->bfd_section != NULL)
-    return;
-
   if (strcmp (s->name, DISCARD_SECTION_NAME) == 0)
     einfo (_("%P%F: Illegal use of `%s' section\n"), DISCARD_SECTION_NAME);
 
@@ -2055,10 +2154,10 @@ init_os (lang_output_section_statement_type *s, asection *isec,
 
   if (!link_info.reduce_memory_overheads)
     {
-      fat_section_userdata_type *new
-       = stat_alloc (sizeof (fat_section_userdata_type));
-      memset (new, 0, sizeof (fat_section_userdata_type));
-      get_userdata (s->bfd_section) = new;
+      fat_section_userdata_type *new_userdata = (fat_section_userdata_type *)
+        stat_alloc (sizeof (fat_section_userdata_type));
+      memset (new_userdata, 0, sizeof (fat_section_userdata_type));
+      get_userdata (s->bfd_section) = new_userdata;
     }
 
   /* If there is a base address, make sure that any sections it might
@@ -2072,11 +2171,6 @@ init_os (lang_output_section_statement_type *s, asection *isec,
   /* If supplied an alignment, set it.  */
   if (s->section_alignment != -1)
     s->bfd_section->alignment_power = s->section_alignment;
-
-  if (isec)
-    bfd_init_private_section_data (isec->owner, isec,
-                                  link_info.output_bfd, s->bfd_section,
-                                  &link_info);
 }
 
 /* Make sure that all output sections mentioned in an expression are
@@ -2122,7 +2216,7 @@ exp_init_os (etree_type *exp)
 
            os = lang_output_section_find (exp->name.name);
            if (os != NULL && os->bfd_section == NULL)
-             init_os (os, NULL, 0);
+             init_os (os, 0);
          }
        }
       break;
@@ -2135,7 +2229,7 @@ exp_init_os (etree_type *exp)
 static void
 section_already_linked (bfd *abfd, asection *sec, void *data)
 {
-  lang_input_statement_type *entry = data;
+  lang_input_statement_type *entry = (lang_input_statement_type *) data;
 
   /* If we are only reading symbols from this object, then we want to
      discard all sections.  */
@@ -2146,7 +2240,12 @@ section_already_linked (bfd *abfd, asection *sec, void *data)
     }
 
   if (!(abfd->flags & DYNAMIC))
-    bfd_section_already_linked (abfd, sec, &link_info);
+    {
+      struct already_linked linked;
+      linked.comdat_key = NULL;
+      linked.u.sec = sec;
+      bfd_section_already_linked (abfd, &linked, &link_info);
+    }
 }
 \f
 /* The wild routines.
@@ -2165,7 +2264,11 @@ lang_add_section (lang_statement_list_type *ptr,
                  lang_output_section_statement_type *output)
 {
   flagword flags = section->flags;
+  struct flag_info *sflag_info = section->section_flag_info;
+
   bfd_boolean discard;
+  lang_input_section_type *new_section;
+  bfd *abfd = link_info.output_bfd;
 
   /* Discard sections marked with SEC_EXCLUDE.  */
   discard = (flags & SEC_EXCLUDE) != 0;
@@ -2191,113 +2294,135 @@ lang_add_section (lang_statement_list_type *ptr,
       return;
     }
 
-  if (section->output_section == NULL)
+  if (sflag_info)
     {
-      bfd_boolean first;
-      lang_input_section_type *new;
-      flagword flags;
-
-      flags = section->flags;
+      if (sflag_info->flags_initialized == FALSE)
+       bfd_lookup_section_flags (&link_info, sflag_info);
 
-      /* We don't copy the SEC_NEVER_LOAD flag from an input section
-        to an output section, because we want to be able to include a
-        SEC_NEVER_LOAD section in the middle of an otherwise loaded
-        section (I don't know why we want to do this, but we do).
-        build_link_order in ldwrite.c handles this case by turning
-        the embedded SEC_NEVER_LOAD section into a fill.  */
+      if (sflag_info->only_with_flags != 0
+         && sflag_info->not_with_flags != 0
+          && ((sflag_info->not_with_flags & flags) != 0
+              || (sflag_info->only_with_flags & flags)
+                   != sflag_info->only_with_flags))
+       return;
 
-      flags &= ~ SEC_NEVER_LOAD;
+      if (sflag_info->only_with_flags != 0
+         && (sflag_info->only_with_flags & flags)
+              != sflag_info->only_with_flags)
+       return;
 
-      switch (output->sectype)
-       {
-       case normal_section:
-       case overlay_section:
-         break;
-       case noalloc_section:
-         flags &= ~SEC_ALLOC;
-         break;
-       case noload_section:
-         flags &= ~SEC_LOAD;
-         flags |= SEC_NEVER_LOAD;
-         break;
-       }
+      if (sflag_info->not_with_flags != 0
+          && (sflag_info->not_with_flags & flags) != 0)
+       return;
+    }
 
-      if (output->bfd_section == NULL)
-       init_os (output, section, flags);
+  if (section->output_section != NULL)
+    return;
 
-      first = ! output->bfd_section->linker_has_input;
-      output->bfd_section->linker_has_input = 1;
+  /* We don't copy the SEC_NEVER_LOAD flag from an input section
+     to an output section, because we want to be able to include a
+     SEC_NEVER_LOAD section in the middle of an otherwise loaded
+     section (I don't know why we want to do this, but we do).
+     build_link_order in ldwrite.c handles this case by turning
+     the embedded SEC_NEVER_LOAD section into a fill.  */
+  flags &= ~ SEC_NEVER_LOAD;
 
-      if (!link_info.relocatable
-         && !stripped_excluded_sections)
-       {
-         asection *s = output->bfd_section->map_tail.s;
-         output->bfd_section->map_tail.s = section;
-         section->map_head.s = NULL;
-         section->map_tail.s = s;
-         if (s != NULL)
-           s->map_head.s = section;
-         else
-           output->bfd_section->map_head.s = section;
-       }
+  /* If final link, don't copy the SEC_LINK_ONCE flags, they've
+     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.  */
 
-      /* Add a section reference to the list.  */
-      new = new_stat (lang_input_section, ptr);
+  if (!link_info.relocatable)
+    flags &= ~(SEC_LINK_ONCE | SEC_LINK_DUPLICATES | SEC_RELOC);
 
-      new->section = section;
-      section->output_section = output->bfd_section;
-
-      /* If final link, don't copy the SEC_LINK_ONCE flags, they've
-        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.  */
+  switch (output->sectype)
+    {
+    case normal_section:
+    case overlay_section:
+      break;
+    case noalloc_section:
+      flags &= ~SEC_ALLOC;
+      break;
+    case noload_section:
+      flags &= ~SEC_LOAD;
+      flags |= SEC_NEVER_LOAD;
+      /* Unfortunately GNU ld has managed to evolve two different
+        meanings to NOLOAD in scripts.  ELF gets a .bss style noload,
+        alloc, no contents section.  All others get a noload, noalloc
+        section.  */
+      if (bfd_get_flavour (link_info.output_bfd) == bfd_target_elf_flavour)
+       flags &= ~SEC_HAS_CONTENTS;
+      else
+       flags &= ~SEC_ALLOC;
+      break;
+    }
 
-      if (! link_info.relocatable)
-       flags &= ~ (SEC_LINK_ONCE | SEC_LINK_DUPLICATES);
+  if (output->bfd_section == NULL)
+    init_os (output, flags);
 
-      /* If this is not the first input section, and the SEC_READONLY
-        flag is not currently set, then don't set it just because the
-        input section has it set.  */
+  /* If SEC_READONLY is not set in the input section, then clear
+     it from the output section.  */
+  output->bfd_section->flags &= flags | ~SEC_READONLY;
 
-      if (! first && (output->bfd_section->flags & SEC_READONLY) == 0)
-       flags &= ~ SEC_READONLY;
+  if (output->bfd_section->linker_has_input)
+    {
+      /* Only set SEC_READONLY flag on the first input section.  */
+      flags &= ~ SEC_READONLY;
 
       /* Keep SEC_MERGE and SEC_STRINGS only if they are the same.  */
-      if (! first
-         && ((output->bfd_section->flags & (SEC_MERGE | SEC_STRINGS))
-             != (flags & (SEC_MERGE | SEC_STRINGS))
-             || ((flags & SEC_MERGE)
-                 && output->bfd_section->entsize != section->entsize)))
+      if ((output->bfd_section->flags & (SEC_MERGE | SEC_STRINGS))
+         != (flags & (SEC_MERGE | SEC_STRINGS))
+         || ((flags & SEC_MERGE) != 0
+             && output->bfd_section->entsize != section->entsize))
        {
          output->bfd_section->flags &= ~ (SEC_MERGE | SEC_STRINGS);
          flags &= ~ (SEC_MERGE | SEC_STRINGS);
        }
+    }
+  output->bfd_section->flags |= flags;
 
-      output->bfd_section->flags |= flags;
-
-      if (flags & SEC_MERGE)
+  if (!output->bfd_section->linker_has_input)
+    {
+      output->bfd_section->linker_has_input = 1;
+      /* This must happen after flags have been updated.  The output
+        section may have been created before we saw its first input
+        section, eg. for a data statement.  */
+      bfd_init_private_section_data (section->owner, section,
+                                    link_info.output_bfd,
+                                    output->bfd_section,
+                                    &link_info);
+      if ((flags & SEC_MERGE) != 0)
        output->bfd_section->entsize = section->entsize;
+    }
 
-      /* If SEC_READONLY is not set in the input section, then clear
-        it from the output section.  */
-      if ((section->flags & SEC_READONLY) == 0)
-       output->bfd_section->flags &= ~SEC_READONLY;
+  if ((flags & SEC_TIC54X_BLOCK) != 0
+      && bfd_get_arch (section->owner) == bfd_arch_tic54x)
+    {
+      /* FIXME: This value should really be obtained from the bfd...  */
+      output->block_value = 128;
+    }
 
-      /* Copy over SEC_SMALL_DATA.  */
-      if (section->flags & SEC_SMALL_DATA)
-       output->bfd_section->flags |= SEC_SMALL_DATA;
+  if (section->alignment_power > output->bfd_section->alignment_power)
+    output->bfd_section->alignment_power = section->alignment_power;
 
-      if (section->alignment_power > output->bfd_section->alignment_power)
-       output->bfd_section->alignment_power = section->alignment_power;
+  section->output_section = output->bfd_section;
 
-      if (bfd_get_arch (section->owner) == bfd_arch_tic54x
-         && (section->flags & SEC_TIC54X_BLOCK) != 0)
-       {
-         output->bfd_section->flags |= SEC_TIC54X_BLOCK;
-         /* FIXME: This value should really be obtained from the bfd...  */
-         output->block_value = 128;
-       }
+  if (!link_info.relocatable
+      && !stripped_excluded_sections)
+    {
+      asection *s = output->bfd_section->map_tail.s;
+      output->bfd_section->map_tail.s = section;
+      section->map_head.s = NULL;
+      section->map_tail.s = s;
+      if (s != NULL)
+       s->map_head.s = section;
+      else
+       output->bfd_section->map_head.s = section;
     }
+
+  /* Add a section reference to the list.  */
+  new_section = new_stat (lang_input_section, ptr);
+  new_section->section = section;
 }
 
 /* Handle wildcard sorting.  This returns the lang_input_section which
@@ -2311,14 +2436,12 @@ wild_sort (lang_wild_statement_type *wild,
           lang_input_statement_type *file,
           asection *section)
 {
-  const char *section_name;
   lang_statement_union_type *l;
 
   if (!wild->filenames_sorted
       && (sec == NULL || sec->spec.sorted == none))
     return NULL;
 
-  section_name = bfd_get_section_name (file->the_bfd, section);
   for (l = wild->children.head; l != NULL; l = l->header.next)
     {
       lang_input_section_type *ls;
@@ -2364,7 +2487,7 @@ wild_sort (lang_wild_statement_type *wild,
              la = FALSE;
            }
 
-         i = strcmp (fn, ln);
+         i = filename_cmp (fn, ln);
          if (i > 0)
            continue;
          else if (i < 0)
@@ -2377,7 +2500,7 @@ wild_sort (lang_wild_statement_type *wild,
              if (la)
                ln = ls->section->owner->filename;
 
-             i = strcmp (fn, ln);
+             i = filename_cmp (fn, ln);
              if (i > 0)
                continue;
              else if (i < 0)
@@ -2407,9 +2530,12 @@ output_section_callback (lang_wild_statement_type *ptr,
                         void *output)
 {
   lang_statement_union_type *before;
+  lang_output_section_statement_type *os;
+
+  os = (lang_output_section_statement_type *) output;
 
   /* Exclude sections that match UNIQUE_SECTION_LIST.  */
-  if (unique_section_p (section))
+  if (unique_section_p (section, os))
     return;
 
   before = wild_sort (ptr, sec, file, section);
@@ -2420,16 +2546,14 @@ output_section_callback (lang_wild_statement_type *ptr,
      of the current list.  */
 
   if (before == NULL)
-    lang_add_section (&ptr->children, section,
-                     (lang_output_section_statement_type *) output);
+    lang_add_section (&ptr->children, section, os);
   else
     {
       lang_statement_list_type list;
       lang_statement_union_type **pp;
 
       lang_list_init (&list);
-      lang_add_section (&list, section,
-                       (lang_output_section_statement_type *) output);
+      lang_add_section (&list, section, os);
 
       /* If we are discarding the section, LIST.HEAD will
         be NULL.  */
@@ -2456,14 +2580,18 @@ check_section_callback (lang_wild_statement_type *ptr ATTRIBUTE_UNUSED,
                        struct wildcard_list *sec ATTRIBUTE_UNUSED,
                        asection *section,
                        lang_input_statement_type *file ATTRIBUTE_UNUSED,
-                       void *data)
+                       void *output)
 {
+  lang_output_section_statement_type *os;
+
+  os = (lang_output_section_statement_type *) output;
+
   /* Exclude sections that match UNIQUE_SECTION_LIST.  */
-  if (unique_section_p (section))
+  if (unique_section_p (section, os))
     return;
 
   if (section->output_section == NULL && (section->flags & SEC_READONLY) == 0)
-    ((lang_output_section_statement_type *) data)->all_input_readonly = FALSE;
+    os->all_input_readonly = FALSE;
 }
 
 /* This is passed a file name which must have been seen already and
@@ -2485,7 +2613,7 @@ lookup_name (const char *name)
       const char *filename = search->local_sym_name;
 
       if (filename != NULL
-         && strcmp (filename, name) == 0)
+         && filename_cmp (filename, name) == 0)
        break;
     }
 
@@ -2524,9 +2652,9 @@ add_excluded_libs (const char *list)
       end = strpbrk (p, ",:");
       if (end == NULL)
        end = p + strlen (p);
-      entry = xmalloc (sizeof (*entry));
+      entry = (struct excluded_lib *) xmalloc (sizeof (*entry));
       entry->next = excluded_libs;
-      entry->name = xmalloc (end - p + 1);
+      entry->name = (char *) xmalloc (end - p + 1);
       memcpy (entry->name, p, end - p);
       entry->name[end - p] = '\0';
       excluded_libs = entry;
@@ -2552,7 +2680,7 @@ check_excluded_libs (bfd *abfd)
          return;
        }
 
-      if (strncmp (lib->name, filename, len) == 0
+      if (filename_ncmp (lib->name, filename, len) == 0
          && (filename[len] == '\0'
              || (filename[len] == '.' && filename[len + 1] == 'a'
                  && filename[len + 2] == '\0')))
@@ -2578,12 +2706,18 @@ load_symbols (lang_input_statement_type *entry,
 
   ldfile_open_file (entry);
 
+  /* Do not process further if the file was missing.  */
+  if (entry->missing_file)
+    return TRUE;
+
   if (! bfd_check_format (entry->the_bfd, bfd_archive)
       && ! bfd_check_format_matches (entry->the_bfd, bfd_object, &matching))
     {
       bfd_error_type err;
       bfd_boolean save_ldlang_sysrooted_script;
-      bfd_boolean save_as_needed, save_add_needed;
+      bfd_boolean save_add_DT_NEEDED_for_regular;
+      bfd_boolean save_add_DT_NEEDED_for_dynamic;
+      bfd_boolean save_whole_archive;
 
       err = bfd_get_error ();
 
@@ -2614,10 +2748,12 @@ load_symbols (lang_input_statement_type *entry,
       push_stat_ptr (place);
       save_ldlang_sysrooted_script = ldlang_sysrooted_script;
       ldlang_sysrooted_script = entry->sysrooted;
-      save_as_needed = as_needed;
-      as_needed = entry->as_needed;
-      save_add_needed = add_needed;
-      add_needed = entry->add_needed;
+      save_add_DT_NEEDED_for_regular = add_DT_NEEDED_for_regular;
+      add_DT_NEEDED_for_regular = entry->add_DT_NEEDED_for_regular;
+      save_add_DT_NEEDED_for_dynamic = add_DT_NEEDED_for_dynamic;
+      add_DT_NEEDED_for_dynamic = entry->add_DT_NEEDED_for_dynamic;
+      save_whole_archive = whole_archive;
+      whole_archive = entry->whole_archive;
 
       ldfile_assumed_script = TRUE;
       parser_input = input_script;
@@ -2628,8 +2764,9 @@ load_symbols (lang_input_statement_type *entry,
       ldfile_assumed_script = FALSE;
 
       ldlang_sysrooted_script = save_ldlang_sysrooted_script;
-      as_needed = save_as_needed;
-      add_needed = save_add_needed;
+      add_DT_NEEDED_for_regular = save_add_DT_NEEDED_for_regular;
+      add_DT_NEEDED_for_dynamic = save_add_DT_NEEDED_for_dynamic;
+      whole_archive = save_whole_archive;
       pop_stat_ptr ();
 
       return TRUE;
@@ -2663,6 +2800,7 @@ load_symbols (lang_input_statement_type *entry,
 
          for (;;)
            {
+             bfd *subsbfd;
              member = bfd_openr_next_archived_file (entry->the_bfd, member);
 
              if (member == NULL)
@@ -2675,11 +2813,15 @@ load_symbols (lang_input_statement_type *entry,
                  loaded = FALSE;
                }
 
-             if (! ((*link_info.callbacks->add_archive_element)
-                    (&link_info, member, "--whole-archive")))
+             subsbfd = member;
+             if (!(*link_info.callbacks
+                   ->add_archive_element) (&link_info, member,
+                                           "--whole-archive", &subsbfd))
                abort ();
 
-             if (! bfd_link_add_symbols (member, &link_info))
+             /* Potentially, the add_archive_element hook may have set a
+                substitute BFD for us.  */
+             if (!bfd_link_add_symbols (subsbfd, &link_info))
                {
                  einfo (_("%F%B: could not read symbols: %E\n"), member);
                  loaded = FALSE;
@@ -2747,7 +2889,7 @@ wild (lang_wild_statement_type *s,
 static int
 get_target (const bfd_target *target, void *data)
 {
-  const char *sought = data;
+  const char *sought = (const char *) data;
 
   return strcmp (target->name, sought) == 0;
 }
@@ -2794,8 +2936,8 @@ name_compare (char *first, char *second)
   char *copy2;
   int result;
 
-  copy1 = xmalloc (strlen (first) + 1);
-  copy2 = xmalloc (strlen (second) + 1);
+  copy1 = (char *) xmalloc (strlen (first) + 1);
+  copy2 = (char *) xmalloc (strlen (second) + 1);
 
   /* Convert the names to lower case.  */
   stricpy (copy1, first);
@@ -2833,7 +2975,7 @@ static const bfd_target *winner;
 static int
 closest_target_match (const bfd_target *target, void *data)
 {
-  const bfd_target *original = data;
+  const bfd_target *original = (const bfd_target *) data;
 
   if (command_line.endian == ENDIAN_BIG
       && target->byteorder != BFD_ENDIAN_BIG)
@@ -2910,7 +3052,7 @@ lang_get_output_target (void)
 
   /* No - has the current target been set to something other than
      the default?  */
-  if (current_target != default_target)
+  if (current_target != default_target && current_target != NULL)
     return current_target;
 
   /* No - can we determine the format of the first input file?  */
@@ -3061,26 +3203,37 @@ init_opb (void)
 
 /* Open all the input files.  */
 
+enum open_bfd_mode
+  {
+    OPEN_BFD_NORMAL = 0,
+    OPEN_BFD_FORCE = 1,
+    OPEN_BFD_RESCAN = 2
+  };
+#ifdef ENABLE_PLUGINS
+static lang_input_statement_type *plugin_insert = NULL;
+#endif
+
 static void
-open_input_bfds (lang_statement_union_type *s, bfd_boolean force)
+open_input_bfds (lang_statement_union_type *s, enum open_bfd_mode mode)
 {
   for (; s != NULL; s = s->header.next)
     {
       switch (s->header.type)
        {
        case lang_constructors_statement_enum:
-         open_input_bfds (constructor_list.head, force);
+         open_input_bfds (constructor_list.head, mode);
          break;
        case lang_output_section_statement_enum:
-         open_input_bfds (s->output_section_statement.children.head, force);
+         open_input_bfds (s->output_section_statement.children.head, mode);
          break;
        case lang_wild_statement_enum:
          /* Maybe we should load the file's symbols.  */
-         if (s->wild_statement.filename
+         if ((mode & OPEN_BFD_RESCAN) == 0
+             && s->wild_statement.filename
              && !wildcardp (s->wild_statement.filename)
              && !archive_path (s->wild_statement.filename))
            lookup_name (s->wild_statement.filename);
-         open_input_bfds (s->wild_statement.children.head, force);
+         open_input_bfds (s->wild_statement.children.head, mode);
          break;
        case lang_group_statement_enum:
          {
@@ -3093,7 +3246,8 @@ open_input_bfds (lang_statement_union_type *s, bfd_boolean force)
            do
              {
                undefs = link_info.hash->undefs_tail;
-               open_input_bfds (s->group_statement.children.head, TRUE);
+               open_input_bfds (s->group_statement.children.head,
+                                mode | OPEN_BFD_FORCE);
              }
            while (undefs != link_info.hash->undefs_tail);
          }
@@ -3112,8 +3266,12 @@ open_input_bfds (lang_statement_union_type *s, bfd_boolean force)
              /* If we are being called from within a group, and this
                 is an archive which has already been searched, then
                 force it to be researched unless the whole archive
-                has been loaded already.  */
-             if (force
+                has been loaded already.  Do the same for a rescan.  */
+             if (mode != OPEN_BFD_NORMAL
+#ifdef ENABLE_PLUGINS
+                 && ((mode & OPEN_BFD_RESCAN) == 0
+                     || plugin_insert == NULL)
+#endif
                  && !s->input_statement.whole_archive
                  && s->input_statement.loaded
                  && bfd_check_format (s->input_statement.the_bfd,
@@ -3149,11 +3307,26 @@ open_input_bfds (lang_statement_union_type *s, bfd_boolean force)
                    }
                }
            }
+#ifdef ENABLE_PLUGINS
+         /* If we have found the point at which a plugin added new
+            files, clear plugin_insert to enable archive rescan.  */
+         if (&s->input_statement == plugin_insert)
+           plugin_insert = NULL;
+#endif
+         break;
+       case lang_assignment_statement_enum:
+         if (s->assignment_statement.exp->assign.hidden)
+           /* This is from a --defsym on the command line.  */
+           exp_fold_tree_no_dot (s->assignment_statement.exp);
          break;
        default:
          break;
        }
     }
+
+  /* Exit if any of the files were missing.  */
+  if (missing_file)
+    einfo ("%F");
 }
 
 /* Add a symbol to a hash of symbols used in DEFINED (NAME) expressions.  */
@@ -3246,18 +3419,19 @@ typedef struct bfd_sym_chain ldlang_undef_chain_list_type;
 #define ldlang_undef_chain_list_head entry_symbol.next
 
 void
-ldlang_add_undef (const char *const name)
+ldlang_add_undef (const char *const name, bfd_boolean cmdline)
 {
-  ldlang_undef_chain_list_type *new =
-    stat_alloc (sizeof (ldlang_undef_chain_list_type));
+  ldlang_undef_chain_list_type *new_undef;
 
-  new->next = ldlang_undef_chain_list_head;
-  ldlang_undef_chain_list_head = new;
+  undef_from_cmdline = undef_from_cmdline || cmdline;
+  new_undef = (ldlang_undef_chain_list_type *) stat_alloc (sizeof (*new_undef));
+  new_undef->next = ldlang_undef_chain_list_head;
+  ldlang_undef_chain_list_head = new_undef;
 
-  new->name = xstrdup (name);
+  new_undef->name = xstrdup (name);
 
   if (link_info.output_bfd != NULL)
-    insert_undefined (new->name);
+    insert_undefined (new_undef->name);
 }
 
 /* Insert NAME as undefined in the symbol table.  */
@@ -3399,10 +3573,11 @@ map_input_to_output_sections
   (lang_statement_union_type *s, const char *target,
    lang_output_section_statement_type *os)
 {
-  flagword flags;
-
   for (; s != NULL; s = s->header.next)
     {
+      lang_output_section_statement_type *tos;
+      flagword flags;
+
       switch (s->header.type)
        {
        case lang_wild_statement_enum:
@@ -3414,27 +3589,23 @@ map_input_to_output_sections
                                        os);
          break;
        case lang_output_section_statement_enum:
-         if (s->output_section_statement.constraint)
+         tos = &s->output_section_statement;
+         if (tos->constraint != 0)
            {
-             if (s->output_section_statement.constraint != ONLY_IF_RW
-                 && s->output_section_statement.constraint != ONLY_IF_RO)
+             if (tos->constraint != ONLY_IF_RW
+                 && tos->constraint != ONLY_IF_RO)
                break;
-             s->output_section_statement.all_input_readonly = TRUE;
-             check_input_sections (s->output_section_statement.children.head,
-                                   &s->output_section_statement);
-             if ((s->output_section_statement.all_input_readonly
-                  && s->output_section_statement.constraint == ONLY_IF_RW)
-                 || (!s->output_section_statement.all_input_readonly
-                     && s->output_section_statement.constraint == ONLY_IF_RO))
+             tos->all_input_readonly = TRUE;
+             check_input_sections (tos->children.head, tos);
+             if (tos->all_input_readonly != (tos->constraint == ONLY_IF_RO))
                {
-                 s->output_section_statement.constraint = -1;
+                 tos->constraint = -1;
                  break;
                }
            }
-
-         map_input_to_output_sections (s->output_section_statement.children.head,
+         map_input_to_output_sections (tos->children.head,
                                        target,
-                                       &s->output_section_statement);
+                                       tos);
          break;
        case lang_output_statement_enum:
          break;
@@ -3450,13 +3621,27 @@ map_input_to_output_sections
          /* Make sure that any sections mentioned in the expression
             are initialized.  */
          exp_init_os (s->data_statement.exp);
-         flags = SEC_HAS_CONTENTS;
-         /* The output section gets contents, and then we inspect for
-            any flags set in the input script which override any ALLOC.  */
-         if (!(os->flags & SEC_NEVER_LOAD))
-           flags |= SEC_ALLOC | SEC_LOAD;
+         /* The output section gets CONTENTS, ALLOC and LOAD, but
+            these may be overridden by the script.  */
+         flags = SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD;
+         switch (os->sectype)
+           {
+           case normal_section:
+           case overlay_section:
+             break;
+           case noalloc_section:
+             flags = SEC_HAS_CONTENTS;
+             break;
+           case noload_section:
+             if (bfd_get_flavour (link_info.output_bfd)
+                 == bfd_target_elf_flavour)
+               flags = SEC_NEVER_LOAD | SEC_ALLOC;
+             else
+               flags = SEC_NEVER_LOAD | SEC_HAS_CONTENTS;
+             break;
+           }
          if (os->bfd_section == NULL)
-           init_os (os, NULL, flags);
+           init_os (os, flags);
          else
            os->bfd_section->flags |= flags;
          break;
@@ -3468,11 +3653,11 @@ map_input_to_output_sections
        case lang_padding_statement_enum:
        case lang_input_statement_enum:
          if (os != NULL && os->bfd_section == NULL)
-           init_os (os, NULL, 0);
+           init_os (os, 0);
          break;
        case lang_assignment_statement_enum:
          if (os != NULL && os->bfd_section == NULL)
-           init_os (os, NULL, 0);
+           init_os (os, 0);
 
          /* Make sure that any sections mentioned in the assignment
             are initialized.  */
@@ -3491,13 +3676,18 @@ map_input_to_output_sections
          if (!s->address_statement.segment
              || !s->address_statement.segment->used)
            {
-             lang_output_section_statement_type *aos
-               = (lang_output_section_statement_lookup
-                  (s->address_statement.section_name, 0, TRUE));
-
-             if (aos->bfd_section == NULL)
-               init_os (aos, NULL, 0);
-             aos->addr_tree = s->address_statement.address;
+             const char *name = s->address_statement.section_name;
+
+             /* Create the output section statement here so that
+                orphans with a set address will be placed after other
+                script sections.  If we let the orphan placement code
+                place them in amongst other sections then the address
+                will affect following script sections, which is
+                likely to surprise naive users.  */
+             tos = lang_output_section_statement_lookup (name, 0, TRUE);
+             tos->addr_tree = s->address_statement.address;
+             if (tos->bfd_section == NULL)
+               init_os (tos, 0);
            }
          break;
        case lang_insert_statement_enum:
@@ -3803,12 +3993,12 @@ scan_for_self_assignment (const char * dst, etree_type * rhs)
   switch (rhs->type.node_class)
     {
     case etree_binary:
-      return scan_for_self_assignment (dst, rhs->binary.lhs)
-       ||   scan_for_self_assignment (dst, rhs->binary.rhs);
+      return (scan_for_self_assignment (dst, rhs->binary.lhs)
+             || scan_for_self_assignment (dst, rhs->binary.rhs));
 
     case etree_trinary:
-      return scan_for_self_assignment (dst, rhs->trinary.lhs)
-       ||   scan_for_self_assignment (dst, rhs->trinary.rhs);
+      return (scan_for_self_assignment (dst, rhs->trinary.lhs)
+             || scan_for_self_assignment (dst, rhs->trinary.rhs));
 
     case etree_assign:
     case etree_provided:
@@ -3846,6 +4036,7 @@ print_assignment (lang_assignment_statement_type *assignment,
   bfd_boolean is_dot;
   bfd_boolean computation_is_valid = TRUE;
   etree_type *tree;
+  asection *osec;
 
   for (i = 0; i < SECTION_NAME_MAP_LENGTH; i++)
     print_space ();
@@ -3862,10 +4053,13 @@ print_assignment (lang_assignment_statement_type *assignment,
 
       is_dot = (dst[0] == '.' && dst[1] == 0);
       tree = assignment->exp->assign.src;
-      computation_is_valid = is_dot || (scan_for_self_assignment (dst, tree) == FALSE);
+      computation_is_valid = is_dot || !scan_for_self_assignment (dst, tree);
     }
 
-  exp_fold_tree (tree, output_section->bfd_section, &print_dot);
+  osec = output_section->bfd_section;
+  if (osec == NULL)
+    osec = bfd_abs_section_ptr;
+  exp_fold_tree (tree, osec, &print_dot);
   if (expld.result.valid_p)
     {
       bfd_vma value;
@@ -3874,7 +4068,7 @@ print_assignment (lang_assignment_statement_type *assignment,
        {
          value = expld.result.value;
 
-         if (expld.result.section)
+         if (expld.result.section != NULL)
            value += expld.result.section->vma;
 
          minfo ("0x%V", value);
@@ -3890,9 +4084,8 @@ print_assignment (lang_assignment_statement_type *assignment,
          if (h)
            {
              value = h->u.def.value;
-
-             if (expld.result.section)
-               value += expld.result.section->vma;
+             value += h->u.def.section->output_section->vma;
+             value += h->u.def.section->output_offset;
 
              minfo ("[0x%V]", value);
            }
@@ -3928,7 +4121,7 @@ print_input_statement (lang_input_statement_type *statm)
 static bfd_boolean
 print_one_symbol (struct bfd_link_hash_entry *hash_entry, void *ptr)
 {
-  asection *sec = ptr;
+  asection *sec = (asection *) ptr;
 
   if ((hash_entry->type == bfd_link_hash_defined
        || hash_entry->type == bfd_link_hash_defweak)
@@ -3949,18 +4142,49 @@ print_one_symbol (struct bfd_link_hash_entry *hash_entry, void *ptr)
   return TRUE;
 }
 
+static int
+hash_entry_addr_cmp (const void *a, const void *b)
+{
+  const struct bfd_link_hash_entry *l = *(const struct bfd_link_hash_entry **)a;
+  const struct bfd_link_hash_entry *r = *(const struct bfd_link_hash_entry **)b;
+
+  if (l->u.def.value < r->u.def.value)
+    return -1;
+  else if (l->u.def.value > r->u.def.value)
+    return 1;
+  else
+    return 0;
+}
+
 static void
 print_all_symbols (asection *sec)
 {
-  struct fat_user_section_struct *ud = get_userdata (sec);
+  struct fat_user_section_struct *ud =
+      (struct fat_user_section_struct *) get_userdata (sec);
   struct map_symbol_def *def;
+  struct bfd_link_hash_entry **entries;
+  unsigned int i;
 
   if (!ud)
     return;
 
   *ud->map_symbol_def_tail = 0;
-  for (def = ud->map_symbol_def_head; def; def = def->next)
-    print_one_symbol (def->entry, sec);
+
+  /* Sort the symbols by address.  */
+  entries = (struct bfd_link_hash_entry **)
+      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;
+
+  qsort (entries, ud->map_symbol_def_count, sizeof (*entries),
+         hash_entry_addr_cmp);
+
+  /* Print the symbols.  */
+  for (i = 0; i < ud->map_symbol_def_count; i++)
+    print_one_symbol (entries[i], sec);
+
+  obstack_free (&map_obstack, entries);
 }
 
 /* Print information about an input section to the map file.  */
@@ -4385,7 +4609,8 @@ insert_pad (lang_statement_union_type **ptr,
   else
     {
       /* Make a new padding statement, linked into existing chain.  */
-      pad = stat_alloc (sizeof (lang_padding_statement_type));
+      pad = (lang_statement_union_type *)
+          stat_alloc (sizeof (lang_padding_statement_type));
       pad->header.next = *ptr;
       *ptr = pad;
       pad->header.type = lang_padding_statement_enum;
@@ -4474,9 +4699,8 @@ sort_sections_by_lma (const void *arg1, const void *arg2)
 }
 
 #define IGNORE_SECTION(s) \
-  ((s->flags & SEC_NEVER_LOAD) != 0                            \
-   || (s->flags & SEC_ALLOC) == 0                              \
-   || ((s->flags & SEC_THREAD_LOCAL) != 0                      \
+  ((s->flags & SEC_ALLOC) == 0                         \
+   || ((s->flags & SEC_THREAD_LOCAL) != 0              \
        && (s->flags & SEC_LOAD) == 0))
 
 /* Check to see if any allocated sections overlap with other allocated
@@ -4487,13 +4711,13 @@ sort_sections_by_lma (const void *arg1, const void *arg2)
 static void
 lang_check_section_addresses (void)
 {
-  asection *s, *os;
+  asection *s, *p;
   asection **sections, **spp;
   unsigned int count;
   bfd_vma s_start;
   bfd_vma s_end;
-  bfd_vma os_start;
-  bfd_vma os_end;
+  bfd_vma p_start;
+  bfd_vma p_end;
   bfd_size_type amt;
   lang_memory_region_type *m;
 
@@ -4501,15 +4725,14 @@ lang_check_section_addresses (void)
     return;
 
   amt = bfd_count_sections (link_info.output_bfd) * sizeof (asection *);
-  sections = xmalloc (amt);
+  sections = (asection **) xmalloc (amt);
 
   /* 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_NEVER_LOAD)
-         || !(s->flags & SEC_LOAD)
+      if (!(s->flags & SEC_LOAD)
          || !(s->flags & SEC_ALLOC)
          || s->size == 0)
        continue;
@@ -4526,24 +4749,29 @@ lang_check_section_addresses (void)
 
   spp = sections;
   s = *spp++;
-  s_start = bfd_section_lma (link_info.output_bfd, s);
+  s_start = s->lma;
   s_end = s_start + TO_ADDR (s->size) - 1;
   for (count--; count; count--)
     {
       /* We must check the sections' LMA addresses not their VMA
         addresses because overlay sections can have overlapping VMAs
         but they must have distinct LMAs.  */
-      os = s;
-      os_start = s_start;
-      os_end = s_end;
+      p = s;
+      p_start = s_start;
+      p_end = s_end;
       s = *spp++;
-      s_start = bfd_section_lma (link_info.output_bfd, s);
+      s_start = s->lma;
       s_end = s_start + TO_ADDR (s->size) - 1;
 
-      /* Look for an overlap.  */
-      if (s_end >= os_start && s_start <= os_end)
+      /* 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, os->name, os_start, os_end);
+              s->name, s_start, s_end, p->name, p_start, p_end);
     }
 
   free (sections);
@@ -4572,12 +4800,12 @@ static void
 os_region_check (lang_output_section_statement_type *os,
                 lang_memory_region_type *region,
                 etree_type *tree,
-                bfd_vma base)
+                bfd_vma rbase)
 {
   if ((region->current < region->origin
        || (region->current - region->origin > region->length))
       && ((region->current != region->origin + region->length)
-         || base == 0))
+         || rbase == 0))
     {
       if (tree != NULL)
        {
@@ -4604,16 +4832,17 @@ os_region_check (lang_output_section_statement_type *os,
 
 static bfd_vma
 lang_size_sections_1
-  (lang_statement_union_type *s,
+  (lang_statement_union_type **prev,
    lang_output_section_statement_type *output_section_statement,
-   lang_statement_union_type **prev,
    fill_type *fill,
    bfd_vma dot,
    bfd_boolean *relax,
    bfd_boolean check_regions)
 {
+  lang_statement_union_type *s;
+
   /* Size up the sections from their constituent parts.  */
-  for (; s != NULL; s = s->header.next)
+  for (s = *prev; s != NULL; s = s->header.next)
     {
       switch (s->header.type)
        {
@@ -4622,15 +4851,31 @@ lang_size_sections_1
            bfd_vma newdot, after;
            lang_output_section_statement_type *os;
            lang_memory_region_type *r;
+           int section_alignment = 0;
 
            os = &s->output_section_statement;
+           if (os->constraint == -1)
+             break;
+
+           /* FIXME: We shouldn't need to zero section vmas for ld -r
+              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_get_flavour (link_info.output_bfd)
+                   == bfd_target_coff_flavour))
+             os->addr_tree = exp_intop (0);
            if (os->addr_tree != NULL)
              {
                os->processed_vma = FALSE;
                exp_fold_tree (os->addr_tree, bfd_abs_section_ptr, &dot);
 
                if (expld.result.valid_p)
-                 dot = expld.result.value + expld.result.section->vma;
+                 {
+                   dot = expld.result.value;
+                   if (expld.result.section != NULL)
+                     dot += expld.result.section->vma;
+                 }
                else if (expld.phase != lang_mark_phase_enum)
                  einfo (_("%F%S: non constant or forward reference"
                           " address expression for section %s\n"),
@@ -4676,8 +4921,6 @@ lang_size_sections_1
              }
            else
              {
-               int align;
-
                if (os->addr_tree == NULL)
                  {
                    /* No address specified for this section, get one
@@ -4728,16 +4971,16 @@ lang_size_sections_1
                      }
 
                    newdot = os->region->current;
-                   align = os->bfd_section->alignment_power;
+                   section_alignment = os->bfd_section->alignment_power;
                  }
                else
-                 align = os->section_alignment;
+                 section_alignment = os->section_alignment;
 
                /* Align to what the section needs.  */
-               if (align > 0)
+               if (section_alignment > 0)
                  {
                    bfd_vma savedot = newdot;
-                   newdot = align_power (newdot, align);
+                   newdot = align_power (newdot, section_alignment);
 
                    if (newdot != savedot
                        && (config.warn_section_align
@@ -4748,17 +4991,12 @@ lang_size_sections_1
                             os->name, (unsigned long) (newdot - savedot));
                  }
 
-               /* PR 6945: Do not update the vma's of output sections
-                  when performing a relocatable link on COFF objects.  */
-               if (! link_info.relocatable
-                   || (bfd_get_flavour (link_info.output_bfd)
-                       != bfd_target_coff_flavour))
-                 bfd_set_section_vma (0, os->bfd_section, newdot);
+               bfd_set_section_vma (0, os->bfd_section, newdot);
 
                os->bfd_section->output_offset = 0;
              }
 
-           lang_size_sections_1 (os->children.head, os, &os->children.head,
+           lang_size_sections_1 (&os->children.head, os,
                                  os->fill, newdot, relax, check_regions);
 
            os->processed_vma = TRUE;
@@ -4798,8 +5036,8 @@ lang_size_sections_1
              {
                bfd_vma lma = os->lma_region->current;
 
-               if (os->section_alignment != -1)
-                 lma = align_power (lma, os->section_alignment);
+               if (section_alignment > 0)
+                 lma = align_power (lma, section_alignment);
                os->bfd_section->lma = lma;
              }
            else if (r->last_os != NULL
@@ -4840,8 +5078,8 @@ lang_size_sections_1
                    else
                      lma = dot + last->lma - last->vma;
 
-                   if (os->section_alignment != -1)
-                     lma = align_power (lma, os->section_alignment);
+                   if (section_alignment > 0)
+                     lma = align_power (lma, section_alignment);
                    os->bfd_section->lma = lma;
                  }
              }
@@ -4883,14 +5121,9 @@ lang_size_sections_1
            /* Update dot in the region ?
               We only do this if the section is going to be allocated,
               since unallocated sections do not contribute to the region's
-              overall size in memory.
-
-              If the SEC_NEVER_LOAD bit is not set, it will affect the
-              addresses of sections after it. We have to update
-              dot.  */
+              overall size in memory.  */
            if (os->region != NULL
-               && ((os->bfd_section->flags & SEC_NEVER_LOAD) == 0
-                   || (os->bfd_section->flags & (SEC_ALLOC | SEC_LOAD))))
+               && (os->bfd_section->flags & (SEC_ALLOC | SEC_LOAD)))
              {
                os->region->current = dot;
 
@@ -4914,9 +5147,8 @@ lang_size_sections_1
          break;
 
        case lang_constructors_statement_enum:
-         dot = lang_size_sections_1 (constructor_list.head,
+         dot = lang_size_sections_1 (&constructor_list.head,
                                      output_section_statement,
-                                     &s->wild_statement.children.head,
                                      fill, dot, relax, check_regions);
          break;
 
@@ -4973,9 +5205,8 @@ lang_size_sections_1
          break;
 
        case lang_wild_statement_enum:
-         dot = lang_size_sections_1 (s->wild_statement.children.head,
+         dot = lang_size_sections_1 (&s->wild_statement.children.head,
                                      output_section_statement,
-                                     &s->wild_statement.children.head,
                                      fill, dot, relax, check_regions);
          break;
 
@@ -4992,7 +5223,7 @@ lang_size_sections_1
          {
            asection *i;
 
-           i = (*prev)->input_section.section;
+           i = s->input_section.section;
            if (relax)
              {
                bfd_boolean again;
@@ -5078,8 +5309,11 @@ lang_size_sections_1
                    /* If dot is advanced, this implies that the section
                       should have space allocated to it, unless the
                       user has explicitly stated that the section
-                      should never be loaded.  */
-                   if (!(output_section_statement->flags & SEC_NEVER_LOAD))
+                      should not be allocated.  */
+                   if (output_section_statement->sectype != noalloc_section
+                       && (output_section_statement->sectype != noload_section
+                           || (bfd_get_flavour (link_info.output_bfd)
+                               == bfd_target_elf_flavour)))
                      output_section_statement->bfd_section->flags |= SEC_ALLOC;
                  }
                dot = newdot;
@@ -5105,9 +5339,8 @@ lang_size_sections_1
          break;
 
        case lang_group_statement_enum:
-         dot = lang_size_sections_1 (s->group_statement.children.head,
+         dot = lang_size_sections_1 (&s->group_statement.children.head,
                                      output_section_statement,
-                                     &s->group_statement.children.head,
                                      fill, dot, relax, check_regions);
          break;
 
@@ -5173,8 +5406,8 @@ void
 one_lang_size_sections_pass (bfd_boolean *relax, bfd_boolean check_regions)
 {
   lang_statement_iteration++;
-  lang_size_sections_1 (statement_list.head, abs_output_section,
-                       &statement_list.head, 0, 0, relax, check_regions);
+  lang_size_sections_1 (&statement_list.head, abs_output_section,
+                       0, 0, relax, check_regions);
 }
 
 void
@@ -5258,9 +5491,11 @@ lang_size_sections (bfd_boolean *relax, bfd_boolean check_regions)
          lang_reset_memory_regions ();
          one_lang_size_sections_pass (relax, check_regions);
        }
+      else
+       expld.dataseg.phase = exp_dataseg_done;
     }
-
-  expld.phase = lang_final_phase_enum;
+  else
+    expld.dataseg.phase = exp_dataseg_done;
 }
 
 /* Worker function for lang_do_assignments.  Recursiveness goes here.  */
@@ -5317,8 +5552,11 @@ lang_do_assignments_1 (lang_statement_union_type *s,
        case lang_data_statement_enum:
          exp_fold_tree (s->data_statement.exp, bfd_abs_section_ptr, &dot);
          if (expld.result.valid_p)
-           s->data_statement.value = (expld.result.value
-                                      + expld.result.section->vma);
+           {
+             s->data_statement.value = expld.result.value;
+             if (expld.result.section != NULL)
+               s->data_statement.value += expld.result.section->vma;
+           }
          else
            einfo (_("%F%P: invalid data statement\n"));
          {
@@ -5403,8 +5641,9 @@ lang_do_assignments_1 (lang_statement_union_type *s,
 }
 
 void
-lang_do_assignments (void)
+lang_do_assignments (lang_phase_type phase)
 {
+  expld.phase = phase;
   lang_statement_iteration++;
   lang_do_assignments_1 (statement_list.head, abs_output_section, NULL, 0);
 }
@@ -5431,7 +5670,7 @@ lang_set_startof (void)
       struct bfd_link_hash_entry *h;
 
       secname = bfd_get_section_name (link_info.output_bfd, s);
-      buf = xmalloc (10 + strlen (secname));
+      buf = (char *) xmalloc (10 + strlen (secname));
 
       sprintf (buf, ".startof.%s", secname);
       h = bfd_link_hash_lookup (link_info.hash, buf, FALSE, FALSE, TRUE);
@@ -5470,8 +5709,7 @@ lang_end (void)
   /* Force the user to specify a root when generating a relocatable with
      --gc-sections.  */
   if (link_info.gc_sections && link_info.relocatable
-      && (entry_symbol.name == NULL
-         && ldlang_undef_chain_list_head == NULL))
+      && !(entry_from_cmdline || undef_from_cmdline))
     einfo (_("%P%F: gc-sections requires either an entry or "
             "an undefined symbol\n"));
 
@@ -5567,6 +5805,11 @@ lang_check (void)
 
   for (file = file_chain.head; file != NULL; file = file->input_statement.next)
     {
+#ifdef ENABLE_PLUGINS
+      /* Don't check format of files claimed by plugin.  */
+      if (file->input_statement.claimed)
+       continue;
+#endif /* ENABLE_PLUGINS */
       input_bfd = file->input_statement.the_bfd;
       compatible
        = bfd_arch_get_compatible (input_bfd, link_info.output_bfd,
@@ -5792,7 +6035,8 @@ lang_place_orphans (void)
                  const char *name = s->name;
                  int constraint = 0;
 
-                 if (config.unique_orphan_sections || unique_section_p (s))
+                 if (config.unique_orphan_sections
+                     || unique_section_p (s, NULL))
                    constraint = SPECIAL;
 
                  if (!ldemul_place_orphan (s, name, constraint))
@@ -5801,6 +6045,10 @@ lang_place_orphans (void)
                      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, os);
                    }
                }
@@ -5978,10 +6226,11 @@ lang_enter_output_section_statement (const char *output_section_statement_name,
 void
 lang_final (void)
 {
-  lang_output_statement_type *new;
+  lang_output_statement_type *new_stmt;
+
+  new_stmt = new_stat (lang_output_statement, stat_ptr);
+  new_stmt->name = output_filename;
 
-  new = new_stat (lang_output_statement, stat_ptr);
-  new->name = output_filename;
 }
 
 /* Reset the current counters in the regions.  */
@@ -6072,6 +6321,10 @@ lang_gc_sections (void)
       LANG_FOR_EACH_INPUT_STATEMENT (f)
        {
          asection *sec;
+#ifdef ENABLE_PLUGINS
+         if (f->claimed)
+           continue;
+#endif
          for (sec = f->the_bfd->sections; sec != NULL; sec = sec->next)
            if ((sec->flags & SEC_DEBUGGING) == 0)
              sec->flags &= ~SEC_EXCLUDE;
@@ -6159,37 +6412,126 @@ lang_find_relro_sections (void)
 
 /* Relax all sections until bfd_relax_section gives up.  */
 
-static void
-relax_sections (void)
+void
+lang_relax_sections (bfd_boolean need_layout)
 {
-  /* Keep relaxing until bfd_relax_section gives up.  */
-  bfd_boolean relax_again;
-
-  link_info.relax_trip = -1;
-  do
+  if (RELAXATION_ENABLED)
     {
-      relax_again = FALSE;
-      link_info.relax_trip++;
+      /* We may need more than one relaxation pass.  */
+      int i = link_info.relax_pass;
+
+      /* The backend can use it to determine the current pass.  */
+      link_info.relax_pass = 0;
 
-      /* Note: pe-dll.c does something like this also.  If you find
-        you need to change this code, you probably need to change
-        pe-dll.c also.  DJ  */
+      while (i--)
+       {
+         /* Keep relaxing until bfd_relax_section gives up.  */
+         bfd_boolean relax_again;
+
+         link_info.relax_trip = -1;
+         do
+           {
+             link_info.relax_trip++;
 
-      /* Do all the assignments with our current guesses as to
-        section sizes.  */
-      lang_do_assignments ();
+             /* Note: pe-dll.c does something like this also.  If you find
+                you need to change this code, you probably need to change
+                pe-dll.c also.  DJ  */
+
+             /* Do all the assignments with our current guesses as to
+                section sizes.  */
+             lang_do_assignments (lang_assigning_phase_enum);
+
+             /* We must do this after lang_do_assignments, because it uses
+                size.  */
+             lang_reset_memory_regions ();
 
-      /* We must do this after lang_do_assignments, because it uses
-        size.  */
+             /* Perform another relax pass - this time we know where the
+                globals are, so can make a better guess.  */
+             relax_again = FALSE;
+             lang_size_sections (&relax_again, FALSE);
+           }
+         while (relax_again);
+
+         link_info.relax_pass++;
+       }
+      need_layout = TRUE;
+    }
+
+  if (need_layout)
+    {
+      /* Final extra sizing to report errors.  */
+      lang_do_assignments (lang_assigning_phase_enum);
       lang_reset_memory_regions ();
+      lang_size_sections (NULL, TRUE);
+    }
+}
+
+#ifdef ENABLE_PLUGINS
+/* Find the insert point for the plugin's replacement files.  We
+   place them after the first claimed real object file, or if the
+   first claimed object is an archive member, after the last real
+   object file immediately preceding the archive.  In the event
+   no objects have been claimed at all, we return the first dummy
+   object file on the list as the insert point; that works, but
+   the callee must be careful when relinking the file_chain as it
+   is not actually on that chain, only the statement_list and the
+   input_file list; in that case, the replacement files must be
+   inserted at the head of the file_chain.  */
 
-      /* Perform another relax pass - this time we know where the
-        globals are, so can make a better guess.  */
-      lang_size_sections (&relax_again, FALSE);
+static lang_input_statement_type *
+find_replacements_insert_point (void)
+{
+  lang_input_statement_type *claim1, *lastobject;
+  lastobject = &input_file_chain.head->input_statement;
+  for (claim1 = &file_chain.head->input_statement;
+       claim1 != NULL;
+       claim1 = &claim1->next->input_statement)
+    {
+      if (claim1->claimed)
+       return claim1->claim_archive ? lastobject : claim1;
+      /* Update lastobject if this is a real object file.  */
+      if (claim1->the_bfd && (claim1->the_bfd->my_archive == NULL))
+       lastobject = claim1;
     }
-  while (relax_again);
+  /* No files were claimed by the plugin.  Choose the last object
+     file found on the list (maybe the first, dummy entry) as the
+     insert point.  */
+  return lastobject;
+}
+
+/* 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.)  */
+
+static void
+lang_list_insert_after (lang_statement_list_type *destlist,
+                       lang_statement_list_type *srclist,
+                       lang_statement_union_type **field)
+{
+  *(srclist->tail) = *field;
+  *field = srclist->head;
+  if (destlist->tail == field)
+    destlist->tail = srclist->tail;
 }
 
+/* Detach new nodes added to DESTLIST since the time ORIGLIST
+   was taken as a copy of it and leave them in ORIGLIST.  */
+
+static void
+lang_list_remove_tail (lang_statement_list_type *destlist,
+                      lang_statement_list_type *origlist)
+{
+  union lang_statement_union **savetail;
+  /* Check that ORIGLIST really is an earlier state of DESTLIST.  */
+  ASSERT (origlist->head == destlist->head);
+  savetail = origlist->tail;
+  origlist->head = *(savetail);
+  origlist->tail = destlist->tail;
+  destlist->tail = savetail;
+  *savetail = NULL;
+}
+#endif /* ENABLE_PLUGINS */
+
 void
 lang_process (void)
 {
@@ -6213,7 +6555,65 @@ lang_process (void)
 
   /* Create a bfd for each input file.  */
   current_target = default_target;
-  open_input_bfds (statement_list.head, FALSE);
+  open_input_bfds (statement_list.head, OPEN_BFD_NORMAL);
+
+#ifdef ENABLE_PLUGINS
+  if (plugin_active_plugins_p ())
+    {
+      lang_statement_list_type added;
+      lang_statement_list_type files, inputfiles;
+
+      /* Now all files are read, let the plugin(s) decide if there
+        are any more to be added to the link before we call the
+        emulation's after_open hook.  We create a private list of
+        input statements for this purpose, which we will eventually
+        insert into the global statment 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"),
+              plugin_error_plugin ());
+      /* Open any newly added files, updating the file chains.  */
+      link_info.loading_lto_outputs = TRUE;
+      open_input_bfds (added.head, OPEN_BFD_NORMAL);
+      /* Restore the global list pointer now they have all been added.  */
+      lang_list_remove_tail (stat_ptr, &added);
+      /* And detach the fresh ends of the file lists.  */
+      lang_list_remove_tail (&file_chain, &files);
+      lang_list_remove_tail (&input_file_chain, &inputfiles);
+      /* Were any new files added?  */
+      if (added.head != NULL)
+       {
+         /* If so, we will insert them into the statement list immediately
+            after the first input file that was claimed by the plugin.  */
+         plugin_insert = find_replacements_insert_point ();
+         /* If a plugin adds input files without having claimed any, we
+            don't really have a good idea where to place them.  Just putting
+            them at the start or end of the list is liable to leave them
+            outside the crtbegin...crtend range.  */
+         ASSERT (plugin_insert != NULL);
+         /* Splice the new statement list into the old one.  */
+         lang_list_insert_after (stat_ptr, &added,
+                                 &plugin_insert->header.next);
+         /* Likewise for the file chains.  */
+         lang_list_insert_after (&input_file_chain, &inputfiles,
+                                 &plugin_insert->next_real_file);
+         /* We must be careful when relinking file_chain; we may need to
+            insert the new files at the head of the list if the insert
+            point chosen is the dummy first input file.  */
+         if (plugin_insert->filename)
+           lang_list_insert_after (&file_chain, &files, &plugin_insert->next);
+         else
+           lang_list_insert_after (&file_chain, &files, &file_chain.head);
+
+         /* Rescan archives in case new undefined symbols have appeared.  */
+         open_input_bfds (statement_list.head, OPEN_BFD_RESCAN);
+       }
+    }
+#endif /* ENABLE_PLUGINS */
 
   link_info.gc_sym_list = &entry_symbol;
   if (entry_symbol.name == NULL)
@@ -6249,6 +6649,7 @@ lang_process (void)
 
   /* Run through the contours of the script and attach input sections
      to the correct output sections.  */
+  lang_statement_iteration++;
   map_input_to_output_sections (statement_list.head, NULL, NULL);
 
   process_insert_statements ();
@@ -6291,31 +6692,10 @@ lang_process (void)
     lang_find_relro_sections ();
 
   /* Size up the sections.  */
-  lang_size_sections (NULL, !command_line.relax);
-
-  /* Now run around and relax if we can.  */
-  if (command_line.relax)
-    {
-      /* We may need more than one relaxation pass.  */
-      int i = link_info.relax_pass;
-
-      /* The backend can use it to determine the current pass.  */
-      link_info.relax_pass = 0;
-
-      while (i--)
-       {
-         relax_sections ();
-         link_info.relax_pass++;
-       }
-
-      /* Final extra sizing to report errors.  */
-      lang_do_assignments ();
-      lang_reset_memory_regions ();
-      lang_size_sections (NULL, TRUE);
-    }
+  lang_size_sections (NULL, ! RELAXATION_ENABLED);
 
   /* See if anything special should be done now we know how big
-     everything is.  */
+     everything is.  This is where relaxation is done.  */
   ldemul_after_allocation ();
 
   /* Fix any .startof. or .sizeof. symbols.  */
@@ -6323,8 +6703,7 @@ lang_process (void)
 
   /* Do all the assignments, now that we know the final resting places
      of all the symbols.  */
-
-  lang_do_assignments ();
+  lang_do_assignments (lang_final_phase_enum);
 
   ldemul_finish ();
 
@@ -6343,7 +6722,7 @@ lang_add_wild (struct wildcard_spec *filespec,
               bfd_boolean keep_sections)
 {
   struct wildcard_list *curr, *next;
-  lang_wild_statement_type *new;
+  lang_wild_statement_type *new_stmt;
 
   /* Reverse the list as the parser puts it back to front.  */
   for (curr = section_list, section_list = NULL;
@@ -6365,18 +6744,20 @@ lang_add_wild (struct wildcard_spec *filespec,
        lang_has_input_file = TRUE;
     }
 
-  new = new_stat (lang_wild_statement, stat_ptr);
-  new->filename = NULL;
-  new->filenames_sorted = FALSE;
+  new_stmt = new_stat (lang_wild_statement, stat_ptr);
+  new_stmt->filename = NULL;
+  new_stmt->filenames_sorted = FALSE;
+  new_stmt->section_flag_list = NULL;
   if (filespec != NULL)
     {
-      new->filename = filespec->name;
-      new->filenames_sorted = filespec->sorted == by_name;
+      new_stmt->filename = filespec->name;
+      new_stmt->filenames_sorted = filespec->sorted == by_name;
+      new_stmt->section_flag_list = filespec->section_flag_list;
     }
-  new->section_list = section_list;
-  new->keep_sections = keep_sections;
-  lang_list_init (&new->children);
-  analyze_walk_wild_section_handler (new);
+  new_stmt->section_list = section_list;
+  new_stmt->keep_sections = keep_sections;
+  lang_list_init (&new_stmt->children);
+  analyze_walk_wild_section_handler (new_stmt);
 }
 
 void
@@ -6421,10 +6802,10 @@ lang_default_entry (const char *name)
 void
 lang_add_target (const char *name)
 {
-  lang_target_statement_type *new;
+  lang_target_statement_type *new_stmt;
 
-  new = new_stat (lang_target_statement, stat_ptr);
-  new->target = name;
+  new_stmt = new_stat (lang_target_statement, stat_ptr);
+  new_stmt->target = name;
 }
 
 void
@@ -6445,20 +6826,20 @@ lang_add_map (const char *name)
 void
 lang_add_fill (fill_type *fill)
 {
-  lang_fill_statement_type *new;
+  lang_fill_statement_type *new_stmt;
 
-  new = new_stat (lang_fill_statement, stat_ptr);
-  new->fill = fill;
+  new_stmt = new_stat (lang_fill_statement, stat_ptr);
+  new_stmt->fill = fill;
 }
 
 void
 lang_add_data (int type, union etree_union *exp)
 {
-  lang_data_statement_type *new;
+  lang_data_statement_type *new_stmt;
 
-  new = new_stat (lang_data_statement, stat_ptr);
-  new->exp = exp;
-  new->type = type;
+  new_stmt = new_stat (lang_data_statement, stat_ptr);
+  new_stmt->exp = exp;
+  new_stmt->type = type;
 }
 
 /* Create a new reloc statement.  RELOC is the BFD relocation type to
@@ -6491,11 +6872,11 @@ lang_add_reloc (bfd_reloc_code_real_type reloc,
 lang_assignment_statement_type *
 lang_add_assignment (etree_type *exp)
 {
-  lang_assignment_statement_type *new;
+  lang_assignment_statement_type *new_stmt;
 
-  new = new_stat (lang_assignment_statement, stat_ptr);
-  new->exp = exp;
-  return new;
+  new_stmt = new_stat (lang_assignment_statement, stat_ptr);
+  new_stmt->exp = exp;
+  return new_stmt;
 }
 
 void
@@ -6507,15 +6888,13 @@ lang_add_attribute (enum statement_enum attribute)
 void
 lang_startup (const char *name)
 {
-  if (startup_file != NULL)
+  if (first_file->filename != NULL)
     {
       einfo (_("%P%F: multiple STARTUP files\n"));
     }
   first_file->filename = name;
   first_file->local_sym_name = name;
   first_file->real = TRUE;
-
-  startup_file = name;
 }
 
 void
@@ -6571,14 +6950,16 @@ 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 has the same
+  /* 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 && !current_section->load_base
+  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 ();
@@ -6680,11 +7061,11 @@ lang_add_output_format (const char *format,
 void
 lang_add_insert (const char *where, int is_before)
 {
-  lang_insert_statement_type *new;
+  lang_insert_statement_type *new_stmt;
 
-  new = new_stat (lang_insert_statement, stat_ptr);
-  new->where = where;
-  new->is_before = is_before;
+  new_stmt = new_stat (lang_insert_statement, stat_ptr);
+  new_stmt->where = where;
+  new_stmt->is_before = is_before;
   saved_script_handle = previous_script_handle;
 }
 
@@ -6724,8 +7105,9 @@ lang_new_phdr (const char *name,
               etree_type *flags)
 {
   struct lang_phdr *n, **pp;
+  bfd_boolean hdrs;
 
-  n = stat_alloc (sizeof (struct lang_phdr));
+  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");
@@ -6734,8 +7116,17 @@ lang_new_phdr (const char *name,
   n->at = at;
   n->flags = flags;
 
+  hdrs = n->type == 1 && (phdrs || filehdr);
+
   for (pp = &lang_phdr_list; *pp != NULL; pp = &(*pp)->next)
-    ;
+    if (hdrs
+       && (*pp)->type == 1
+       && !((*pp)->filehdr || (*pp)->phdrs))
+      {
+       einfo (_("%X%P:%S: PHDRS and FILEHDR are not supported when prior PT_LOAD headers lack them\n"));
+       hdrs = FALSE;
+      }
+
   *pp = n;
 }
 
@@ -6752,7 +7143,7 @@ lang_record_phdrs (void)
   lang_output_section_statement_type *os;
 
   alc = 10;
-  secs = xmalloc (alc * sizeof (asection *));
+  secs = (asection **) xmalloc (alc * sizeof (asection *));
   last = NULL;
 
   for (l = lang_phdr_list; l != NULL; l = l->next)
@@ -6819,7 +7210,8 @@ lang_record_phdrs (void)
                  if (c >= alc)
                    {
                      alc *= 2;
-                     secs = xrealloc (secs, alc * sizeof (asection *));
+                     secs = (asection **) xrealloc (secs,
+                                                     alc * sizeof (asection *));
                    }
                  secs[c] = os->bfd_section;
                  ++c;
@@ -6873,7 +7265,7 @@ lang_add_nocrossref (lang_nocrossref_type *l)
 {
   struct lang_nocrossrefs *n;
 
-  n = xmalloc (sizeof *n);
+  n = (struct lang_nocrossrefs *) xmalloc (sizeof *n);
   n->next = nocrossref_list;
   n->list = l;
   nocrossref_list = n;
@@ -6935,7 +7327,7 @@ lang_enter_overlay_section (const char *name)
     overlay_vma = exp_nameop (ADDR, name);
 
   /* Remember the section.  */
-  n = xmalloc (sizeof *n);
+  n = (struct overlay_list *) xmalloc (sizeof *n);
   n->os = current_section;
   n->next = overlay_list;
   overlay_list = n;
@@ -6971,20 +7363,20 @@ lang_leave_overlay_section (fill_type *fill,
 
   /* Define the magic symbols.  */
 
-  clean = xmalloc (strlen (name) + 1);
+  clean = (char *) xmalloc (strlen (name) + 1);
   s2 = clean;
   for (s1 = name; *s1 != '\0'; s1++)
     if (ISALNUM (*s1) || *s1 == '_')
       *s2++ = *s1;
   *s2 = '\0';
 
-  buf = xmalloc (strlen (clean) + sizeof "__load_start_");
+  buf = (char *) xmalloc (strlen (clean) + sizeof "__load_start_");
   sprintf (buf, "__load_start_%s", clean);
   lang_add_assignment (exp_provide (buf,
                                    exp_nameop (LOADADDR, name),
                                    FALSE));
 
-  buf = xmalloc (strlen (clean) + sizeof "__load_stop_");
+  buf = (char *) xmalloc (strlen (clean) + sizeof "__load_stop_");
   sprintf (buf, "__load_stop_%s", clean);
   lang_add_assignment (exp_provide (buf,
                                    exp_binop ('+',
@@ -7021,7 +7413,7 @@ lang_leave_overlay (etree_type *lma_expr,
      overlay region.  */
   if (overlay_list != NULL)
     overlay_list->os->update_dot_tree
-      = exp_assop ('=', ".", exp_binop ('+', overlay_vma, overlay_max));
+      = exp_assign (".", exp_binop ('+', overlay_vma, overlay_max));
 
   l = overlay_list;
   while (l != NULL)
@@ -7050,7 +7442,7 @@ lang_leave_overlay (etree_type *lma_expr,
        {
          lang_nocrossref_type *nc;
 
-         nc = xmalloc (sizeof *nc);
+         nc = (lang_nocrossref_type *) xmalloc (sizeof *nc);
          nc->name = l->os->name;
          nc->next = nocrossref;
          nocrossref = nc;
@@ -7084,19 +7476,29 @@ lang_vers_match (struct bfd_elf_version_expr_head *head,
                 struct bfd_elf_version_expr *prev,
                 const char *sym)
 {
+  const char *c_sym;
   const char *cxx_sym = sym;
   const char *java_sym = sym;
   struct bfd_elf_version_expr *expr = NULL;
+  enum demangling_styles curr_style;
+
+  curr_style = CURRENT_DEMANGLING_STYLE;
+  cplus_demangle_set_style (no_demangling);
+  c_sym = bfd_demangle (link_info.output_bfd, sym, DMGL_NO_OPTS);
+  if (!c_sym)
+    c_sym = sym;
+  cplus_demangle_set_style (curr_style);
 
   if (head->mask & BFD_ELF_VERSION_CXX_TYPE)
     {
-      cxx_sym = cplus_demangle (sym, DMGL_PARAMS | DMGL_ANSI);
+      cxx_sym = bfd_demangle (link_info.output_bfd, sym,
+                             DMGL_PARAMS | DMGL_ANSI);
       if (!cxx_sym)
        cxx_sym = sym;
     }
   if (head->mask & BFD_ELF_VERSION_JAVA_TYPE)
     {
-      java_sym = cplus_demangle (sym, DMGL_JAVA);
+      java_sym = bfd_demangle (link_info.output_bfd, sym, DMGL_JAVA);
       if (!java_sym)
        java_sym = sym;
     }
@@ -7110,9 +7512,10 @@ lang_vers_match (struct bfd_elf_version_expr_head *head,
        case 0:
          if (head->mask & BFD_ELF_VERSION_C_TYPE)
            {
-             e.pattern = sym;
-             expr = htab_find (head->htab, &e);
-             while (expr && strcmp (expr->pattern, sym) == 0)
+             e.pattern = c_sym;
+             expr = (struct bfd_elf_version_expr *)
+                  htab_find ((htab_t) head->htab, &e);
+             while (expr && strcmp (expr->pattern, c_sym) == 0)
                if (expr->mask == BFD_ELF_VERSION_C_TYPE)
                  goto out_ret;
                else
@@ -7123,7 +7526,8 @@ lang_vers_match (struct bfd_elf_version_expr_head *head,
          if (head->mask & BFD_ELF_VERSION_CXX_TYPE)
            {
              e.pattern = cxx_sym;
-             expr = htab_find (head->htab, &e);
+             expr = (struct bfd_elf_version_expr *)
+                  htab_find ((htab_t) head->htab, &e);
              while (expr && strcmp (expr->pattern, cxx_sym) == 0)
                if (expr->mask == BFD_ELF_VERSION_CXX_TYPE)
                  goto out_ret;
@@ -7135,7 +7539,8 @@ lang_vers_match (struct bfd_elf_version_expr_head *head,
          if (head->mask & BFD_ELF_VERSION_JAVA_TYPE)
            {
              e.pattern = java_sym;
-             expr = htab_find (head->htab, &e);
+             expr = (struct bfd_elf_version_expr *)
+                  htab_find ((htab_t) head->htab, &e);
              while (expr && strcmp (expr->pattern, java_sym) == 0)
                if (expr->mask == BFD_ELF_VERSION_JAVA_TYPE)
                  goto out_ret;
@@ -7168,12 +7573,14 @@ lang_vers_match (struct bfd_elf_version_expr_head *head,
       else if (expr->mask == BFD_ELF_VERSION_CXX_TYPE)
        s = cxx_sym;
       else
-       s = sym;
+       s = c_sym;
       if (fnmatch (expr->pattern, s, 0) == 0)
        break;
     }
 
  out_ret:
+  if (c_sym != sym)
+    free ((char *) c_sym);
   if (cxx_sym != sym)
     free ((char *) cxx_sym);
   if (java_sym != sym)
@@ -7189,7 +7596,7 @@ realsymbol (const char *pattern)
 {
   const char *p;
   bfd_boolean changed = FALSE, backslash = FALSE;
-  char *s, *symbol = xmalloc (strlen (pattern) + 1);
+  char *s, *symbol = (char *) xmalloc (strlen (pattern) + 1);
 
   for (p = pattern, s = symbol; *p != '\0'; ++p)
     {
@@ -7227,27 +7634,27 @@ realsymbol (const char *pattern)
     }
 }
 
-/* This is called for each variable name or match expression.  NEW is
+/* This is called for each variable name or match expression.  NEW_NAME is
    the name of the symbol to match, or, if LITERAL_P is FALSE, a glob
    pattern to be matched against symbol names.  */
 
 struct bfd_elf_version_expr *
 lang_new_vers_pattern (struct bfd_elf_version_expr *orig,
-                      const char *new,
+                      const char *new_name,
                       const char *lang,
                       bfd_boolean literal_p)
 {
   struct bfd_elf_version_expr *ret;
 
-  ret = xmalloc (sizeof *ret);
+  ret = (struct bfd_elf_version_expr *) xmalloc (sizeof *ret);
   ret->next = orig;
   ret->symver = 0;
   ret->script = 0;
   ret->literal = TRUE;
-  ret->pattern = literal_p ? new : realsymbol (new);
+  ret->pattern = literal_p ? new_name : realsymbol (new_name);
   if (ret->pattern == NULL)
     {
-      ret->pattern = new;
+      ret->pattern = new_name;
       ret->literal = FALSE;
     }
 
@@ -7276,7 +7683,7 @@ lang_new_vers_node (struct bfd_elf_version_expr *globals,
 {
   struct bfd_elf_version_tree *ret;
 
-  ret = xcalloc (1, sizeof *ret);
+  ret = (struct bfd_elf_version_tree *) xcalloc (1, sizeof *ret);
   ret->globals.list = globals;
   ret->locals.list = locals;
   ret->match = lang_vers_match;
@@ -7291,7 +7698,8 @@ static int version_index;
 static hashval_t
 version_expr_head_hash (const void *p)
 {
-  const struct bfd_elf_version_expr *e = p;
+  const struct bfd_elf_version_expr *e =
+      (const struct bfd_elf_version_expr *) p;
 
   return htab_hash_string (e->pattern);
 }
@@ -7299,8 +7707,10 @@ version_expr_head_hash (const void *p)
 static int
 version_expr_head_eq (const void *p1, const void *p2)
 {
-  const struct bfd_elf_version_expr *e1 = p1;
-  const struct bfd_elf_version_expr *e2 = p2;
+  const struct bfd_elf_version_expr *e1 =
+      (const struct bfd_elf_version_expr *) p1;
+  const struct bfd_elf_version_expr *e2 =
+      (const struct bfd_elf_version_expr *) p2;
 
   return strcmp (e1->pattern, e2->pattern) == 0;
 }
@@ -7335,13 +7745,13 @@ lang_finalize_version_expr_head (struct bfd_elf_version_expr_head *head)
            }
          else
            {
-             void **loc = htab_find_slot (head->htab, e, INSERT);
+             void **loc = htab_find_slot ((htab_t) head->htab, e, INSERT);
 
              if (*loc)
                {
                  struct bfd_elf_version_expr *e1, *last;
 
-                 e1 = *loc;
+                 e1 = (struct bfd_elf_version_expr *) *loc;
                  last = NULL;
                  do
                    {
@@ -7426,7 +7836,8 @@ lang_register_vers_node (const char *name,
 
          if (t->locals.htab && e1->literal)
            {
-             e2 = htab_find (t->locals.htab, e1);
+             e2 = (struct bfd_elf_version_expr *)
+                  htab_find ((htab_t) t->locals.htab, e1);
              while (e2 && strcmp (e1->pattern, e2->pattern) == 0)
                {
                  if (e1->mask == e2->mask)
@@ -7452,7 +7863,8 @@ lang_register_vers_node (const char *name,
 
          if (t->globals.htab && e1->literal)
            {
-             e2 = htab_find (t->globals.htab, e1);
+             e2 = (struct bfd_elf_version_expr *)
+                  htab_find ((htab_t) t->globals.htab, e1);
              while (e2 && strcmp (e1->pattern, e2->pattern) == 0)
                {
                  if (e1->mask == e2->mask)
@@ -7494,7 +7906,7 @@ lang_add_vers_depend (struct bfd_elf_version_deps *list, const char *name)
   struct bfd_elf_version_deps *ret;
   struct bfd_elf_version_tree *t;
 
-  ret = xmalloc (sizeof *ret);
+  ret = (struct bfd_elf_version_deps *) xmalloc (sizeof *ret);
   ret->next = list;
 
   for (t = lang_elf_version_info; t != NULL; t = t->next)
@@ -7508,6 +7920,7 @@ lang_add_vers_depend (struct bfd_elf_version_deps *list, const char *name)
 
   einfo (_("%X%P: unable to find version dependency `%s'\n"), name);
 
+  ret->version_needed = NULL;
   return ret;
 }
 
@@ -7526,7 +7939,7 @@ lang_do_version_exports_section (void)
        continue;
 
       len = sec->size;
-      contents = xmalloc (len);
+      contents = (char *) xmalloc (len);
       if (!bfd_get_section_contents (is->the_bfd, sec, contents, 0, len))
        einfo (_("%X%P: unable to read .exports section contents\n"), sec);
 
@@ -7557,7 +7970,7 @@ lang_add_unique (const char *name)
     if (strcmp (ent->name, name) == 0)
       return;
 
-  ent = xmalloc (sizeof *ent);
+  ent = (struct unique_sections *) xmalloc (sizeof *ent);
   ent->name = xstrdup (name);
   ent->next = unique_section_list;
   unique_section_list = ent;
@@ -7580,7 +7993,7 @@ lang_append_dynamic_list (struct bfd_elf_version_expr *dynamic)
     {
       struct bfd_elf_dynamic_list *d;
 
-      d = xcalloc (1, sizeof *d);
+      d = (struct bfd_elf_dynamic_list *) xcalloc (1, sizeof *d);
       d->head.list = dynamic;
       d->match = lang_vers_match;
       link_info.dynamic_list = d;
@@ -7628,3 +8041,32 @@ lang_append_dynamic_list_cpp_new (void)
 
   lang_append_dynamic_list (dynamic);
 }
+
+/* Scan a space and/or comma separated string of features.  */
+
+void
+lang_ld_feature (char *str)
+{
+  char *p, *q;
+
+  p = str;
+  while (*p)
+    {
+      char sep;
+      while (*p == ',' || ISSPACE (*p))
+       ++p;
+      if (!*p)
+       break;
+      q = p + 1;
+      while (*q && *q != ',' && !ISSPACE (*q))
+       ++q;
+      sep = *q;
+      *q = 0;
+      if (strcasecmp (p, "SANE_EXPR") == 0)
+       config.sane_expr = TRUE;
+      else
+       einfo (_("%X%P: unknown feature `%s'\n"), p);
+      *q = sep;
+      p = q;
+    }
+}
This page took 0.061145 seconds and 4 git commands to generate.