PR ld/13812
[deliverable/binutils-gdb.git] / ld / ldlang.c
index 03a11bd82694961da5948f226485386ead595360..08aa32aa0c464797027521a9f69d33b85fc939f1 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, 2010
+   2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012
    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"
@@ -55,7 +56,6 @@ 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;
@@ -69,7 +69,6 @@ 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 *);
@@ -100,6 +99,7 @@ lang_statement_list_type file_chain = { NULL, NULL };
 lang_statement_list_type input_file_chain;
 struct bfd_sym_chain entry_symbol = { NULL, NULL };
 const char *entry_section = ".text";
+struct lang_input_statement_flags input_flags;
 bfd_boolean entry_from_cmdline;
 bfd_boolean undef_from_cmdline;
 bfd_boolean lang_has_input_file = FALSE;
@@ -108,7 +108,6 @@ 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;
-bfd_boolean missing_file = FALSE;
 
  /* Functions that traverse the linker script and might evaluate
     DEFINED() need to increment this.  */
@@ -263,7 +262,7 @@ walk_wild_consider_section (lang_wild_statement_type *ptr,
        return;
     }
 
-  (*callback) (ptr, sec, s, file, data);
+  (*callback) (ptr, sec, s, ptr->section_flag_list, file, data);
 }
 
 /* Lowest common denominator routine that can handle everything correctly,
@@ -282,7 +281,7 @@ walk_wild_section_general (lang_wild_statement_type *ptr,
     {
       sec = ptr->section_list;
       if (sec == NULL)
-       (*callback) (ptr, sec, s, file, data);
+       (*callback) (ptr, sec, s, ptr->section_flag_list, file, data);
 
       while (sec != NULL)
        {
@@ -371,18 +370,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/.dtors.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));
@@ -391,6 +442,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;
@@ -451,6 +503,7 @@ static void
 output_section_callback_fast (lang_wild_statement_type *ptr,
                              struct wildcard_list *sec,
                              asection *section,
+                             struct flag_info *sflag_list ATTRIBUTE_UNUSED,
                              lang_input_statement_type *file,
                              void *output)
 {
@@ -483,7 +536,7 @@ output_section_callback_tree_to_list (lang_wild_statement_type *ptr,
   if (tree->left)
     output_section_callback_tree_to_list (ptr, tree->left, output);
 
-  lang_add_section (&ptr->children, tree->section,
+  lang_add_section (&ptr->children, tree->section, NULL,
                    (lang_output_section_statement_type *) output);
 
   if (tree->right)
@@ -675,7 +728,7 @@ walk_wild_section (lang_wild_statement_type *ptr,
                   callback_t callback,
                   void *data)
 {
-  if (file->just_syms_flag)
+  if (file->flags.just_syms)
     return;
 
   (*ptr->walk_wild_section_handler) (ptr, file, callback, data);
@@ -825,8 +878,8 @@ walk_wild_file (lang_wild_statement_type *s,
          if (member->usrdata != NULL)
            {
              walk_wild_section (s,
-                                 (lang_input_statement_type *) member->usrdata,
-                                 callback, data);
+                                (lang_input_statement_type *) member->usrdata,
+                                callback, data);
            }
 
          member = bfd_openr_next_archived_file (f->the_bfd, member);
@@ -990,19 +1043,26 @@ new_afile (const char *name,
 {
   lang_input_statement_type *p;
 
+  lang_has_input_file = TRUE;
+
   if (add_to_list)
     p = (lang_input_statement_type *) new_stat (lang_input_statement, stat_ptr);
   else
     {
       p = (lang_input_statement_type *)
-          stat_alloc (sizeof (lang_input_statement_type));
+         stat_alloc (sizeof (lang_input_statement_type));
       p->header.type = lang_input_statement_enum;
       p->header.next = NULL;
     }
 
-  lang_has_input_file = TRUE;
+  memset (&p->the_bfd, 0,
+         sizeof (*p) - offsetof (lang_input_statement_type, the_bfd));
   p->target = target;
-  p->sysrooted = FALSE;
+  p->flags.dynamic = input_flags.dynamic;
+  p->flags.add_DT_NEEDED_for_dynamic = input_flags.add_DT_NEEDED_for_dynamic;
+  p->flags.add_DT_NEEDED_for_regular = input_flags.add_DT_NEEDED_for_regular;
+  p->flags.whole_archive = input_flags.whole_archive;
+  p->flags.sysrooted = input_flags.sysrooted;
 
   if (file_type == lang_input_file_is_l_enum
       && name[0] == ':' && name[1] != '\0')
@@ -1015,65 +1075,40 @@ new_afile (const char *name,
     {
     case lang_input_file_is_symbols_only_enum:
       p->filename = name;
-      p->maybe_archive = FALSE;
-      p->real = TRUE;
       p->local_sym_name = name;
-      p->just_syms_flag = TRUE;
-      p->search_dirs_flag = FALSE;
+      p->flags.real = TRUE;
+      p->flags.just_syms = TRUE;
       break;
     case lang_input_file_is_fake_enum:
       p->filename = name;
-      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->maybe_archive = TRUE;
       p->filename = name;
-      p->real = TRUE;
       p->local_sym_name = concat ("-l", name, (const char *) NULL);
-      p->just_syms_flag = FALSE;
-      p->search_dirs_flag = TRUE;
+      p->flags.maybe_archive = TRUE;
+      p->flags.real = TRUE;
+      p->flags.search_dirs = TRUE;
       break;
     case lang_input_file_is_marker_enum:
       p->filename = name;
-      p->maybe_archive = FALSE;
-      p->real = FALSE;
       p->local_sym_name = name;
-      p->just_syms_flag = FALSE;
-      p->search_dirs_flag = TRUE;
+      p->flags.search_dirs = TRUE;
       break;
     case lang_input_file_is_search_file_enum:
-      p->sysrooted = ldlang_sysrooted_script;
       p->filename = name;
-      p->maybe_archive = FALSE;
-      p->real = TRUE;
       p->local_sym_name = name;
-      p->just_syms_flag = FALSE;
-      p->search_dirs_flag = TRUE;
+      p->flags.real = TRUE;
+      p->flags.search_dirs = TRUE;
       break;
     case lang_input_file_is_file_enum:
       p->filename = name;
-      p->maybe_archive = FALSE;
-      p->real = TRUE;
       p->local_sym_name = name;
-      p->just_syms_flag = FALSE;
-      p->search_dirs_flag = FALSE;
+      p->flags.real = TRUE;
       break;
     default:
       FAIL ();
     }
-  p->the_bfd = NULL;
-  p->next_real_file = NULL;
-  p->next = NULL;
-  p->dynamic = config.dynamic_link;
-  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;
 
   lang_statement_append (&input_file_chain,
                         (lang_statement_union_type *) p,
@@ -1113,7 +1148,7 @@ output_section_statement_newfunc (struct bfd_hash_entry *entry,
   if (entry == NULL)
     {
       entry = (struct bfd_hash_entry *) bfd_hash_allocate (table,
-                                                           sizeof (*ret));
+                                                          sizeof (*ret));
       if (entry == NULL)
        return entry;
     }
@@ -1205,6 +1240,8 @@ lang_init (void)
 void
 lang_finish (void)
 {
+  bfd_link_hash_table_free (link_info.output_bfd, link_info.hash);
+  bfd_hash_table_free (&lang_definedness_table);
   output_section_statement_table_free ();
 }
 
@@ -1248,15 +1285,16 @@ lang_memory_region_lookup (const char *const name, bfd_boolean create)
   for (r = lang_memory_region_list; r != NULL; r = r->next)
     for (n = &r->name_list; n != NULL; n = n->next)
       if (strcmp (n->name, name) == 0)
-        {
-          if (create)
-            einfo (_("%P:%S: warning: redeclaration of memory region `%s'\n"),
-                   name);
-          return r;
-        }
+       {
+         if (create)
+           einfo (_("%P:%S: warning: redeclaration of memory region `%s'\n"),
+                  NULL, name);
+         return r;
+       }
 
   if (!create && strcmp (name, DEFAULT_MEMORY_REGION))
-    einfo (_("%P:%S: warning: memory region `%s' not declared\n"), name);
+    einfo (_("%P:%S: warning: memory region `%s' not declared\n"),
+          NULL, name);
 
   new_region = (lang_memory_region_type *)
       stat_alloc (sizeof (lang_memory_region_type));
@@ -1290,7 +1328,7 @@ lang_memory_region_alias (const char * alias, const char * region_name)
      the default memory region.  */
   if (strcmp (region_name, DEFAULT_MEMORY_REGION) == 0
       || strcmp (alias, DEFAULT_MEMORY_REGION) == 0)
-    einfo (_("%F%P:%S: error: alias for default memory region\n"));
+    einfo (_("%F%P:%S: error: alias for default memory region\n"), NULL);
 
   /* Look for the target region and check if the alias is not already
      in use.  */
@@ -1298,20 +1336,19 @@ lang_memory_region_alias (const char * alias, const char * region_name)
   for (r = lang_memory_region_list; r != NULL; r = r->next)
     for (n = &r->name_list; n != NULL; n = n->next)
       {
-        if (region == NULL && strcmp (n->name, region_name) == 0)
-          region = r;
-        if (strcmp (n->name, alias) == 0)
-          einfo (_("%F%P:%S: error: redefinition of memory region "
-                   "alias `%s'\n"),
-                 alias);
+       if (region == NULL && strcmp (n->name, region_name) == 0)
+         region = r;
+       if (strcmp (n->name, alias) == 0)
+         einfo (_("%F%P:%S: error: redefinition of memory region "
+                  "alias `%s'\n"),
+                NULL, alias);
       }
 
   /* Check if the target region exists.  */
   if (region == NULL)
     einfo (_("%F%P:%S: error: memory region `%s' "
-             "for alias `%s' does not exist\n"),
-           region_name,
-           alias);
+            "for alias `%s' does not exist\n"),
+          NULL, region_name, alias);
 
   /* Add alias to region name list.  */
   n = (lang_memory_region_name *) stat_alloc (sizeof (lang_memory_region_name));
@@ -1522,8 +1559,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;
        }
     }
@@ -1736,7 +1779,7 @@ 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, normal_section,
-                                            NULL, NULL, NULL, constraint);
+                                           NULL, NULL, NULL, constraint);
 
   ps = NULL;
   if (config.build_constructors && *os_tail == os)
@@ -1749,24 +1792,19 @@ lang_insert_orphan (asection *s,
       if (*ps == '\0')
        {
          char *symname;
-         etree_type *e_align;
 
          symname = (char *) xmalloc (ps - secname + sizeof "__start_" + 1);
          symname[0] = bfd_get_symbol_leading_char (link_info.output_bfd);
          sprintf (symname + (symname[0] != 0), "__start_%s", secname);
-         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_provide (symname,
-                                           exp_unop (ABSOLUTE,
-                                                     exp_nameop (NAME, ".")),
+                                           exp_nameop (NAME, "."),
                                            FALSE));
        }
     }
 
   if (add_child == NULL)
     add_child = &os->children;
-  lang_add_section (add_child, s, os);
+  lang_add_section (add_child, s, NULL, os);
 
   if (after && (s->flags & (SEC_LOAD | SEC_ALLOC)) != 0)
     {
@@ -1945,7 +1983,7 @@ lang_map (void)
       asection *s;
 
       if ((file->the_bfd->flags & (BFD_LINKER_CREATED | DYNAMIC)) != 0
-         || file->just_syms_flag)
+         || file->flags.just_syms)
        continue;
 
       for (s = file->the_bfd->sections; s != NULL; s = s->next)
@@ -2044,14 +2082,14 @@ sort_def_symbol (struct bfd_link_hash_entry *hash_entry,
       struct map_symbol_def *def;
 
       ud = (struct fat_user_section_struct *)
-          get_userdata (hash_entry->u.def.section);
+         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 = (struct fat_user_section_struct *)
-              get_userdata (hash_entry->u.def.section);
+             get_userdata (hash_entry->u.def.section);
        }
       else if  (!ud->map_symbol_def_tail)
        ud->map_symbol_def_tail = &ud->map_symbol_def_head;
@@ -2089,7 +2127,7 @@ init_os (lang_output_section_statement_type *s, flagword flags)
   if (!link_info.reduce_memory_overheads)
     {
       fat_section_userdata_type *new_userdata = (fat_section_userdata_type *)
-        stat_alloc (sizeof (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;
     }
@@ -2167,7 +2205,7 @@ section_already_linked (bfd *abfd, asection *sec, void *data)
 
   /* If we are only reading symbols from this object, then we want to
      discard all sections.  */
-  if (entry->just_syms_flag)
+  if (entry->flags.just_syms)
     {
       bfd_link_just_syms (abfd, sec, &link_info);
       return;
@@ -2184,17 +2222,19 @@ section_already_linked (bfd *abfd, asection *sec, void *data)
    foo.o(.text, .data).  */
 
 /* Add SECTION to the output section OUTPUT.  Do this by creating a
-   lang_input_section statement which is placed at PTR.  FILE is the
-   input file which holds SECTION.  */
+   lang_input_section statement which is placed at PTR.  */
 
 void
 lang_add_section (lang_statement_list_type *ptr,
                  asection *section,
+                 struct flag_info *sflag_info,
                  lang_output_section_statement_type *output)
 {
   flagword flags = section->flags;
+
   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;
@@ -2220,6 +2260,15 @@ lang_add_section (lang_statement_list_type *ptr,
       return;
     }
 
+  if (sflag_info)
+    {
+      bfd_boolean keep;
+
+      keep = bfd_lookup_section_flags (&link_info, sflag_info, section);
+      if (!keep)
+       return;
+    }
+
   if (section->output_section != NULL)
     return;
 
@@ -2391,7 +2440,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)
@@ -2404,7 +2453,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)
@@ -2415,7 +2464,9 @@ wild_sort (lang_wild_statement_type *wild,
       /* Here either the files are not sorted by name, or we are
         looking at the sections for this file.  */
 
-      if (sec != NULL && sec->spec.sorted != none)
+      if (sec != NULL
+         && sec->spec.sorted != none
+         && sec->spec.sorted != by_none)
        if (compare_section (sec->spec.sorted, section, ls->section) < 0)
          break;
     }
@@ -2430,6 +2481,7 @@ static void
 output_section_callback (lang_wild_statement_type *ptr,
                         struct wildcard_list *sec,
                         asection *section,
+                        struct flag_info *sflag_info,
                         lang_input_statement_type *file,
                         void *output)
 {
@@ -2450,14 +2502,14 @@ output_section_callback (lang_wild_statement_type *ptr,
      of the current list.  */
 
   if (before == NULL)
-    lang_add_section (&ptr->children, section, os);
+    lang_add_section (&ptr->children, section, sflag_info, os);
   else
     {
       lang_statement_list_type list;
       lang_statement_union_type **pp;
 
       lang_list_init (&list);
-      lang_add_section (&list, section, os);
+      lang_add_section (&list, section, sflag_info, os);
 
       /* If we are discarding the section, LIST.HEAD will
         be NULL.  */
@@ -2483,6 +2535,7 @@ static void
 check_section_callback (lang_wild_statement_type *ptr ATTRIBUTE_UNUSED,
                        struct wildcard_list *sec ATTRIBUTE_UNUSED,
                        asection *section,
+                       struct flag_info *sflag_info ATTRIBUTE_UNUSED,
                        lang_input_statement_type *file ATTRIBUTE_UNUSED,
                        void *output)
 {
@@ -2517,7 +2570,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;
     }
 
@@ -2527,7 +2580,7 @@ lookup_name (const char *name)
 
   /* If we have already added this file, or this file is not real
      don't add this file.  */
-  if (search->loaded || !search->real)
+  if (search->flags.loaded || !search->flags.real)
     return search;
 
   if (! load_symbols (search, NULL))
@@ -2584,7 +2637,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')))
@@ -2605,23 +2658,21 @@ load_symbols (lang_input_statement_type *entry,
 {
   char **matching;
 
-  if (entry->loaded)
+  if (entry->flags.loaded)
     return TRUE;
 
   ldfile_open_file (entry);
 
   /* Do not process further if the file was missing.  */
-  if (entry->missing_file)
+  if (entry->flags.missing_file)
     return TRUE;
 
   if (! bfd_check_format (entry->the_bfd, bfd_archive)
       && ! bfd_check_format_matches (entry->the_bfd, bfd_object, &matching))
     {
       bfd_error_type err;
-      bfd_boolean save_ldlang_sysrooted_script;
-      bfd_boolean save_add_DT_NEEDED_for_regular;
-      bfd_boolean save_add_DT_NEEDED_for_dynamic;
-      bfd_boolean save_whole_archive;
+      struct lang_input_statement_flags save_flags;
+      extern FILE *yyin;
 
       err = bfd_get_error ();
 
@@ -2647,31 +2698,31 @@ load_symbols (lang_input_statement_type *entry,
       entry->the_bfd = NULL;
 
       /* Try to interpret the file as a linker script.  */
+      save_flags = input_flags;
       ldfile_open_command_file (entry->filename);
 
       push_stat_ptr (place);
-      save_ldlang_sysrooted_script = ldlang_sysrooted_script;
-      ldlang_sysrooted_script = entry->sysrooted;
-      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;
+      input_flags.add_DT_NEEDED_for_regular
+       = entry->flags.add_DT_NEEDED_for_regular;
+      input_flags.add_DT_NEEDED_for_dynamic
+       = entry->flags.add_DT_NEEDED_for_dynamic;
+      input_flags.whole_archive = entry->flags.whole_archive;
+      input_flags.dynamic = entry->flags.dynamic;
 
       ldfile_assumed_script = TRUE;
       parser_input = input_script;
-      /* We want to use the same -Bdynamic/-Bstatic as the one for
-        ENTRY.  */
-      config.dynamic_link = entry->dynamic;
       yyparse ();
       ldfile_assumed_script = FALSE;
 
-      ldlang_sysrooted_script = save_ldlang_sysrooted_script;
-      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;
+      /* missing_file is sticky.  sysrooted will already have been
+        restored when seeing EOF in yyparse, but no harm to restore
+        again.  */
+      save_flags.missing_file |= input_flags.missing_file;
+      input_flags = save_flags;
       pop_stat_ptr ();
+      fclose (yyin);
+      yyin = NULL;
+      entry->flags.loaded = TRUE;
 
       return TRUE;
     }
@@ -2689,15 +2740,18 @@ load_symbols (lang_input_statement_type *entry,
       break;
 
     case bfd_object:
-      ldlang_add_file (entry);
-      if (trace_files || trace_file_tries)
+#ifdef ENABLE_PLUGINS
+      if (!entry->flags.reload)
+#endif
+       ldlang_add_file (entry);
+      if (trace_files || verbose)
        info_msg ("%I\n", entry);
       break;
 
     case bfd_archive:
       check_excluded_libs (entry->the_bfd);
 
-      if (entry->whole_archive)
+      if (entry->flags.whole_archive)
        {
          bfd *member = NULL;
          bfd_boolean loaded = TRUE;
@@ -2718,31 +2772,32 @@ load_symbols (lang_input_statement_type *entry,
                }
 
              subsbfd = member;
-             if (! ((*link_info.callbacks->add_archive_element)
-                    (&link_info, member, "--whole-archive", &subsbfd)))
+             if (!(*link_info.callbacks
+                   ->add_archive_element) (&link_info, member,
+                                           "--whole-archive", &subsbfd))
                abort ();
 
              /* Potentially, the add_archive_element hook may have set a
                 substitute BFD for us.  */
-             if (! bfd_link_add_symbols (member, &link_info))
+             if (!bfd_link_add_symbols (subsbfd, &link_info))
                {
                  einfo (_("%F%B: could not read symbols: %E\n"), member);
                  loaded = FALSE;
                }
            }
 
-         entry->loaded = loaded;
+         entry->flags.loaded = loaded;
          return loaded;
        }
       break;
     }
 
   if (bfd_link_add_symbols (entry->the_bfd, &link_info))
-    entry->loaded = TRUE;
+    entry->flags.loaded = TRUE;
   else
     einfo (_("%F%B: could not read symbols: %E\n"), entry->the_bfd);
 
-  return entry->loaded;
+  return entry->flags.loaded;
 }
 
 /* Handle a wild statement.  S->FILENAME or S->SECTION_LIST or both
@@ -2926,7 +2981,7 @@ get_first_input_target (void)
   LANG_FOR_EACH_INPUT_STATEMENT (s)
     {
       if (s->header.type == lang_input_statement_enum
-         && s->real)
+         && s->flags.real)
        {
          ldfile_open_file (s);
 
@@ -2955,7 +3010,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?  */
@@ -3106,26 +3161,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:
          {
@@ -3138,7 +3204,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);
          }
@@ -3147,7 +3214,7 @@ open_input_bfds (lang_statement_union_type *s, bfd_boolean force)
          current_target = s->target_statement.target;
          break;
        case lang_input_statement_enum:
-         if (s->input_statement.real)
+         if (s->input_statement.flags.real)
            {
              lang_statement_union_type **os_tail;
              lang_statement_list_type add;
@@ -3157,13 +3224,32 @@ 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
-                 && !s->input_statement.whole_archive
-                 && s->input_statement.loaded
+                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.flags.whole_archive
+                 && s->input_statement.flags.loaded
+                 && s->input_statement.the_bfd != NULL
                  && bfd_check_format (s->input_statement.the_bfd,
                                       bfd_archive))
-               s->input_statement.loaded = FALSE;
+               s->input_statement.flags.loaded = FALSE;
+#ifdef ENABLE_PLUGINS
+             /* When rescanning, reload --as-needed shared libs.  */
+             else if ((mode & OPEN_BFD_RESCAN) != 0
+                      && plugin_insert == NULL
+                      && s->input_statement.flags.loaded
+                      && s->input_statement.flags.add_DT_NEEDED_for_regular
+                      && s->input_statement.the_bfd != NULL
+                      && ((s->input_statement.the_bfd->flags) & DYNAMIC) != 0
+                      && plugin_should_reload (s->input_statement.the_bfd))
+               {
+                 s->input_statement.flags.loaded = FALSE;
+                 s->input_statement.flags.reload = TRUE;
+               }
+#endif
 
              os_tail = lang_output_section_statement.tail;
              lang_list_init (&add);
@@ -3194,6 +3280,17 @@ 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.defsym)
+           /* This is from a --defsym on the command line.  */
+           exp_fold_tree_no_dot (s->assignment_statement.exp);
          break;
        default:
          break;
@@ -3201,7 +3298,7 @@ open_input_bfds (lang_statement_union_type *s, bfd_boolean force)
     }
 
   /* Exit if any of the files were missing.  */
-  if (missing_file)
+  if (input_flags.missing_file)
     einfo ("%F");
 }
 
@@ -3341,65 +3438,6 @@ lang_place_undefineds (void)
     insert_undefined (ptr->name);
 }
 
-typedef struct bfd_sym_chain ldlang_def_chain_list_type;
-
-static ldlang_def_chain_list_type ldlang_def_chain_list_head;
-
-/* Insert NAME as defined in the symbol table.  */
-
-static void
-insert_defined (const char *name)
-{
-  struct bfd_link_hash_entry *h;
-
-  h = bfd_link_hash_lookup (link_info.hash, name, TRUE, FALSE, TRUE);
-  if (h == NULL)
-    einfo (_("%P%F: bfd_link_hash_lookup failed: %E\n"));
-  if (h->type == bfd_link_hash_new
-      || h->type == bfd_link_hash_undefined
-      || h->type == bfd_link_hash_undefweak)
-    {
-      h->type = bfd_link_hash_defined;
-      h->u.def.section = bfd_abs_section_ptr;
-      h->u.def.value   = 0;
-    }
-}
-
-/* Like lang_add_undef, but this time for symbols defined on the
-   command line.  */
-
-static void
-ldlang_add_def (const char *const name)
-{
-  if (link_info.output_bfd != NULL)
-    insert_defined (xstrdup (name));
-  else
-    {
-      ldlang_def_chain_list_type *new_def;
-
-      new_def = (ldlang_def_chain_list_type *) stat_alloc (sizeof (*new_def));
-      new_def->next = ldlang_def_chain_list_head.next;
-      ldlang_def_chain_list_head.next = new_def;
-
-      new_def->name = xstrdup (name);
-    }
-}
-
-/* Run through the list of defineds created above and place them
-   into the linker hash table as defined symbols belonging to the
-   script file.  */
-
-static void
-lang_place_defineds (void)
-{
-  ldlang_def_chain_list_type *ptr;
-
-  for (ptr = ldlang_def_chain_list_head.next;
-       ptr != NULL;
-       ptr = ptr->next)
-    insert_defined (ptr->name);
-}
-
 /* Check for all readonly or some readwrite sections.  */
 
 static void
@@ -3460,7 +3498,6 @@ update_wild_statements (lang_statement_union_type *s)
              break;
 
            case lang_wild_statement_enum:
-             sec = s->wild_statement.section_list;
              for (sec = s->wild_statement.section_list; sec != NULL;
                   sec = sec->next)
                {
@@ -3488,8 +3525,11 @@ update_wild_statements (lang_statement_union_type *s)
              break;
 
            case lang_output_section_statement_enum:
-             update_wild_statements
-               (s->output_section_statement.children.head);
+             /* Don't sort .init/.fini sections.  */
+             if (strcmp (s->output_section_statement.name, ".init") != 0
+                 && strcmp (s->output_section_statement.name, ".fini") != 0)
+               update_wild_statements
+                 (s->output_section_statement.children.head);
              break;
 
            case lang_group_statement_enum:
@@ -3839,8 +3879,9 @@ strip_excluded_output_sections (void)
          asection *s;
 
          for (s = output_section->map_head.s; s != NULL; s = s->map_head.s)
-           if ((s->flags & SEC_LINKER_CREATED) != 0
-               && (s->flags & SEC_EXCLUDE) == 0)
+           if ((s->flags & SEC_EXCLUDE) == 0
+               && ((s->flags & SEC_LINKER_CREATED) != 0
+                   || link_info.emitrelocations))
              {
                exclude = FALSE;
                break;
@@ -3855,8 +3896,7 @@ strip_excluded_output_sections (void)
        {
          /* We don't set bfd_section to NULL since bfd_section of the
             removed output section statement may still be used.  */
-         if (!os->section_relative_symbol
-             && !os->update_dot_tree)
+         if (!os->update_dot)
            os->ignored = TRUE;
          output_section->flags |= SEC_EXCLUDE;
          bfd_section_list_remove (link_info.output_bfd, output_section);
@@ -3913,63 +3953,12 @@ print_output_section_statement
                        output_section_statement);
 }
 
-/* Scan for the use of the destination in the right hand side
-   of an expression.  In such cases we will not compute the
-   correct expression, since the value of DST that is used on
-   the right hand side will be its final value, not its value
-   just before this expression is evaluated.  */
-
-static bfd_boolean
-scan_for_self_assignment (const char * dst, etree_type * rhs)
-{
-  if (rhs == NULL || dst == NULL)
-    return FALSE;
-
-  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);
-
-    case etree_trinary:
-      return scan_for_self_assignment (dst, rhs->trinary.lhs)
-       ||   scan_for_self_assignment (dst, rhs->trinary.rhs);
-
-    case etree_assign:
-    case etree_provided:
-    case etree_provide:
-      if (strcmp (dst, rhs->assign.dst) == 0)
-       return TRUE;
-      return scan_for_self_assignment (dst, rhs->assign.src);
-
-    case etree_unary:
-      return scan_for_self_assignment (dst, rhs->unary.child);
-
-    case etree_value:
-      if (rhs->value.str)
-       return strcmp (dst, rhs->value.str) == 0;
-      return FALSE;
-
-    case etree_name:
-      if (rhs->name.name)
-       return strcmp (dst, rhs->name.name) == 0;
-      return FALSE;
-
-    default:
-      break;
-    }
-
-  return FALSE;
-}
-
-
 static void
 print_assignment (lang_assignment_statement_type *assignment,
                  lang_output_section_statement_type *output_section)
 {
   unsigned int i;
   bfd_boolean is_dot;
-  bfd_boolean computation_is_valid = TRUE;
   etree_type *tree;
   asection *osec;
 
@@ -3980,15 +3969,14 @@ print_assignment (lang_assignment_statement_type *assignment,
     {
       is_dot = FALSE;
       tree = assignment->exp->assert_s.child;
-      computation_is_valid = TRUE;
     }
   else
     {
       const char *dst = assignment->exp->assign.dst;
 
       is_dot = (dst[0] == '.' && dst[1] == 0);
+      expld.assign_name = dst;
       tree = assignment->exp->assign.src;
-      computation_is_valid = is_dot || (scan_for_self_assignment (dst, tree) == FALSE);
     }
 
   osec = output_section->bfd_section;
@@ -3999,7 +3987,9 @@ print_assignment (lang_assignment_statement_type *assignment,
     {
       bfd_vma value;
 
-      if (computation_is_valid)
+      if (assignment->exp->type.node_class == etree_assert
+         || is_dot
+         || expld.assign_name != NULL)
        {
          value = expld.result.value;
 
@@ -4019,9 +4009,8 @@ print_assignment (lang_assignment_statement_type *assignment,
          if (h)
            {
              value = h->u.def.value;
-
-             if (expld.result.section != NULL)
-               value += expld.result.section->vma;
+             value += h->u.def.section->output_section->vma;
+             value += h->u.def.section->output_offset;
 
              minfo ("[0x%V]", value);
            }
@@ -4036,6 +4025,7 @@ print_assignment (lang_assignment_statement_type *assignment,
       minfo ("        ");
 #endif
     }
+  expld.assign_name = NULL;
 
   minfo ("                ");
   exp_print_tree (assignment->exp);
@@ -4114,7 +4104,7 @@ print_all_symbols (asection *sec)
     entries[i] = def->entry;
 
   qsort (entries, ud->map_symbol_def_count, sizeof (*entries),
-         hash_entry_addr_cmp);
+        hash_entry_addr_cmp);
 
   /* Print the symbols.  */
   for (i = 0; i < ud->map_symbol_def_count; i++)
@@ -4520,11 +4510,11 @@ dprint_statement (lang_statement_union_type *s, int n)
 static void
 insert_pad (lang_statement_union_type **ptr,
            fill_type *fill,
-           unsigned int alignment_needed,
+           bfd_size_type alignment_needed,
            asection *output_section,
            bfd_vma dot)
 {
-  static fill_type zero_fill = { 1, { 0 } };
+  static fill_type zero_fill;
   lang_statement_union_type *pad = NULL;
 
   if (ptr != &statement_list.head)
@@ -4546,7 +4536,7 @@ insert_pad (lang_statement_union_type **ptr,
     {
       /* Make a new padding statement, linked into existing chain.  */
       pad = (lang_statement_union_type *)
-          stat_alloc (sizeof (lang_padding_statement_type));
+         stat_alloc (sizeof (lang_padding_statement_type));
       pad->header.next = *ptr;
       *ptr = pad;
       pad->header.type = lang_padding_statement_enum;
@@ -4557,7 +4547,8 @@ insert_pad (lang_statement_union_type **ptr,
     }
   pad->padding_statement.output_offset = dot - output_section->vma;
   pad->padding_statement.size = alignment_needed;
-  output_section->size += alignment_needed;
+  output_section->size = TO_SIZE (dot + TO_ADDR (alignment_needed)
+                                 - output_section->vma);
 }
 
 /* Work out how much this section will move the dot point.  */
@@ -4572,10 +4563,10 @@ size_input_section
   lang_input_section_type *is = &((*this_ptr)->input_section);
   asection *i = is->section;
 
-  if (!((lang_input_statement_type *) i->owner->usrdata)->just_syms_flag
+  if (i->sec_info_type != SEC_INFO_TYPE_JUST_SYMS
       && (i->flags & SEC_EXCLUDE) == 0)
     {
-      unsigned int alignment_needed;
+      bfd_size_type alignment_needed;
       asection *o;
 
       /* Align this section first to the input sections requirement,
@@ -4815,7 +4806,7 @@ lang_size_sections_1
                else if (expld.phase != lang_mark_phase_enum)
                  einfo (_("%F%S: non constant or forward reference"
                           " address expression for section %s\n"),
-                        os->name);
+                        os->addr_tree, os->name);
              }
 
            if (os->bfd_section == NULL)
@@ -4972,6 +4963,13 @@ lang_size_sections_1
              {
                bfd_vma lma = os->lma_region->current;
 
+               /* When LMA_REGION is the same as REGION, align the LMA
+                  as we did for the VMA, possibly including alignment
+                  from the bfd section.  If a different region, then
+                  only align according to the value in the output
+                  statement.  */
+               if (os->lma_region != os->region)
+                 section_alignment = os->section_alignment;
                if (section_alignment > 0)
                  lma = align_power (lma, section_alignment);
                os->bfd_section->lma = lma;
@@ -5122,7 +5120,9 @@ lang_size_sections_1
            if (size < TO_SIZE ((unsigned) 1))
              size = TO_SIZE ((unsigned) 1);
            dot += TO_ADDR (size);
-           output_section_statement->bfd_section->size += size;
+           output_section_statement->bfd_section->size
+             = TO_SIZE (dot - output_section_statement->bfd_section->vma);
+
          }
          break;
 
@@ -5136,7 +5136,8 @@ lang_size_sections_1
              output_section_statement->bfd_section;
            size = bfd_get_reloc_size (s->reloc_statement.howto);
            dot += TO_ADDR (size);
-           output_section_statement->bfd_section->size += size;
+           output_section_statement->bfd_section->size
+             = TO_SIZE (dot - output_section_statement->bfd_section->vma);
          }
          break;
 
@@ -5215,12 +5216,12 @@ lang_size_sections_1
              }
            expld.dataseg.relro = exp_dataseg_relro_none;
 
-           /* This symbol is relative to this section.  */
+           /* This symbol may be relative to this section.  */
            if ((tree->type.node_class == etree_provided
                 || tree->type.node_class == etree_assign)
                && (tree->assign.dst [0] != '.'
                    || tree->assign.dst [1] != '\0'))
-             output_section_statement->section_relative_symbol = 1;
+             output_section_statement->update_dot = 1;
 
            if (!output_section_statement->ignored)
              {
@@ -5320,6 +5321,12 @@ ldlang_override_segment_assignment (struct bfd_link_info * info ATTRIBUTE_UNUSED
   if (current_section == NULL || previous_section == NULL)
     return new_segment;
 
+  /* If this flag is set, the target never wants code and non-code
+     sections comingled in the same segment.  */
+  if (config.separate_code
+      && ((current_section->flags ^ previous_section->flags) & SEC_CODE))
+    return TRUE;
+
   /* Find the memory regions associated with the two sections.
      We call lang_output_section_find() here rather than scanning the list
      of output sections looking for a matching section pointer because if
@@ -5427,18 +5434,25 @@ 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;
 }
 
+static lang_output_section_statement_type *current_section;
+static lang_assignment_statement_type *current_assign;
+static bfd_boolean prefer_next_section;
+
 /* Worker function for lang_do_assignments.  Recursiveness goes here.  */
 
 static bfd_vma
 lang_do_assignments_1 (lang_statement_union_type *s,
                       lang_output_section_statement_type *current_os,
                       fill_type *fill,
-                      bfd_vma dot)
+                      bfd_vma dot,
+                      bfd_boolean *found_end)
 {
   for (; s != NULL; s = s->header.next)
     {
@@ -5446,7 +5460,7 @@ lang_do_assignments_1 (lang_statement_union_type *s,
        {
        case lang_constructors_statement_enum:
          dot = lang_do_assignments_1 (constructor_list.head,
-                                      current_os, fill, dot);
+                                      current_os, fill, dot, found_end);
          break;
 
        case lang_output_section_statement_enum:
@@ -5454,11 +5468,18 @@ lang_do_assignments_1 (lang_statement_union_type *s,
            lang_output_section_statement_type *os;
 
            os = &(s->output_section_statement);
+           os->after_end = *found_end;
            if (os->bfd_section != NULL && !os->ignored)
              {
+               if ((os->bfd_section->flags & SEC_ALLOC) != 0)
+                 {
+                   current_section = os;
+                   prefer_next_section = FALSE;
+                 }
                dot = os->bfd_section->vma;
 
-               lang_do_assignments_1 (os->children.head, os, os->fill, dot);
+               lang_do_assignments_1 (os->children.head,
+                                      os, os->fill, dot, found_end);
 
                /* .tbss sections effectively have zero size.  */
                if ((os->bfd_section->flags & SEC_HAS_CONTENTS) != 0
@@ -5475,7 +5496,7 @@ lang_do_assignments_1 (lang_statement_union_type *s,
        case lang_wild_statement_enum:
 
          dot = lang_do_assignments_1 (s->wild_statement.children.head,
-                                      current_os, fill, dot);
+                                      current_os, fill, dot, found_end);
          break;
 
        case lang_object_symbols_statement_enum:
@@ -5546,6 +5567,19 @@ lang_do_assignments_1 (lang_statement_union_type *s,
          break;
 
        case lang_assignment_statement_enum:
+         current_assign = &s->assignment_statement;
+         if (current_assign->exp->type.node_class != etree_assert)
+           {
+             const char *p = current_assign->exp->assign.dst;
+
+             if (current_os == abs_output_section && p[0] == '.' && p[1] == 0)
+               prefer_next_section = TRUE;
+
+             while (*p == '_')
+               ++p;
+             if (strcmp (p, "end") == 0)
+               *found_end = TRUE;
+           }
          exp_fold_tree (s->assignment_statement.exp,
                         current_os->bfd_section,
                         &dot);
@@ -5557,7 +5591,7 @@ lang_do_assignments_1 (lang_statement_union_type *s,
 
        case lang_group_statement_enum:
          dot = lang_do_assignments_1 (s->group_statement.children.head,
-                                      current_os, fill, dot);
+                                      current_os, fill, dot, found_end);
          break;
 
        case lang_insert_statement_enum:
@@ -5575,10 +5609,91 @@ lang_do_assignments_1 (lang_statement_union_type *s,
 }
 
 void
-lang_do_assignments (void)
+lang_do_assignments (lang_phase_type phase)
 {
+  bfd_boolean found_end = FALSE;
+
+  current_section = NULL;
+  prefer_next_section = FALSE;
+  expld.phase = phase;
   lang_statement_iteration++;
-  lang_do_assignments_1 (statement_list.head, abs_output_section, NULL, 0);
+  lang_do_assignments_1 (statement_list.head,
+                        abs_output_section, NULL, 0, &found_end);
+}
+
+/* For an assignment statement outside of an output section statement,
+   choose the best of neighbouring output sections to use for values
+   of "dot".  */
+
+asection *
+section_for_dot (void)
+{
+  asection *s;
+
+  /* Assignments belong to the previous output section, unless there
+     has been an assignment to "dot", in which case following
+     assignments belong to the next output section.  (The assumption
+     is that an assignment to "dot" is setting up the address for the
+     next output section.)  Except that past the assignment to "_end"
+     we always associate with the previous section.  This exception is
+     for targets like SH that define an alloc .stack or other
+     weirdness after non-alloc sections.  */
+  if (current_section == NULL || prefer_next_section)
+    {
+      lang_statement_union_type *stmt;
+      lang_output_section_statement_type *os;
+
+      for (stmt = (lang_statement_union_type *) current_assign;
+          stmt != NULL;
+          stmt = stmt->header.next)
+       if (stmt->header.type == lang_output_section_statement_enum)
+         break;
+
+      os = &stmt->output_section_statement;
+      while (os != NULL
+            && !os->after_end
+            && (os->bfd_section == NULL
+                || (os->bfd_section->flags & SEC_EXCLUDE) != 0
+                || bfd_section_removed_from_list (link_info.output_bfd,
+                                                  os->bfd_section)))
+       os = os->next;
+
+      if (current_section == NULL || os == NULL || !os->after_end)
+       {
+         if (os != NULL)
+           s = os->bfd_section;
+         else
+           s = link_info.output_bfd->section_last;
+         while (s != NULL
+                && ((s->flags & SEC_ALLOC) == 0
+                    || (s->flags & SEC_THREAD_LOCAL) != 0))
+           s = s->prev;
+         if (s != NULL)
+           return s;
+
+         return bfd_abs_section_ptr;
+       }
+    }
+
+  s = current_section->bfd_section;
+
+  /* The section may have been stripped.  */
+  while (s != NULL
+        && ((s->flags & SEC_EXCLUDE) != 0
+            || (s->flags & SEC_ALLOC) == 0
+            || (s->flags & SEC_THREAD_LOCAL) != 0
+            || bfd_section_removed_from_list (link_info.output_bfd, s)))
+    s = s->prev;
+  if (s == NULL)
+    s = link_info.output_bfd->sections;
+  while (s != NULL
+        && ((s->flags & SEC_ALLOC) == 0
+            || (s->flags & SEC_THREAD_LOCAL) != 0))
+    s = s->next;
+  if (s != NULL)
+    return s;
+
+  return bfd_abs_section_ptr;
 }
 
 /* Fix any .startof. or .sizeof. symbols.  When the assemblers see the
@@ -5610,8 +5725,8 @@ lang_set_startof (void)
       if (h != NULL && h->type == bfd_link_hash_undefined)
        {
          h->type = bfd_link_hash_defined;
-         h->u.def.value = bfd_get_section_vma (link_info.output_bfd, s);
-         h->u.def.section = bfd_abs_section_ptr;
+         h->u.def.value = 0;
+         h->u.def.section = s;
        }
 
       sprintf (buf, ".sizeof.%s", secname);
@@ -5711,9 +5826,6 @@ lang_end (void)
            }
        }
     }
-
-  /* Don't bfd_hash_table_free (&lang_definedness_table);
-     map file output may result in a call of lang_track_definedness.  */
 }
 
 /* This is a small function used when we want to ignore errors from
@@ -5738,6 +5850,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.flags.claimed)
+       continue;
+#endif /* ENABLE_PLUGINS */
       input_bfd = file->input_statement.the_bfd;
       compatible
        = bfd_arch_get_compatible (input_bfd, link_info.output_bfd,
@@ -5938,7 +6055,7 @@ lang_place_orphans (void)
              /* This section of the file is not attached, root
                 around for a sensible place for it to go.  */
 
-             if (file->just_syms_flag)
+             if (file->flags.just_syms)
                bfd_link_just_syms (file->the_bfd, s, &link_info);
              else if ((s->flags & SEC_EXCLUDE) != 0)
                s->output_section = bfd_abs_section_ptr;
@@ -5955,7 +6072,7 @@ lang_place_orphans (void)
                          = lang_output_section_statement_lookup (".bss", 0,
                                                                  TRUE);
                      lang_add_section (&default_common_section->children, s,
-                                       default_common_section);
+                                       NULL, default_common_section);
                    }
                }
              else
@@ -5977,7 +6094,7 @@ lang_place_orphans (void)
                          && (link_info.relocatable
                              || (s->flags & (SEC_LOAD | SEC_ALLOC)) == 0))
                        os->addr_tree = exp_intop (0);
-                     lang_add_section (&os->children, s, os);
+                     lang_add_section (&os->children, s, NULL, os);
                    }
                }
            }
@@ -6092,8 +6209,6 @@ lang_add_output (const char *name, int from_script)
     }
 }
 
-static lang_output_section_statement_type *current_section;
-
 static int
 topower (int x)
 {
@@ -6198,6 +6313,7 @@ static void
 gc_section_callback (lang_wild_statement_type *ptr,
                     struct wildcard_list *sec ATTRIBUTE_UNUSED,
                     asection *section,
+                    struct flag_info *sflag_info ATTRIBUTE_UNUSED,
                     lang_input_statement_type *file ATTRIBUTE_UNUSED,
                     void *data ATTRIBUTE_UNUSED)
 {
@@ -6249,6 +6365,10 @@ lang_gc_sections (void)
       LANG_FOR_EACH_INPUT_STATEMENT (f)
        {
          asection *sec;
+#ifdef ENABLE_PLUGINS
+         if (f->flags.claimed)
+           continue;
+#endif
          for (sec = f->the_bfd->sections; sec != NULL; sec = sec->next)
            if ((sec->flags & SEC_DEBUGGING) == 0)
              sec->flags &= ~SEC_EXCLUDE;
@@ -6265,6 +6385,7 @@ static void
 find_relro_section_callback (lang_wild_statement_type *ptr ATTRIBUTE_UNUSED,
                             struct wildcard_list *sec ATTRIBUTE_UNUSED,
                             asection *section,
+                            struct flag_info *sflag_info ATTRIBUTE_UNUSED,
                             lang_input_statement_type *file ATTRIBUTE_UNUSED,
                             void *data)
 {
@@ -6363,7 +6484,7 @@ lang_relax_sections (bfd_boolean need_layout)
 
              /* Do all the assignments with our current guesses as to
                 section sizes.  */
-             lang_do_assignments ();
+             lang_do_assignments (lang_assigning_phase_enum);
 
              /* We must do this after lang_do_assignments, because it uses
                 size.  */
@@ -6384,12 +6505,78 @@ lang_relax_sections (bfd_boolean need_layout)
   if (need_layout)
     {
       /* Final extra sizing to report errors.  */
-      lang_do_assignments ();
+      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.  */
+
+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->flags.claimed)
+       return claim1->flags.claim_archive ? lastobject : claim1;
+      /* Update lastobject if this is a real object file.  */
+      if (claim1->the_bfd && (claim1->the_bfd->my_archive == NULL))
+       lastobject = claim1;
+    }
+  /* 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)
 {
@@ -6407,31 +6594,69 @@ lang_process (void)
 
   /* Add to the hash table all undefineds on the command line.  */
   lang_place_undefineds ();
-  lang_place_defineds ();
 
   if (!bfd_section_already_linked_table_init ())
     einfo (_("%P%F: Failed to create hash table\n"));
 
   /* 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 ())
     {
-      union lang_statement_union **listend;
+      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.  */
-      listend = statement_list.tail;
-      ASSERT (!*listend);
+        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 ());
-      /* If any new files were added, they will be on the end of the
-        statement list, and we can open them now by getting open_input_bfds
-        to carry on from where it ended last time.  */
-      if (*listend)
-       open_input_bfds (*listend, FALSE);
+      /* Open any newly added files, updating the file chains.  */
+      link_info.loading_lto_outputs = TRUE;
+      open_input_bfds (*added.tail, OPEN_BFD_NORMAL);
+      /* Restore the global list pointer now they have all been added.  */
+      lang_list_remove_tail (stat_ptr, &added);
+      /* 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 */
 
@@ -6458,6 +6683,11 @@ lang_process (void)
      files.  */
   ldctor_build_sets ();
 
+  /* PR 13683: We must rerun the assignments prior to running garbage
+     collection in order to make sure that all symbol aliases are resolved.  */
+  lang_do_assignments (lang_mark_phase_enum);
+  expld.phase = lang_first_phase_enum;
+
   /* Remove unreferenced sections if asked to.  */
   lang_gc_sections ();
 
@@ -6469,6 +6699,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 ();
@@ -6522,8 +6753,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 ();
 
@@ -6567,10 +6797,12 @@ lang_add_wild (struct wildcard_spec *filespec,
   new_stmt = new_stat (lang_wild_statement, stat_ptr);
   new_stmt->filename = NULL;
   new_stmt->filenames_sorted = FALSE;
+  new_stmt->section_flag_list = NULL;
   if (filespec != NULL)
     {
       new_stmt->filename = filespec->name;
       new_stmt->filenames_sorted = filespec->sorted == by_name;
+      new_stmt->section_flag_list = filespec->section_flag_list;
     }
   new_stmt->section_list = section_list;
   new_stmt->keep_sections = keep_sections;
@@ -6692,10 +6924,6 @@ lang_add_assignment (etree_type *exp)
 {
   lang_assignment_statement_type *new_stmt;
 
-  extern int parsing_defsym;
-  if (parsing_defsym)
-    ldlang_add_def (exp->assign.dst);
-
   new_stmt = new_stat (lang_assignment_statement, stat_ptr);
   new_stmt->exp = exp;
   return new_stmt;
@@ -6710,15 +6938,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;
+  first_file->flags.real = TRUE;
 }
 
 void
@@ -6760,7 +6986,8 @@ lang_get_regions (lang_memory_region_type **region,
     *region = lang_memory_region_lookup (memspec, FALSE);
 
   if (have_lma && lma_memspec != 0)
-    einfo (_("%X%P:%S: section has both a load address and a load region\n"));
+    einfo (_("%X%P:%S: section has both a load address and a load region\n"),
+          NULL);
 }
 
 void
@@ -6774,11 +7001,13 @@ 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;
 
@@ -6787,69 +7016,6 @@ lang_leave_output_section_statement (fill_type *fill, const char *memspec,
   pop_stat_ptr ();
 }
 
-/* Create an absolute symbol with the given name with the value of the
-   address of first byte of the section named.
-
-   If the symbol already exists, then do nothing.  */
-
-void
-lang_abs_symbol_at_beginning_of (const char *secname, const char *name)
-{
-  struct bfd_link_hash_entry *h;
-
-  h = bfd_link_hash_lookup (link_info.hash, name, TRUE, TRUE, TRUE);
-  if (h == NULL)
-    einfo (_("%P%F: bfd_link_hash_lookup failed: %E\n"));
-
-  if (h->type == bfd_link_hash_new
-      || h->type == bfd_link_hash_undefined)
-    {
-      asection *sec;
-
-      h->type = bfd_link_hash_defined;
-
-      sec = bfd_get_section_by_name (link_info.output_bfd, secname);
-      if (sec == NULL)
-       h->u.def.value = 0;
-      else
-       h->u.def.value = bfd_get_section_vma (link_info.output_bfd, sec);
-
-      h->u.def.section = bfd_abs_section_ptr;
-    }
-}
-
-/* Create an absolute symbol with the given name with the value of the
-   address of the first byte after the end of the section named.
-
-   If the symbol already exists, then do nothing.  */
-
-void
-lang_abs_symbol_at_end_of (const char *secname, const char *name)
-{
-  struct bfd_link_hash_entry *h;
-
-  h = bfd_link_hash_lookup (link_info.hash, name, TRUE, TRUE, TRUE);
-  if (h == NULL)
-    einfo (_("%P%F: bfd_link_hash_lookup failed: %E\n"));
-
-  if (h->type == bfd_link_hash_new
-      || h->type == bfd_link_hash_undefined)
-    {
-      asection *sec;
-
-      h->type = bfd_link_hash_defined;
-
-      sec = bfd_get_section_by_name (link_info.output_bfd, secname);
-      if (sec == NULL)
-       h->u.def.value = 0;
-      else
-       h->u.def.value = (bfd_get_section_vma (link_info.output_bfd, sec)
-                         + TO_ADDR (sec->size));
-
-      h->u.def.section = bfd_abs_section_ptr;
-    }
-}
-
 void
 lang_statement_append (lang_statement_list_type *list,
                       lang_statement_union_type *element,
@@ -6945,7 +7111,8 @@ lang_new_phdr (const char *name,
        && (*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"));
+       einfo (_("%X%P:%S: PHDRS and FILEHDR are not supported"
+                " when prior PT_LOAD headers lack them\n"), NULL);
        hdrs = FALSE;
       }
 
@@ -7033,7 +7200,7 @@ lang_record_phdrs (void)
                    {
                      alc *= 2;
                      secs = (asection **) xrealloc (secs,
-                                                     alc * sizeof (asection *));
+                                                    alc * sizeof (asection *));
                    }
                  secs[c] = os->bfd_section;
                  ++c;
@@ -7234,8 +7401,11 @@ lang_leave_overlay (etree_type *lma_expr,
   /* After setting the size of the last section, set '.' to end of the
      overlay region.  */
   if (overlay_list != NULL)
-    overlay_list->os->update_dot_tree
-      = exp_assop ('=', ".", exp_binop ('+', overlay_vma, overlay_max));
+    {
+      overlay_list->os->update_dot = 1;
+      overlay_list->os->update_dot_tree
+       = exp_assign (".", exp_binop ('+', overlay_vma, overlay_max), FALSE);
+    }
 
   l = overlay_list;
   while (l != NULL)
@@ -7285,10 +7455,6 @@ lang_leave_overlay (etree_type *lma_expr,
 \f
 /* Version handling.  This is only useful for ELF.  */
 
-/* This global variable holds the version tree that we build.  */
-
-struct bfd_elf_version_tree *lang_elf_version_info;
-
 /* If PREV is NULL, return first version pattern matching particular symbol.
    If PREV is non-NULL, return first version pattern matching particular
    symbol after PREV (previously returned by lang_vers_match).  */
@@ -7298,19 +7464,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;
     }
@@ -7324,10 +7500,10 @@ lang_vers_match (struct bfd_elf_version_expr_head *head,
        case 0:
          if (head->mask & BFD_ELF_VERSION_C_TYPE)
            {
-             e.pattern = sym;
+             e.pattern = c_sym;
              expr = (struct bfd_elf_version_expr *)
-                  htab_find ((htab_t) head->htab, &e);
-             while (expr && strcmp (expr->pattern, sym) == 0)
+                 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
@@ -7339,7 +7515,7 @@ lang_vers_match (struct bfd_elf_version_expr_head *head,
            {
              e.pattern = cxx_sym;
              expr = (struct bfd_elf_version_expr *)
-                  htab_find ((htab_t) head->htab, &e);
+                 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;
@@ -7352,7 +7528,7 @@ lang_vers_match (struct bfd_elf_version_expr_head *head,
            {
              e.pattern = java_sym;
              expr = (struct bfd_elf_version_expr *)
-                  htab_find ((htab_t) head->htab, &e);
+                 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;
@@ -7385,12 +7561,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)
@@ -7618,8 +7796,8 @@ lang_register_vers_node (const char *name,
   if (name == NULL)
     name = "";
 
-  if ((name[0] == '\0' && lang_elf_version_info != NULL)
-      || (lang_elf_version_info && lang_elf_version_info->name[0] == '\0'))
+  if (link_info.version_info != NULL
+      && (name[0] == '\0' || link_info.version_info->name[0] == '\0'))
     {
       einfo (_("%X%P: anonymous version tag cannot be combined"
               " with other version tags\n"));
@@ -7628,7 +7806,7 @@ lang_register_vers_node (const char *name,
     }
 
   /* Make sure this node has a unique name.  */
-  for (t = lang_elf_version_info; t != NULL; t = t->next)
+  for (t = link_info.version_info; t != NULL; t = t->next)
     if (strcmp (t->name, name) == 0)
       einfo (_("%X%P: duplicate version tag `%s'\n"), name);
 
@@ -7640,14 +7818,14 @@ lang_register_vers_node (const char *name,
 
   for (e1 = version->globals.list; e1 != NULL; e1 = e1->next)
     {
-      for (t = lang_elf_version_info; t != NULL; t = t->next)
+      for (t = link_info.version_info; t != NULL; t = t->next)
        {
          struct bfd_elf_version_expr *e2;
 
          if (t->locals.htab && e1->literal)
            {
              e2 = (struct bfd_elf_version_expr *)
-                  htab_find ((htab_t) t->locals.htab, e1);
+                 htab_find ((htab_t) t->locals.htab, e1);
              while (e2 && strcmp (e1->pattern, e2->pattern) == 0)
                {
                  if (e1->mask == e2->mask)
@@ -7667,14 +7845,14 @@ lang_register_vers_node (const char *name,
 
   for (e1 = version->locals.list; e1 != NULL; e1 = e1->next)
     {
-      for (t = lang_elf_version_info; t != NULL; t = t->next)
+      for (t = link_info.version_info; t != NULL; t = t->next)
        {
          struct bfd_elf_version_expr *e2;
 
          if (t->globals.htab && e1->literal)
            {
              e2 = (struct bfd_elf_version_expr *)
-                  htab_find ((htab_t) t->globals.htab, e1);
+                 htab_find ((htab_t) t->globals.htab, e1);
              while (e2 && strcmp (e1->pattern, e2->pattern) == 0)
                {
                  if (e1->mask == e2->mask)
@@ -7703,7 +7881,7 @@ lang_register_vers_node (const char *name,
   else
     version->vernum = 0;
 
-  for (pp = &lang_elf_version_info; *pp != NULL; pp = &(*pp)->next)
+  for (pp = &link_info.version_info; *pp != NULL; pp = &(*pp)->next)
     ;
   *pp = version;
 }
@@ -7719,7 +7897,7 @@ lang_add_vers_depend (struct bfd_elf_version_deps *list, const char *name)
   ret = (struct bfd_elf_version_deps *) xmalloc (sizeof *ret);
   ret->next = list;
 
-  for (t = lang_elf_version_info; t != NULL; t = t->next)
+  for (t = link_info.version_info; t != NULL; t = t->next)
     {
       if (strcmp (t->name, name) == 0)
        {
@@ -7851,3 +8029,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.050462 seconds and 4 git commands to generate.