* ld-d10v/default_layout.d: Update for unused section removal.
[deliverable/binutils-gdb.git] / ld / ldlang.c
index 8daf9c5337a0644be91304beeed70f117a7e96bf..3e7a78cd0abb8ca1678627a4bbd77f4b323d3f6c 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
+   2001, 2002, 2003, 2004, 2005
    Free Software Foundation, Inc.
 
    This file is part of GLD, the Gnu Linker.
@@ -67,7 +67,6 @@ static struct bfd_hash_table lang_definedness_table;
 /* Forward declarations.  */
 static void exp_init_os (etree_type *);
 static void init_map_userdata (bfd *, asection *, void *);
-static bfd_boolean wildcardp (const char *);
 static lang_input_statement_type *lookup_name (const char *);
 static bfd_boolean load_symbols (lang_input_statement_type *,
                                 lang_statement_list_type *);
@@ -85,9 +84,6 @@ static bfd_boolean lang_one_common (struct bfd_link_hash_entry *, void *);
 static void lang_record_phdrs (void);
 static void lang_do_version_exports_section (void);
 
-typedef void (*callback_t) (lang_wild_statement_type *, struct wildcard_list *,
-                           asection *, lang_input_statement_type *, void *);
-
 /* Exported variables.  */
 lang_output_section_statement_type *abs_output_section;
 lang_statement_list_type lang_output_section_statement;
@@ -107,6 +103,13 @@ int lang_statement_iteration = 0;
 
 etree_type *base; /* Relocation base - or null */
 
+/* Return TRUE if the PATTERN argument is a wildcard pattern.
+   Although backslashes are treated specially if a pattern contains
+   wildcards, we do not consider the mere presence of a backslash to
+   be enough to cause the pattern to be treated as a wildcard.
+   That lets us handle DOS filenames more naturally.  */
+#define wildcardp(pattern) (strpbrk ((pattern), "?*[") != NULL)
+
 #define new_stat(x, y) \
   (x##_type *) new_statement (x##_enum, sizeof (x##_type), y)
 
@@ -149,21 +152,71 @@ unique_section_p (const asection *sec)
 
 /* Generic traversal routines for finding matching sections.  */
 
+/* Try processing a section against a wildcard.  This just calls
+   the callback unless the filename exclusion list is present
+   and excludes the file.  It's hardly ever present so this
+   function is very fast.  */
+
 static void
-walk_wild_section (lang_wild_statement_type *ptr,
-                  lang_input_statement_type *file,
-                  callback_t callback,
-                  void *data)
+walk_wild_consider_section (lang_wild_statement_type *ptr,
+                           lang_input_statement_type *file,
+                           asection *s,
+                           struct wildcard_list *sec,
+                           callback_t callback,
+                           void *data)
+{
+  bfd_boolean skip = FALSE;
+  struct name_list *list_tmp;
+
+  /* Don't process sections from files which were
+     excluded.  */
+  for (list_tmp = sec->spec.exclude_name_list;
+       list_tmp;
+       list_tmp = list_tmp->next)
+    {
+      bfd_boolean is_wildcard = wildcardp (list_tmp->name);
+      if (is_wildcard)
+       skip = fnmatch (list_tmp->name, file->filename, 0) == 0;
+      else
+       skip = strcmp (list_tmp->name, file->filename) == 0;
+
+      /* If this file is part of an archive, and the archive is
+        excluded, exclude this file.  */
+      if (! skip && file->the_bfd != NULL
+         && file->the_bfd->my_archive != NULL
+         && file->the_bfd->my_archive->filename != NULL)
+       {
+         if (is_wildcard)
+           skip = fnmatch (list_tmp->name,
+                           file->the_bfd->my_archive->filename,
+                           0) == 0;
+         else
+           skip = strcmp (list_tmp->name,
+                          file->the_bfd->my_archive->filename) == 0;
+       }
+
+      if (skip)
+       break;
+    }
+
+  if (!skip)
+    (*callback) (ptr, sec, s, file, data);
+}
+
+/* Lowest common denominator routine that can handle everything correctly,
+   but slowly.  */
+
+static void
+walk_wild_section_general (lang_wild_statement_type *ptr,
+                          lang_input_statement_type *file,
+                          callback_t callback,
+                          void *data)
 {
   asection *s;
-
-  if (file->just_syms_flag)
-    return;
+  struct wildcard_list *sec;
 
   for (s = file->the_bfd->sections; s != NULL; s = s->next)
     {
-      struct wildcard_list *sec;
-
       sec = ptr->section_list;
       if (sec == NULL)
        (*callback) (ptr, sec, s, file, data);
@@ -171,39 +224,8 @@ walk_wild_section (lang_wild_statement_type *ptr,
       while (sec != NULL)
        {
          bfd_boolean skip = FALSE;
-         struct name_list *list_tmp;
-
-         /* Don't process sections from files which were
-            excluded.  */
-         for (list_tmp = sec->spec.exclude_name_list;
-              list_tmp;
-              list_tmp = list_tmp->next)
-           {
-             if (wildcardp (list_tmp->name))
-               skip = fnmatch (list_tmp->name, file->filename, 0) == 0;
-             else
-               skip = strcmp (list_tmp->name, file->filename) == 0;
-
-             /* If this file is part of an archive, and the archive is
-                excluded, exclude this file.  */
-             if (! skip && file->the_bfd != NULL
-                 && file->the_bfd->my_archive != NULL
-                 && file->the_bfd->my_archive->filename != NULL)
-               {
-                 if (wildcardp (list_tmp->name))
-                   skip = fnmatch (list_tmp->name,
-                                   file->the_bfd->my_archive->filename,
-                                   0) == 0;
-                 else
-                   skip = strcmp (list_tmp->name,
-                                  file->the_bfd->my_archive->filename) == 0;
-               }
 
-             if (skip)
-               break;
-           }
-
-         if (!skip && sec->spec.name != NULL)
+         if (sec->spec.name != NULL)
            {
              const char *sname = bfd_get_section_name (file->the_bfd, s);
 
@@ -214,13 +236,381 @@ walk_wild_section (lang_wild_statement_type *ptr,
            }
 
          if (!skip)
-           (*callback) (ptr, sec, s, file, data);
+           walk_wild_consider_section (ptr, file, s, sec, callback, data);
 
          sec = sec->next;
        }
     }
 }
 
+/* Routines to find a single section given its name.  If there's more
+   than one section with that name, we report that.  */
+
+typedef struct
+{
+  asection *found_section;
+  bfd_boolean multiple_sections_found;
+} section_iterator_callback_data;
+
+static bfd_boolean
+section_iterator_callback (bfd *bfd ATTRIBUTE_UNUSED, asection *s, void *data)
+{
+  section_iterator_callback_data *d = data;
+
+  if (d->found_section != NULL)
+    {
+      d->multiple_sections_found = TRUE;
+      return TRUE;
+    }
+
+  d->found_section = s;
+  return FALSE;
+}
+
+static asection *
+find_section (lang_input_statement_type *file,
+             struct wildcard_list *sec,
+             bfd_boolean *multiple_sections_found)
+{
+  section_iterator_callback_data cb_data = { NULL, FALSE };
+
+  bfd_get_section_by_name_if (file->the_bfd, sec->spec.name, 
+                             section_iterator_callback, &cb_data);
+  *multiple_sections_found = cb_data.multiple_sections_found;
+  return cb_data.found_section;
+}
+
+/* Code for handling simple wildcards without going through fnmatch,
+   which can be expensive because of charset translations etc.  */
+
+/* A simple wild is a literal string followed by a single '*',
+   where the literal part is at least 4 characters long.  */
+
+static bfd_boolean
+is_simple_wild (const char *name)
+{
+  size_t len = strcspn (name, "*?[");
+  return len >= 4 && name[len] == '*' && name[len + 1] == '\0';
+}
+
+static bfd_boolean
+match_simple_wild (const char *pattern, const char *name)
+{
+  /* The first four characters of the pattern are guaranteed valid
+     non-wildcard characters.  So we can go faster.  */
+  if (pattern[0] != name[0] || pattern[1] != name[1]
+      || pattern[2] != name[2] || pattern[3] != name[3])
+    return FALSE;
+
+  pattern += 4;
+  name += 4;
+  while (*pattern != '*')
+    if (*name++ != *pattern++)
+      return FALSE;
+
+  return TRUE;
+}
+
+/* Specialized, optimized routines for handling different kinds of
+   wildcards */
+
+static void
+walk_wild_section_specs1_wild0 (lang_wild_statement_type *ptr,
+                               lang_input_statement_type *file,
+                               callback_t callback,
+                               void *data)
+{
+  /* We can just do a hash lookup for the section with the right name.
+     But if that lookup discovers more than one section with the name
+     (should be rare), we fall back to the general algorithm because
+     we would otherwise have to sort the sections to make sure they
+     get processed in the bfd's order.  */
+  bfd_boolean multiple_sections_found;
+  struct wildcard_list *sec0 = ptr->handler_data[0];
+  asection *s0 = find_section (file, sec0, &multiple_sections_found);
+
+  if (multiple_sections_found)
+    walk_wild_section_general (ptr, file, callback, data);
+  else if (s0)
+    walk_wild_consider_section (ptr, file, s0, sec0, callback, data);
+}
+
+static void
+walk_wild_section_specs1_wild1 (lang_wild_statement_type *ptr,
+                               lang_input_statement_type *file,
+                               callback_t callback,
+                               void *data)
+{
+  asection *s;
+  struct wildcard_list *wildsec0 = ptr->handler_data[0];
+
+  for (s = file->the_bfd->sections; s != NULL; s = s->next)
+    {
+      const char *sname = bfd_get_section_name (file->the_bfd, s);
+      bfd_boolean skip = !match_simple_wild (wildsec0->spec.name, sname);
+
+      if (!skip)
+       walk_wild_consider_section (ptr, file, s, wildsec0, callback, data);
+    }
+}
+
+static void
+walk_wild_section_specs2_wild1 (lang_wild_statement_type *ptr,
+                               lang_input_statement_type *file,
+                               callback_t callback,
+                               void *data)
+{
+  asection *s;
+  struct wildcard_list *sec0 = ptr->handler_data[0];
+  struct wildcard_list *wildsec1 = ptr->handler_data[1];
+  bfd_boolean multiple_sections_found;
+  asection *s0 = find_section (file, sec0, &multiple_sections_found);
+
+  if (multiple_sections_found)
+    {
+      walk_wild_section_general (ptr, file, callback, data);
+      return;
+    }
+
+  /* Note that if the section was not found, s0 is NULL and
+     we'll simply never succeed the s == s0 test below.  */
+  for (s = file->the_bfd->sections; s != NULL; s = s->next)
+    {
+      /* Recall that in this code path, a section cannot satisfy more
+        than one spec, so if s == s0 then it cannot match
+        wildspec1.  */
+      if (s == s0)
+       walk_wild_consider_section (ptr, file, s, sec0, callback, data);
+      else
+       {
+         const char *sname = bfd_get_section_name (file->the_bfd, s);
+         bfd_boolean skip = !match_simple_wild (wildsec1->spec.name, sname);
+
+         if (!skip)
+           walk_wild_consider_section (ptr, file, s, wildsec1, callback,
+                                       data);
+       }
+    }
+}
+
+static void
+walk_wild_section_specs3_wild2 (lang_wild_statement_type *ptr,
+                               lang_input_statement_type *file,
+                               callback_t callback,
+                               void *data)
+{
+  asection *s;
+  struct wildcard_list *sec0 = ptr->handler_data[0];
+  struct wildcard_list *wildsec1 = ptr->handler_data[1];
+  struct wildcard_list *wildsec2 = ptr->handler_data[2];
+  bfd_boolean multiple_sections_found;
+  asection *s0 = find_section (file, sec0, &multiple_sections_found);
+
+  if (multiple_sections_found)
+    {
+      walk_wild_section_general (ptr, file, callback, data);
+      return;
+    }
+
+  for (s = file->the_bfd->sections; s != NULL; s = s->next)
+    {
+      if (s == s0)
+       walk_wild_consider_section (ptr, file, s, sec0, callback, data);
+      else
+       {
+         const char *sname = bfd_get_section_name (file->the_bfd, s);
+         bfd_boolean skip = !match_simple_wild (wildsec1->spec.name, sname);
+
+         if (!skip)
+           walk_wild_consider_section (ptr, file, s, wildsec1, callback, data);
+         else
+           {
+             skip = !match_simple_wild (wildsec2->spec.name, sname);
+             if (!skip)
+               walk_wild_consider_section (ptr, file, s, wildsec2, callback,
+                                           data);
+           }
+       }
+    }
+}
+
+static void
+walk_wild_section_specs4_wild2 (lang_wild_statement_type *ptr,
+                               lang_input_statement_type *file,
+                               callback_t callback,
+                               void *data)
+{
+  asection *s;
+  struct wildcard_list *sec0 = ptr->handler_data[0];
+  struct wildcard_list *sec1 = ptr->handler_data[1];
+  struct wildcard_list *wildsec2 = ptr->handler_data[2];
+  struct wildcard_list *wildsec3 = ptr->handler_data[3];
+  bfd_boolean multiple_sections_found;
+  asection *s0 = find_section (file, sec0, &multiple_sections_found), *s1;
+
+  if (multiple_sections_found)
+    {
+      walk_wild_section_general (ptr, file, callback, data);
+      return;
+    }
+
+  s1 = find_section (file, sec1, &multiple_sections_found);
+  if (multiple_sections_found)
+    {
+      walk_wild_section_general (ptr, file, callback, data);
+      return;
+    }
+
+  for (s = file->the_bfd->sections; s != NULL; s = s->next)
+    {
+      if (s == s0)
+       walk_wild_consider_section (ptr, file, s, sec0, callback, data);
+      else
+       if (s == s1)
+         walk_wild_consider_section (ptr, file, s, sec1, callback, data);
+       else
+         {
+           const char *sname = bfd_get_section_name (file->the_bfd, s);
+           bfd_boolean skip = !match_simple_wild (wildsec2->spec.name,
+                                                  sname);
+
+           if (!skip)
+             walk_wild_consider_section (ptr, file, s, wildsec2, callback,
+                                         data);
+           else
+             {
+               skip = !match_simple_wild (wildsec3->spec.name, sname);
+               if (!skip)
+                 walk_wild_consider_section (ptr, file, s, wildsec3,
+                                             callback, data);
+             }
+         }
+    }
+}
+
+static void
+walk_wild_section (lang_wild_statement_type *ptr,
+                  lang_input_statement_type *file,
+                  callback_t callback,
+                  void *data)
+{
+  if (file->just_syms_flag)
+    return;
+
+  (*ptr->walk_wild_section_handler) (ptr, file, callback, data);
+}
+
+/* Returns TRUE when name1 is a wildcard spec that might match
+   something name2 can match.  We're conservative: we return FALSE
+   only if the prefixes of name1 and name2 are different up to the
+   first wildcard character.  */
+
+static bfd_boolean
+wild_spec_can_overlap (const char *name1, const char *name2)
+{
+  size_t prefix1_len = strcspn (name1, "?*[");
+  size_t prefix2_len = strcspn (name2, "?*[");
+  size_t min_prefix_len;
+
+  /* Note that if there is no wildcard character, then we treat the
+     terminating 0 as part of the prefix.  Thus ".text" won't match
+     ".text." or ".text.*", for example.  */
+  if (name1[prefix1_len] == '\0')
+    prefix1_len++;
+  if (name2[prefix2_len] == '\0')
+    prefix2_len++;
+
+  min_prefix_len = prefix1_len < prefix2_len ? prefix1_len : prefix2_len;
+
+  return memcmp (name1, name2, min_prefix_len) == 0;
+}
+
+/* Select specialized code to handle various kinds of wildcard
+   statements.  */
+
+static void
+analyze_walk_wild_section_handler (lang_wild_statement_type *ptr)
+{
+  int sec_count = 0;
+  int wild_name_count = 0;
+  struct wildcard_list *sec;
+  int signature;
+  int data_counter;
+
+  ptr->walk_wild_section_handler = walk_wild_section_general;
+
+  /* Count how many wildcard_specs there are, and how many of those
+     actually use wildcards in the name.  Also, bail out if any of the
+     wildcard names are NULL. (Can this actually happen?
+     walk_wild_section used to test for it.)  And bail out if any
+     of the wildcards are more complex than a simple string
+     ending in a single '*'.  */
+  for (sec = ptr->section_list; sec != NULL; sec = sec->next)
+    {
+      ++sec_count;
+      if (sec->spec.name == NULL)
+       return;
+      if (wildcardp (sec->spec.name))
+       {
+         ++wild_name_count;
+         if (!is_simple_wild (sec->spec.name))
+           return;
+       }
+    }
+
+  /* The zero-spec case would be easy to optimize but it doesn't
+     happen in practice.  Likewise, more than 4 specs doesn't
+     happen in practice.  */
+  if (sec_count == 0 || sec_count > 4)
+    return;
+
+  /* Check that no two specs can match the same section.  */
+  for (sec = ptr->section_list; sec != NULL; sec = sec->next)
+    {
+      struct wildcard_list *sec2;
+      for (sec2 = sec->next; sec2 != NULL; sec2 = sec2->next)
+       {
+         if (wild_spec_can_overlap (sec->spec.name, sec2->spec.name))
+           return;
+       }
+    }
+
+  signature = (sec_count << 8) + wild_name_count;
+  switch (signature)
+    {
+    case 0x0100:
+      ptr->walk_wild_section_handler = walk_wild_section_specs1_wild0;
+      break;
+    case 0x0101:
+      ptr->walk_wild_section_handler = walk_wild_section_specs1_wild1;
+      break;
+    case 0x0201:
+      ptr->walk_wild_section_handler = walk_wild_section_specs2_wild1;
+      break;
+    case 0x0302:
+      ptr->walk_wild_section_handler = walk_wild_section_specs3_wild2;
+      break;
+    case 0x0402:
+      ptr->walk_wild_section_handler = walk_wild_section_specs4_wild2;
+      break;
+    default:
+      return;
+    }
+
+  /* Now fill the data array with pointers to the specs, first the
+     specs with non-wildcard names, then the specs with wildcard
+     names.  It's OK to process the specs in different order from the
+     given order, because we've already determined that no section
+     will match more than one spec.  */
+  data_counter = 0;
+  for (sec = ptr->section_list; sec != NULL; sec = sec->next)
+    if (!wildcardp (sec->spec.name))
+      ptr->handler_data[data_counter++] = sec;
+  for (sec = ptr->section_list; sec != NULL; sec = sec->next)
+    if (wildcardp (sec->spec.name))
+      ptr->handler_data[data_counter++] = sec;
+}
+
 /* Handle a wild statement for a single file F.  */
 
 static void
@@ -454,6 +844,7 @@ new_afile (const char *name,
   p->next = NULL;
   p->symbol_count = 0;
   p->dynamic = config.dynamic_link;
+  p->add_needed = add_needed;
   p->as_needed = as_needed;
   p->whole_archive = whole_archive;
   p->loaded = FALSE;
@@ -499,8 +890,8 @@ lang_init (void)
      simpler to re-use working machinery than using a linked list in terms
      of code-complexity here in ld, besides the initialization which just
      looks like other code here.  */
-  if (bfd_hash_table_init_n (&lang_definedness_table,
-                            lang_definedness_newfunc, 3) != TRUE)
+  if (!bfd_hash_table_init_n (&lang_definedness_table,
+                             lang_definedness_newfunc, 3))
     einfo (_("%P%F: out of memory during initialization"));
 
   /* Callers of exp_fold_tree need to increment this.  */
@@ -546,20 +937,6 @@ lang_memory_region_lookup (const char *const name, bfd_boolean create)
        return p;
       }
 
-#if 0
-  /* This code used to always use the first region in the list as the
-     default region.  I changed it to instead use a region
-     encompassing all of memory as the default region.  This permits
-     NOLOAD sections to work reasonably without requiring a region.
-     People should specify what region they mean, if they really want
-     a region.  */
-  if (strcmp (name, DEFAULT_MEMORY_REGION) == 0)
-    {
-      if (lang_memory_region_list != NULL)
-       return lang_memory_region_list;
-    }
-#endif
-
   if (!create && strcmp (name, DEFAULT_MEMORY_REGION))
     einfo (_("%P:%S: warning: memory region %s not declared\n"), name);
 
@@ -605,12 +982,12 @@ lang_memory_default (asection *section)
 static lang_output_section_statement_type *
 lang_output_section_find_1 (const char *const name, int constraint)
 {
-  lang_statement_union_type *u;
   lang_output_section_statement_type *lookup;
 
-  for (u = lang_output_section_statement.head; u != NULL; u = lookup->next)
+  for (lookup = &lang_output_section_statement.head->output_section_statement;
+       lookup != NULL;
+       lookup = lookup->next)
     {
-      lookup = &u->output_section_statement;
       if (strcmp (name, lookup->name) == 0
          && lookup->constraint != -1
          && (constraint == 0 || constraint == lookup->constraint))
@@ -640,33 +1017,417 @@ lang_output_section_statement_lookup_1 (const char *const name, int constraint)
       lookup->block_value = 1;
       lookup->name = name;
 
-      lookup->next = NULL;
-      lookup->bfd_section = NULL;
-      lookup->processed = 0;
-      lookup->constraint = constraint;
-      lookup->sectype = normal_section;
-      lookup->addr_tree = NULL;
-      lang_list_init (&lookup->children);
+      lookup->next = NULL;
+      lookup->bfd_section = NULL;
+      lookup->processed = 0;
+      lookup->constraint = constraint;
+      lookup->sectype = normal_section;
+      lookup->addr_tree = NULL;
+      lang_list_init (&lookup->children);
+
+      lookup->memspec = NULL;
+      lookup->flags = 0;
+      lookup->subsection_alignment = -1;
+      lookup->section_alignment = -1;
+      lookup->load_base = NULL;
+      lookup->update_dot_tree = NULL;
+      lookup->phdrs = NULL;
+
+      lang_statement_append (&lang_output_section_statement,
+                            (lang_statement_union_type *) lookup,
+                            (lang_statement_union_type **) &lookup->next);
+    }
+  return lookup;
+}
+
+lang_output_section_statement_type *
+lang_output_section_statement_lookup (const char *const name)
+{
+  return lang_output_section_statement_lookup_1 (name, 0);
+}
+
+/* A variant of lang_output_section_find used by place_orphan.
+   Returns the output statement that should precede a new output
+   statement for SEC.  If an exact match is found on certain flags,
+   sets *EXACT too.  */
+
+lang_output_section_statement_type *
+lang_output_section_find_by_flags (const asection *sec,
+                                  lang_output_section_statement_type **exact)
+{
+  lang_output_section_statement_type *first, *look, *found;
+  flagword flags;
+
+  /* We know the first statement on this list is *ABS*.  May as well
+     skip it.  */
+  first = &lang_output_section_statement.head->output_section_statement;
+  first = first->next;
+
+  /* First try for an exact match.  */
+  found = NULL;
+  for (look = first; look; look = look->next)
+    {
+      flags = look->flags;
+      if (look->bfd_section != NULL)
+       flags = look->bfd_section->flags;
+      flags ^= sec->flags;
+      if (!(flags & (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_READONLY
+                    | SEC_CODE | SEC_SMALL_DATA | SEC_THREAD_LOCAL)))
+       found = look;
+    }
+  if (found != NULL)
+    {
+      *exact = found;
+      return found;
+    }
+
+  if (sec->flags & SEC_CODE)
+    {
+      /* Try for a rw code section.  */
+      for (look = first; look; look = look->next)
+       {
+         flags = look->flags;
+         if (look->bfd_section != NULL)
+           flags = look->bfd_section->flags;
+         flags ^= sec->flags;
+         if (!(flags & (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD
+                        | SEC_CODE | SEC_SMALL_DATA | SEC_THREAD_LOCAL)))
+           found = look;
+       }
+      return found;
+    }
+
+  if (sec->flags & (SEC_READONLY | SEC_THREAD_LOCAL))
+    {
+      /* .rodata can go after .text, .sdata2 after .rodata.  */
+      for (look = first; look; look = look->next)
+       {
+         flags = look->flags;
+         if (look->bfd_section != NULL)
+           flags = look->bfd_section->flags;
+         flags ^= sec->flags;
+         if (!(flags & (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD
+                        | SEC_READONLY))
+             && !(look->flags & (SEC_SMALL_DATA | SEC_THREAD_LOCAL)))
+           found = look;
+       }
+      return found;
+    }
+
+  if (sec->flags & SEC_SMALL_DATA)
+    {
+      /* .sdata goes after .data, .sbss after .sdata.  */
+      for (look = first; look; look = look->next)
+       {
+         flags = look->flags;
+         if (look->bfd_section != NULL)
+           flags = look->bfd_section->flags;
+         flags ^= sec->flags;
+         if (!(flags & (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD
+                        | SEC_THREAD_LOCAL))
+             || ((look->flags & SEC_SMALL_DATA)
+                 && !(sec->flags & SEC_HAS_CONTENTS)))
+           found = look;
+       }
+      return found;
+    }
+
+  if (sec->flags & SEC_HAS_CONTENTS)
+    {
+      /* .data goes after .rodata.  */
+      for (look = first; look; look = look->next)
+       {
+         flags = look->flags;
+         if (look->bfd_section != NULL)
+           flags = look->bfd_section->flags;
+         flags ^= sec->flags;
+         if (!(flags & (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD
+                        | SEC_SMALL_DATA | SEC_THREAD_LOCAL)))
+           found = look;
+       }
+      return found;
+    }
+
+  /* .bss goes last.  */
+  for (look = first; look; look = look->next)
+    {
+      flags = look->flags;
+      if (look->bfd_section != NULL)
+       flags = look->bfd_section->flags;
+      flags ^= sec->flags;
+      if (!(flags & SEC_ALLOC))
+       found = look;
+    }
+
+  return found;
+}
+
+/* Find the last output section before given output statement.
+   Used by place_orphan.  */
+
+static asection *
+output_prev_sec_find (lang_output_section_statement_type *os)
+{
+  asection *s = (asection *) NULL;
+  lang_output_section_statement_type *lookup;
+
+  for (lookup = &lang_output_section_statement.head->output_section_statement;
+       lookup != NULL;
+       lookup = lookup->next)
+    {
+      if (lookup->constraint == -1)
+       continue;
+      if (lookup == os)
+       return s;
+
+      if (lookup->bfd_section != NULL && lookup->bfd_section->owner != NULL)
+       s = lookup->bfd_section;
+    }
+
+  return NULL;
+}
+
+lang_output_section_statement_type *
+lang_insert_orphan (lang_input_statement_type *file,
+                   asection *s,
+                   const char *secname,
+                   lang_output_section_statement_type *after,
+                   struct orphan_save *place,
+                   etree_type *address,
+                   lang_statement_list_type *add_child)
+{
+  lang_statement_list_type *old;
+  lang_statement_list_type add;
+  const char *ps;
+  etree_type *load_base;
+  lang_output_section_statement_type *os;
+  lang_output_section_statement_type **os_tail;
+  asection **bfd_tail;
+
+  /* Start building a list of statements for this section.
+     First save the current statement pointer.  */
+  old = stat_ptr;
+
+  /* If we have found an appropriate place for the output section
+     statements for this orphan, add them to our own private list,
+     inserting them later into the global statement list.  */
+  if (after != NULL)
+    {
+      stat_ptr = &add;
+      lang_list_init (stat_ptr);
+    }
+
+  ps = NULL;
+  if (config.build_constructors)
+    {
+      /* If the name of the section is representable in C, then create
+        symbols to mark the start and the end of the section.  */
+      for (ps = secname; *ps != '\0'; ps++)
+       if (! ISALNUM ((unsigned char) *ps) && *ps != '_')
+         break;
+      if (*ps == '\0')
+       {
+         char *symname;
+         etree_type *e_align;
+
+         symname = (char *) xmalloc (ps - secname + sizeof "__start_" + 1);
+         symname[0] = bfd_get_symbol_leading_char (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_assop ('=', symname,
+                                         exp_nameop (NAME, ".")));
+       }
+    }
+
+  if (link_info.relocatable || (s->flags & (SEC_LOAD | SEC_ALLOC)) == 0)
+    address = exp_intop (0);
+
+  load_base = NULL;
+  if (after != NULL && after->load_base != NULL)
+    {
+      etree_type *lma_from_vma;
+      lma_from_vma = exp_binop ('-', after->load_base,
+                               exp_nameop (ADDR, after->name));
+      load_base = exp_binop ('+', lma_from_vma,
+                            exp_nameop (ADDR, secname));
+    }
+
+  os_tail = ((lang_output_section_statement_type **)
+            lang_output_section_statement.tail);
+  bfd_tail = output_bfd->section_tail;
+  os = lang_enter_output_section_statement (secname, address, 0, NULL, NULL,
+                                           load_base, 0);
+
+  if (add_child == NULL)
+    add_child = &os->children;
+  lang_add_section (add_child, s, os, file);
+
+  lang_leave_output_section_statement (0, "*default*", NULL, NULL);
+
+  if (config.build_constructors && *ps == '\0')
+    {
+      char *symname;
+
+      /* lang_leave_ouput_section_statement resets stat_ptr.
+        Put stat_ptr back where we want it.  */
+      if (after != NULL)
+       stat_ptr = &add;
+
+      symname = (char *) xmalloc (ps - secname + sizeof "__stop_" + 1);
+      symname[0] = bfd_get_symbol_leading_char (output_bfd);
+      sprintf (symname + (symname[0] != 0), "__stop_%s", secname);
+      lang_add_assignment (exp_assop ('=', symname,
+                                     exp_nameop (NAME, ".")));
+    }
+
+  /* Restore the global list pointer.  */
+  if (after != NULL)
+    stat_ptr = old;
+
+  if (after != NULL && os->bfd_section != NULL)
+    {
+      asection *snew;
+
+      snew = os->bfd_section;
+
+      /* Shuffle the bfd section list to make the output file look
+        neater.  This is really only cosmetic.  */
+      if (place->section == NULL
+         && after != (&lang_output_section_statement.head
+                      ->output_section_statement))
+       {
+         asection *bfd_section = after->bfd_section;
+
+         /* If the output statement hasn't been used to place any input
+            sections (and thus doesn't have an output bfd_section),
+            look for the closest prior output statement having an
+            output section.  */
+         if (bfd_section == NULL)
+           bfd_section = output_prev_sec_find (after);
+
+         if (bfd_section != NULL && bfd_section != snew)
+           place->section = &bfd_section->next;
+       }
 
-      lookup->memspec = NULL;
-      lookup->flags = 0;
-      lookup->subsection_alignment = -1;
-      lookup->section_alignment = -1;
-      lookup->load_base = NULL;
-      lookup->update_dot_tree = NULL;
-      lookup->phdrs = NULL;
+      if (place->section == NULL)
+       place->section = &output_bfd->sections;
+
+      /* Unlink the section.  */
+      ASSERT (*bfd_tail == snew);
+      bfd_section_list_remove (output_bfd, bfd_tail);
+
+      /* Now tack it back on in the right place.  */
+      bfd_section_list_insert (output_bfd, place->section, snew);
+
+      /* Save the end of this list.  Further ophans of this type will
+        follow the one we've just added.  */
+      place->section = &snew->next;
+
+      /* The following is non-cosmetic.  We try to put the output
+        statements in some sort of reasonable order here, because they
+        determine the final load addresses of the orphan sections.
+        In addition, placing output statements in the wrong order may
+        require extra segments.  For instance, given a typical
+        situation of all read-only sections placed in one segment and
+        following that a segment containing all the read-write
+        sections, we wouldn't want to place an orphan read/write
+        section before or amongst the read-only ones.  */
+      if (add.head != NULL)
+       {
+         lang_output_section_statement_type *newly_added_os;
 
-      lang_statement_append (&lang_output_section_statement,
-                            (lang_statement_union_type *) lookup,
-                            &lookup->next);
-    }
-  return lookup;
-}
+         if (place->stmt == NULL)
+           {
+             lang_statement_union_type **where;
+             lang_statement_union_type **assign = NULL;
+
+             /* Look for a suitable place for the new statement list.
+                The idea is to skip over anything that might be inside
+                a SECTIONS {} statement in a script, before we find
+                another output_section_statement.  Assignments to "dot"
+                before an output section statement are assumed to
+                belong to it.  */
+             for (where = &after->header.next;
+                  *where != NULL;
+                  where = &(*where)->header.next)
+               {
+                 switch ((*where)->header.type)
+                   {
+                   case lang_assignment_statement_enum:
+                     if (assign == NULL)
+                       {
+                         lang_assignment_statement_type *ass;
+                         ass = &(*where)->assignment_statement;
+                         if (ass->exp->type.node_class != etree_assert
+                             && ass->exp->assign.dst[0] == '.'
+                             && ass->exp->assign.dst[1] == 0)
+                           assign = where;
+                       }
+                     continue;
+                   case lang_wild_statement_enum:
+                   case lang_input_section_enum:
+                   case lang_object_symbols_statement_enum:
+                   case lang_fill_statement_enum:
+                   case lang_data_statement_enum:
+                   case lang_reloc_statement_enum:
+                   case lang_padding_statement_enum:
+                   case lang_constructors_statement_enum:
+                     assign = NULL;
+                     continue;
+                   case lang_output_section_statement_enum:
+                     if (assign != NULL)
+                       where = assign;
+                   case lang_input_statement_enum:
+                   case lang_address_statement_enum:
+                   case lang_target_statement_enum:
+                   case lang_output_statement_enum:
+                   case lang_group_statement_enum:
+                   case lang_afile_asection_pair_statement_enum:
+                     break;
+                   }
+                 break;
+               }
 
-lang_output_section_statement_type *
-lang_output_section_statement_lookup (const char *const name)
-{
-  return lang_output_section_statement_lookup_1 (name, 0);
+             *add.tail = *where;
+             *where = add.head;
+
+             place->os_tail = &after->next;
+           }
+         else
+           {
+             /* Put it after the last orphan statement we added.  */
+             *add.tail = *place->stmt;
+             *place->stmt = add.head;
+           }
+
+         /* Fix the global list pointer if we happened to tack our
+            new list at the tail.  */
+         if (*old->tail == add.head)
+           old->tail = add.tail;
+
+         /* Save the end of this list.  */
+         place->stmt = add.tail;
+
+         /* Do the same for the list of output section statements.  */
+         newly_added_os = *os_tail;
+         *os_tail = NULL;
+         newly_added_os->next = *place->os_tail;
+         *place->os_tail = newly_added_os;
+         place->os_tail = &newly_added_os->next;
+
+         /* Fixing the global list pointer here is a little different.
+            We added to the list in lang_enter_output_section_statement,
+            trimmed off the new output_section_statment above when
+            assigning *os_tail = NULL, but possibly added it back in
+            the same place when assigning *place->os_tail.  */
+         if (*os_tail == NULL)
+           lang_output_section_statement.tail
+             = (lang_statement_union_type **) os_tail;
+       }
+    }
+  return os;
 }
 
 static void
@@ -784,9 +1545,10 @@ sort_def_symbol (hash_entry, info)
        }
       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->entry = hash_entry;
-      *ud->map_symbol_def_tail = def;
+      *(ud->map_symbol_def_tail) = def;
       ud->map_symbol_def_tail = &def->next;
     }
   return TRUE;
@@ -797,16 +1559,12 @@ sort_def_symbol (hash_entry, info)
 static void
 init_os (lang_output_section_statement_type *s)
 {
-  lean_section_userdata_type *new;
-
   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);
 
-  new = stat_alloc (SECTION_USERDATA_SIZE);
-
   s->bfd_section = bfd_get_section_by_name (output_bfd, s->name);
   if (s->bfd_section == NULL)
     s->bfd_section = bfd_make_section (output_bfd, s->name);
@@ -820,7 +1578,14 @@ init_os (lang_output_section_statement_type *s)
   /* We initialize an output sections output offset to minus its own
      vma to allow us to output a section through itself.  */
   s->bfd_section->output_offset = 0;
-  get_userdata (s->bfd_section) = new;
+  if (!command_line.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;
+    }
+
 
   /* If there is a base address, make sure that any sections it might
      mention are initialized.  */
@@ -857,7 +1622,7 @@ exp_init_os (etree_type *exp)
     case etree_assert:
       exp_init_os (exp->assert_s.child);
       break;
-      
+
     case etree_unary:
       exp_init_os (exp->unary.child);
       break;
@@ -883,175 +1648,21 @@ exp_init_os (etree_type *exp)
     }
 }
 \f
-/* Sections marked with the SEC_LINK_ONCE flag should only be linked
-   once into the output.  This routine checks each section, and
-   arrange to discard it if a section of the same name has already
-   been linked.  If the section has COMDAT information, then it uses
-   that to decide whether the section should be included.  This code
-   assumes that all relevant sections have the SEC_LINK_ONCE flag set;
-   that is, it does not depend solely upon the section name.
-   section_already_linked is called via bfd_map_over_sections.  */
-
-/* This is the shape of the elements inside the already_linked hash
-   table. It maps a name onto a list of already_linked elements with
-   the same name.  It's possible to get more than one element in a
-   list if the COMDAT sections have different names.  */
-
-struct already_linked_hash_entry
-{
-  struct bfd_hash_entry root;
-  struct already_linked *entry;
-};
-
-struct already_linked
-{
-  struct already_linked *next;
-  asection *sec;
-};
-
-/* The hash table.  */
-
-static struct bfd_hash_table already_linked_table;
-
 static void
 section_already_linked (bfd *abfd, asection *sec, void *data)
 {
   lang_input_statement_type *entry = data;
-  flagword flags;
-  const char *name;
-  struct already_linked *l;
-  struct already_linked_hash_entry *already_linked_list;
 
   /* If we are only reading symbols from this object, then we want to
      discard all sections.  */
   if (entry->just_syms_flag)
     {
-      bfd_link_just_syms (sec, &link_info);
+      bfd_link_just_syms (abfd, sec, &link_info);
       return;
     }
 
-  flags = sec->flags;
-  if ((flags & SEC_LINK_ONCE) == 0)
-    return;
-
-  /* FIXME: When doing a relocatable link, we may have trouble
-     copying relocations in other sections that refer to local symbols
-     in the section being discarded.  Those relocations will have to
-     be converted somehow; as of this writing I'm not sure that any of
-     the backends handle that correctly.
-
-     It is tempting to instead not discard link once sections when
-     doing a relocatable link (technically, they should be discarded
-     whenever we are building constructors).  However, that fails,
-     because the linker winds up combining all the link once sections
-     into a single large link once section, which defeats the purpose
-     of having link once sections in the first place.
-
-     Also, not merging link once sections in a relocatable link
-     causes trouble for MIPS ELF, which relies on link once semantics
-     to handle the .reginfo section correctly.  */
-
-  name = bfd_get_section_name (abfd, sec);
-
-  already_linked_list =
-    ((struct already_linked_hash_entry *)
-     bfd_hash_lookup (&already_linked_table, name, TRUE, FALSE));
-
-  for (l = already_linked_list->entry; l != NULL; l = l->next)
-    {
-      if (sec->comdat == NULL
-         || l->sec->comdat == NULL
-         || strcmp (sec->comdat->name, l->sec->comdat->name) == 0)
-       {
-         /* The section has already been linked.  See if we should
-             issue a warning.  */
-         switch (flags & SEC_LINK_DUPLICATES)
-           {
-           default:
-             abort ();
-
-           case SEC_LINK_DUPLICATES_DISCARD:
-             break;
-
-           case SEC_LINK_DUPLICATES_ONE_ONLY:
-             if (sec->comdat == NULL)
-               einfo (_("%P: %B: warning: ignoring duplicate section `%s'\n"),
-                      abfd, name);
-             else
-               einfo (_("%P: %B: warning: ignoring duplicate `%s'"
-                        " section symbol `%s'\n"),
-                      abfd, name, sec->comdat->name);
-             break;
-
-           case SEC_LINK_DUPLICATES_SAME_CONTENTS:
-             /* FIXME: We should really dig out the contents of both
-                 sections and memcmp them.  The COFF/PE spec says that
-                 the Microsoft linker does not implement this
-                 correctly, so I'm not going to bother doing it
-                 either.  */
-             /* Fall through.  */
-           case SEC_LINK_DUPLICATES_SAME_SIZE:
-             if (sec->size != l->sec->size)
-               einfo (_("%P: %B: warning: duplicate section `%s'"
-                        " has different size\n"),
-                      abfd, name);
-             break;
-           }
-
-         /* Set the output_section field so that lang_add_section
-            does not create a lang_input_section structure for this
-            section.  Since there might be a symbol in the section
-            being discarded, we must retain a pointer to the section
-            which we are really going to use.  */
-         sec->output_section = bfd_abs_section_ptr;
-         sec->kept_section = l->sec;
-
-         if (flags & SEC_GROUP)
-           bfd_discard_group (abfd, sec);
-
-         return;
-       }
-    }
-
-  /* This is the first section with this name.  Record it.  Allocate
-     the memory from the same obstack as the hash table is kept in.  */
-
-  l = bfd_hash_allocate (&already_linked_table, sizeof *l);
-
-  l->sec = sec;
-  l->next = already_linked_list->entry;
-  already_linked_list->entry = l;
-}
-
-/* Support routines for the hash table used by section_already_linked,
-   initialize the table, fill in an entry and remove the table.  */
-
-static struct bfd_hash_entry *
-already_linked_newfunc (struct bfd_hash_entry *entry ATTRIBUTE_UNUSED,
-                       struct bfd_hash_table *table,
-                       const char *string ATTRIBUTE_UNUSED)
-{
-  struct already_linked_hash_entry *ret =
-    bfd_hash_allocate (table, sizeof (struct already_linked_hash_entry));
-
-  ret->entry = NULL;
-
-  return &ret->root;
-}
-
-static void
-already_linked_table_init (void)
-{
-  if (! bfd_hash_table_init_n (&already_linked_table,
-                              already_linked_newfunc,
-                              42))
-    einfo (_("%P%F: Failed to create hash table\n"));
-}
-
-static void
-already_linked_table_free (void)
-{
-  bfd_hash_table_free (&already_linked_table);
+  if (!(abfd->flags & DYNAMIC))
+    bfd_section_already_linked (abfd, sec);
 }
 \f
 /* The wild routines.
@@ -1060,25 +1671,6 @@ already_linked_table_free (void)
    explicit actions, like foo.o(.text), bar.o(.text) and
    foo.o(.text, .data).  */
 
-/* Return TRUE if the PATTERN argument is a wildcard pattern.
-   Although backslashes are treated specially if a pattern contains
-   wildcards, we do not consider the mere presence of a backslash to
-   be enough to cause the pattern to be treated as a wildcard.
-   That lets us handle DOS filenames more naturally.  */
-
-static bfd_boolean
-wildcardp (const char *pattern)
-{
-  const char *s;
-
-  for (s = pattern; *s != '\0'; ++s)
-    if (*s == '?'
-       || *s == '*'
-       || *s == '[')
-      return TRUE;
-  return FALSE;
-}
-
 /* 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.  */
@@ -1155,32 +1747,32 @@ lang_add_section (lang_statement_list_type *ptr,
        flags &= ~ (SEC_LINK_ONCE | SEC_LINK_DUPLICATES);
 
       /* 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.  */
+        flag is not currently set, then don't set it just because the
+        input section has it set.  */
 
-      if (! first && (section->output_section->flags & SEC_READONLY) == 0)
+      if (! first && (output->bfd_section->flags & SEC_READONLY) == 0)
        flags &= ~ SEC_READONLY;
 
       /* Keep SEC_MERGE and SEC_STRINGS only if they are the same.  */
       if (! first
-         && ((section->output_section->flags & (SEC_MERGE | SEC_STRINGS))
+         && ((output->bfd_section->flags & (SEC_MERGE | SEC_STRINGS))
              != (flags & (SEC_MERGE | SEC_STRINGS))
              || ((flags & SEC_MERGE)
-                 && section->output_section->entsize != section->entsize)))
+                 && output->bfd_section->entsize != section->entsize)))
        {
-         section->output_section->flags &= ~ (SEC_MERGE | SEC_STRINGS);
+         output->bfd_section->flags &= ~ (SEC_MERGE | SEC_STRINGS);
          flags &= ~ (SEC_MERGE | SEC_STRINGS);
        }
 
-      section->output_section->flags |= flags;
+      output->bfd_section->flags |= flags;
 
       if (flags & SEC_MERGE)
-       section->output_section->entsize = section->entsize;
+       output->bfd_section->entsize = section->entsize;
 
       /* If SEC_READONLY is not set in the input section, then clear
-         it from the output section.  */
+        it from the output section.  */
       if ((section->flags & SEC_READONLY) == 0)
-       section->output_section->flags &= ~SEC_READONLY;
+       output->bfd_section->flags &= ~SEC_READONLY;
 
       switch (output->sectype)
        {
@@ -1200,7 +1792,7 @@ lang_add_section (lang_statement_list_type *ptr,
 
       /* Copy over SEC_SMALL_DATA.  */
       if (section->flags & SEC_SMALL_DATA)
-       section->output_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;
@@ -1209,15 +1801,56 @@ lang_add_section (lang_statement_list_type *ptr,
       if (output->section_alignment != -1)
        output->bfd_section->alignment_power = output->section_alignment;
 
-      if (section->flags & SEC_BLOCK)
+      if (bfd_get_arch (section->owner) == bfd_arch_tic54x
+         && (section->flags & SEC_TIC54X_BLOCK) != 0)
        {
-         section->output_section->flags |= SEC_BLOCK;
+         output->bfd_section->flags |= SEC_TIC54X_BLOCK;
          /* FIXME: This value should really be obtained from the bfd...  */
          output->block_value = 128;
        }
     }
 }
 
+/* Compare sections ASEC and BSEC according to SORT.  */
+
+static int
+compare_section (sort_type sort, asection *asec, asection *bsec)
+{
+  int ret;
+
+  switch (sort)
+    {
+    default:
+      abort ();
+
+    case by_alignment_name:
+      ret = (bfd_section_alignment (bsec->owner, bsec)
+            - bfd_section_alignment (asec->owner, asec));
+      if (ret)
+       break;
+      /* Fall through.  */
+
+    case by_name:
+      ret = strcmp (bfd_get_section_name (asec->owner, asec),
+                   bfd_get_section_name (bsec->owner, bsec));
+      break;
+
+    case by_name_alignment:
+      ret = strcmp (bfd_get_section_name (asec->owner, asec),
+                   bfd_get_section_name (bsec->owner, bsec));
+      if (ret)
+       break;
+      /* Fall through.  */
+
+    case by_alignment:
+      ret = (bfd_section_alignment (bsec->owner, bsec)
+            - bfd_section_alignment (asec->owner, asec));
+      break;
+    }
+
+  return ret;
+}
+
 /* Handle wildcard sorting.  This returns the lang_input_section which
    should follow the one we are going to create for SECTION and FILE,
    based on the sorting requirements of WILD.  It returns NULL if the
@@ -1232,7 +1865,8 @@ wild_sort (lang_wild_statement_type *wild,
   const char *section_name;
   lang_statement_union_type *l;
 
-  if (!wild->filenames_sorted && (sec == NULL || !sec->spec.sorted))
+  if (!wild->filenames_sorted
+      && (sec == NULL || sec->spec.sorted == none))
     return NULL;
 
   section_name = bfd_get_section_name (file->the_bfd, section);
@@ -1245,7 +1879,7 @@ wild_sort (lang_wild_statement_type *wild,
       ls = &l->input_section;
 
       /* Sorting by filename takes precedence over sorting by section
-         name.  */
+        name.  */
 
       if (wild->filenames_sorted)
        {
@@ -1254,9 +1888,9 @@ wild_sort (lang_wild_statement_type *wild,
          int i;
 
          /* The PE support for the .idata section as generated by
-             dlltool assumes that files will be sorted by the name of
-             the archive and then the name of the file within the
-             archive.  */
+            dlltool assumes that files will be sorted by the name of
+            the archive and then the name of the file within the
+            archive.  */
 
          if (file->the_bfd != NULL
              && bfd_my_archive (file->the_bfd) != NULL)
@@ -1304,14 +1938,12 @@ 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.  */
+        looking at the sections for this file.  */
 
-      if (sec != NULL && sec->spec.sorted)
+      if (sec != NULL && sec->spec.sorted != none)
        {
-         if (strcmp (section_name,
-                     bfd_get_section_name (ls->ifile->the_bfd,
-                                           ls->section))
-             < 0)
+         if (compare_section (sec->spec.sorted, section,
+                              ls->section) < 0)
            break;
        }
     }
@@ -1435,6 +2067,67 @@ lookup_name (const char *name)
   return search;
 }
 
+/* Save LIST as a list of libraries whose symbols should not be exported.  */
+
+struct excluded_lib
+{
+  char *name;
+  struct excluded_lib *next;
+};
+static struct excluded_lib *excluded_libs;
+
+void
+add_excluded_libs (const char *list)
+{
+  const char *p = list, *end;
+
+  while (*p != '\0')
+    {
+      struct excluded_lib *entry;
+      end = strpbrk (p, ",:");
+      if (end == NULL)
+       end = p + strlen (p);
+      entry = xmalloc (sizeof (*entry));
+      entry->next = excluded_libs;
+      entry->name = xmalloc (end - p + 1);
+      memcpy (entry->name, p, end - p);
+      entry->name[end - p] = '\0';
+      excluded_libs = entry;
+      if (*end == '\0')
+        break;
+      p = end + 1;
+    }
+}
+
+static void
+check_excluded_libs (bfd *abfd)
+{
+  struct excluded_lib *lib = excluded_libs;
+
+  while (lib)
+    {
+      int len = strlen (lib->name);
+      const char *filename = lbasename (abfd->filename);
+
+      if (strcmp (lib->name, "ALL") == 0)
+       {
+         abfd->no_export = TRUE;
+         return;
+       }
+
+      if (strncmp (lib->name, filename, len) == 0
+         && (filename[len] == '\0'
+             || (filename[len] == '.' && filename[len + 1] == 'a'
+                 && filename[len + 2] == '\0')))
+       {
+         abfd->no_export = TRUE;
+         return;
+       }
+
+      lib = lib->next;
+    }
+}
+
 /* Get the symbols for an input file.  */
 
 static bfd_boolean
@@ -1491,6 +2184,9 @@ load_symbols (lang_input_statement_type *entry,
 
       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;
 
@@ -1519,6 +2215,8 @@ load_symbols (lang_input_statement_type *entry,
       break;
 
     case bfd_archive:
+      check_excluded_libs (entry->the_bfd);
+
       if (entry->whole_archive)
        {
          bfd *member = NULL;
@@ -1834,10 +2532,6 @@ open_output (const char *name)
 
   delete_output_file_on_failure = TRUE;
 
-#if 0
-  output->flags |= D_PAGED;
-#endif
-
   if (! bfd_set_format (output, bfd_object))
     einfo (_("%P%F:%s: can not make object file: %E\n"), name);
   if (! bfd_set_arch_mach (output,
@@ -1957,8 +2651,8 @@ open_input_bfds (lang_statement_union_type *s, bfd_boolean force)
              s->input_statement.target = current_target;
 
              /* 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
+                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
@@ -1985,31 +2679,6 @@ open_input_bfds (lang_statement_union_type *s, bfd_boolean force)
     }
 }
 
-/* If there are [COMMONS] statements, put a wild one into the bss
-   section.  */
-
-static void
-lang_reasonable_defaults (void)
-{
-#if 0
-  lang_output_section_statement_lookup (".text");
-  lang_output_section_statement_lookup (".data");
-
-  default_common_section = lang_output_section_statement_lookup (".bss");
-
-  if (!placed_commons)
-    {
-      lang_wild_statement_type *new =
-      new_stat (lang_wild_statement,
-               &default_common_section->children);
-
-      new->section_name = "COMMON";
-      new->filename = NULL;
-      lang_list_init (&new->children);
-    }
-#endif
-}
-
 /* Add a symbol to a hash of symbols used in DEFINED (NAME) expressions.  */
 
 void
@@ -2180,24 +2849,89 @@ check_input_sections
     }
 }
 
+/* Update wildcard statements if needed.  */
+
+static void
+update_wild_statements (lang_statement_union_type *s)
+{
+  struct wildcard_list *sec;
+
+  switch (sort_section)
+    {
+    default:
+      FAIL ();
+
+    case none:
+      break;
+
+    case by_name:
+    case by_alignment:
+      for (; s != NULL; s = s->header.next)
+       {
+         switch (s->header.type)
+           {
+           default:
+             break;
+
+           case lang_wild_statement_enum:
+             sec = s->wild_statement.section_list;
+             if (sec != NULL)
+               {
+                 switch (sec->spec.sorted)
+                   {
+                   case none:
+                     sec->spec.sorted = sort_section;
+                     break;
+                   case by_name:
+                     if (sort_section == by_alignment)
+                       sec->spec.sorted = by_name_alignment;
+                     break;
+                   case by_alignment:
+                     if (sort_section == by_name)
+                       sec->spec.sorted = by_alignment_name;
+                     break;
+                   default:
+                     break;
+                   }
+               }
+             break;
+
+           case lang_constructors_statement_enum:
+             update_wild_statements (constructor_list.head);
+             break;
+
+           case lang_output_section_statement_enum:
+             update_wild_statements
+               (s->output_section_statement.children.head);
+             break;
+
+           case lang_group_statement_enum:
+             update_wild_statements (s->group_statement.children.head);
+             break;
+           }
+       }
+      break;
+    }
+}
+
 /* Open input files and attach to output sections.  */
 
 static void
 map_input_to_output_sections
   (lang_statement_union_type *s, const char *target,
-   lang_output_section_statement_type *output_section_statement)
+   lang_output_section_statement_type *os)
 {
   for (; s != NULL; s = s->header.next)
     {
       switch (s->header.type)
        {
        case lang_wild_statement_enum:
-         wild (&s->wild_statement, target, output_section_statement);
+         wild (&s->wild_statement, target, os);
          break;
        case lang_constructors_statement_enum:
          map_input_to_output_sections (constructor_list.head,
                                        target,
-                                       output_section_statement);
+                                       os);
          break;
        case lang_output_section_statement_enum:
          if (s->output_section_statement.constraint)
@@ -2229,27 +2963,32 @@ map_input_to_output_sections
        case lang_group_statement_enum:
          map_input_to_output_sections (s->group_statement.children.head,
                                        target,
-                                       output_section_statement);
+                                       os);
          break;
        case lang_data_statement_enum:
          /* Make sure that any sections mentioned in the expression
             are initialized.  */
          exp_init_os (s->data_statement.exp);
-         /* FALLTHROUGH */
+         if (os != NULL && os->bfd_section == NULL)
+           init_os (os);
+         /* The output section gets contents, and then we inspect for
+            any flags set in the input script which override any ALLOC.  */
+         os->bfd_section->flags |= SEC_HAS_CONTENTS;
+         if (!(os->flags & SEC_NEVER_LOAD))
+           os->bfd_section->flags |= SEC_ALLOC | SEC_LOAD;
+         break;
        case lang_fill_statement_enum:
        case lang_input_section_enum:
        case lang_object_symbols_statement_enum:
        case lang_reloc_statement_enum:
        case lang_padding_statement_enum:
        case lang_input_statement_enum:
-         if (output_section_statement != NULL
-             && output_section_statement->bfd_section == NULL)
-           init_os (output_section_statement);
+         if (os != NULL && os->bfd_section == NULL)
+           init_os (os);
          break;
        case lang_assignment_statement_enum:
-         if (output_section_statement != NULL
-             && output_section_statement->bfd_section == NULL)
-           init_os (output_section_statement);
+         if (os != NULL && os->bfd_section == NULL)
+           init_os (os);
 
          /* Make sure that any sections mentioned in the assignment
             are initialized.  */
@@ -2259,16 +2998,27 @@ map_input_to_output_sections
          FAIL ();
          break;
        case lang_address_statement_enum:
-         /* Mark the specified section with the supplied address.  */
-         {
-           lang_output_section_statement_type *os =
-             lang_output_section_statement_lookup
-               (s->address_statement.section_name);
-
-           if (os->bfd_section == NULL)
-             init_os (os);
-           os->addr_tree = s->address_statement.address;
-         }
+         /* Mark the specified section with the supplied address.  
+
+            If this section was actually a segment marker, then the
+            directive is ignored if the linker script explicitly
+            processed the segment marker.  Originally, the linker
+            treated segment directives (like -Ttext on the
+            command-line) as section directives.  We honor the
+            section directive semantics for backwards compatibilty;
+            linker scripts that do not specifically check for
+            SEGMENT_START automatically get the old semantics.  */
+         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));
+             
+             if (aos->bfd_section == NULL)
+               init_os (aos);
+             aos->addr_tree = s->address_statement.address;
+           }
          break;
        }
     }
@@ -2281,16 +3031,14 @@ map_input_to_output_sections
 static void
 strip_excluded_output_sections (void)
 {
-  lang_statement_union_type *u;
+  lang_output_section_statement_type *os;
 
-  for (u = lang_output_section_statement.head;
-       u != NULL;
-       u = u->output_section_statement.next)
+  for (os = &lang_output_section_statement.head->output_section_statement;
+       os != NULL;
+       os = os->next)
     {
-      lang_output_section_statement_type *os;
       asection *s;
 
-      os = &u->output_section_statement;
       if (os->constraint == -1)
        continue;
       s = os->bfd_section;
@@ -2362,23 +3110,35 @@ print_assignment (lang_assignment_statement_type *assignment,
                  lang_output_section_statement_type *output_section)
 {
   int i;
+  int is_dot;
+  etree_type *tree;
   etree_value_type result;
 
   for (i = 0; i < SECTION_NAME_MAP_LENGTH; i++)
     print_space ();
 
-  result = exp_fold_tree (assignment->exp->assign.src, output_section,
-                         lang_final_phase_enum, print_dot, &print_dot);
+  if (assignment->exp->type.node_class == etree_assert)
+    {
+      is_dot = 0;
+      tree = assignment->exp->assert_s.child;
+    }
+  else
+    {
+      const char *dst = assignment->exp->assign.dst;
+      is_dot = dst[0] == '.' && dst[1] == 0;
+      tree = assignment->exp->assign.src;
+    }
+
+  result = exp_fold_tree (tree, output_section, lang_final_phase_enum,
+                         print_dot, &print_dot);
   if (result.valid_p)
     {
-      const char *dst;
       bfd_vma value;
 
       value = result.value + result.section->bfd_section->vma;
-      dst = assignment->exp->assign.dst;
 
       minfo ("0x%V", value);
-      if (dst[0] == '.' && dst[1] == 0)
+      if (is_dot)
        print_dot = value;
     }
   else
@@ -2390,9 +3150,7 @@ print_assignment (lang_assignment_statement_type *assignment,
     }
 
   minfo ("                ");
-
   exp_print_tree (assignment->exp);
-
   print_nl ();
 }
 
@@ -2439,6 +3197,9 @@ print_all_symbols (sec)
   struct fat_user_section_struct *ud = get_userdata (sec);
   struct map_symbol_def *def;
 
+  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);
@@ -2923,14 +3684,14 @@ size_input_section
 }
 
 #define IGNORE_SECTION(s) \
-  (((s->flags & SEC_THREAD_LOCAL) != 0                         \
-    ? (s->flags & (SEC_LOAD | SEC_NEVER_LOAD)) != SEC_LOAD     \
-    : (s->flags & (SEC_ALLOC | SEC_NEVER_LOAD)) != SEC_ALLOC)  \
-   || s->size == 0)
+  ((s->flags & SEC_NEVER_LOAD) != 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
-   sections.  This can happen when the linker script specifically specifies
-   the output section addresses of the two sections.  */
+   sections.  This can happen if a linker script specifies the output
+   section addresses of the two sections.  */
 
 static void
 lang_check_section_addresses (void)
@@ -2943,7 +3704,7 @@ lang_check_section_addresses (void)
       asection *os;
 
       /* Ignore sections which are not loaded or which have no contents.  */
-      if (IGNORE_SECTION (s))
+      if (IGNORE_SECTION (s) || s->size == 0)
        continue;
 
       /* Once we reach section 's' stop our seach.  This prevents two
@@ -2957,7 +3718,7 @@ lang_check_section_addresses (void)
          bfd_vma os_end;
 
          /* Only consider loadable sections with real contents.  */
-         if (IGNORE_SECTION (os))
+         if (IGNORE_SECTION (os) || os->size == 0)
            continue;
 
          /* We must check the sections' LMA addresses not their
@@ -3051,7 +3812,9 @@ lang_size_sections_1
               address from the input section.  FIXME: This is COFF
               specific; it would be cleaner if there were some other way
               to do this, but nothing simple comes to mind.  */
-           if ((os->bfd_section->flags & SEC_COFF_SHARED_LIBRARY) != 0)
+           if ((bfd_get_flavour (output_bfd) == bfd_target_ecoff_flavour
+                || bfd_get_flavour (output_bfd) == bfd_target_coff_flavour)
+               && (os->bfd_section->flags & SEC_COFF_SHARED_LIBRARY) != 0)
              {
                asection *input;
 
@@ -3150,7 +3913,7 @@ lang_size_sections_1
                                       lang_allocating_phase_enum,
                                       dot, &dot);
                    os->processed = 0;
-                   
+
                    if (!r.valid_p)
                      einfo (_("%F%S: non constant or forward reference"
                               " address expression for section %s\n"),
@@ -3280,14 +4043,6 @@ lang_size_sections_1
              size = TO_SIZE ((unsigned) 1);
            dot += TO_ADDR (size);
            output_section_statement->bfd_section->size += size;
-           /* The output section gets contents, and then we inspect for
-              any flags set in the input script which override any ALLOC.  */
-           output_section_statement->bfd_section->flags |= SEC_HAS_CONTENTS;
-           if (!(output_section_statement->flags & SEC_NEVER_LOAD))
-             {
-               output_section_statement->bfd_section->flags |=
-                 SEC_ALLOC | SEC_LOAD;
-             }
          }
          break;
 
@@ -3450,10 +4205,50 @@ lang_size_sections
     {
       /* If DATA_SEGMENT_ALIGN DATA_SEGMENT_RELRO_END pair was seen, try
         to put exp_data_seg.relro on a (common) page boundary.  */
+      bfd_vma old_min_base, relro_end, maxpage;
 
       exp_data_seg.phase = exp_dataseg_relro_adjust;
+      old_min_base = exp_data_seg.min_base;
+      maxpage = exp_data_seg.maxpagesize;
+      exp_data_seg.base += (-exp_data_seg.relro_end
+                           & (exp_data_seg.pagesize - 1));
+      /* Compute the expected PT_GNU_RELRO segment end.  */
+      relro_end = (exp_data_seg.relro_end + exp_data_seg.pagesize - 1)
+                 & ~(exp_data_seg.pagesize - 1);
+      if (old_min_base + maxpage < exp_data_seg.base)
+       {
+         exp_data_seg.base -= maxpage;
+         relro_end -= maxpage;
+       }
       result = lang_size_sections_1 (s, output_section_statement, prev, fill,
                                     dot, relax, check_regions);
+      if (exp_data_seg.relro_end > relro_end)
+       {
+         /* The alignment of sections between DATA_SEGMENT_ALIGN
+            and DATA_SEGMENT_RELRO_END caused huge padding to be
+            inserted at DATA_SEGMENT_RELRO_END.  Try some other base.  */
+         asection *sec;
+         unsigned int max_alignment_power = 0;
+
+         /* Find maximum alignment power of sections between
+            DATA_SEGMENT_ALIGN and DATA_SEGMENT_RELRO_END.  */
+         for (sec = output_bfd->sections; sec; sec = sec->next)
+           if (sec->vma >= exp_data_seg.base
+               && sec->vma < exp_data_seg.relro_end
+               && sec->alignment_power > max_alignment_power)
+             max_alignment_power = sec->alignment_power;
+
+         if (((bfd_vma) 1 << max_alignment_power) < exp_data_seg.pagesize)
+           {
+             if (exp_data_seg.base - (1 << max_alignment_power)
+                 < old_min_base)
+               exp_data_seg.base += exp_data_seg.pagesize;
+             exp_data_seg.base -= (1 << max_alignment_power);
+             result = lang_size_sections_1 (s, output_section_statement,
+                                            prev, fill, dot, relax,
+                                            check_regions);
+           }
+       }
       link_info.relro_start = exp_data_seg.base;
       link_info.relro_end = exp_data_seg.relro_end;
     }
@@ -3539,9 +4334,6 @@ lang_do_assignments_1
        case lang_object_symbols_statement_enum:
        case lang_output_statement_enum:
        case lang_target_statement_enum:
-#if 0
-       case lang_common_statement_enum:
-#endif
          break;
        case lang_data_statement_enum:
          {
@@ -3740,7 +4532,7 @@ lang_finish (void)
       const char *send;
 
       /* We couldn't find the entry symbol.  Try parsing it as a
-         number.  */
+        number.  */
       val = bfd_scan_vma (entry_symbol.name, &send, 0);
       if (*send == '\0')
        {
@@ -3841,10 +4633,10 @@ lang_check (void)
          bfd_error_handler_type pfn = NULL;
 
          /* If we aren't supposed to warn about mismatched input
-             files, temporarily set the BFD error handler to a
-             function which will do nothing.  We still want to call
-             bfd_merge_private_bfd_data, since it may set up
-             information which is needed in the output file.  */
+            files, temporarily set the BFD error handler to a
+            function which will do nothing.  We still want to call
+            bfd_merge_private_bfd_data, since it may set up
+            information which is needed in the output file.  */
          if (! command_line.warn_mismatch)
            pfn = bfd_set_error_handler (ignore_bfd_errors);
          if (! bfd_merge_private_bfd_data (input_bfd, output_bfd))
@@ -3991,12 +4783,11 @@ lang_place_orphans (void)
          if (s->output_section == NULL)
            {
              /* This section of the file is not attached, root
-                around for a sensible place for it to go.  */
+                around for a sensible place for it to go.  */
 
              if (file->just_syms_flag)
-               abort ();
-
-             if ((s->flags & SEC_EXCLUDE) != 0)
+               bfd_link_just_syms (file->the_bfd, s, &link_info);
+             else if ((s->flags & SEC_EXCLUDE) != 0)
                s->output_section = bfd_abs_section_ptr;
              else if (strcmp (s->name, "COMMON") == 0)
                {
@@ -4008,13 +4799,6 @@ lang_place_orphans (void)
                    {
                      if (default_common_section == NULL)
                        {
-#if 0
-                         /* This message happens when using the
-                             svr3.ifile linker script, so I have
-                             disabled it.  */
-                         info_msg (_("%P: no [COMMON] command,"
-                                     " defaulting to .bss\n"));
-#endif
                          default_common_section =
                            lang_output_section_statement_lookup (".bss");
 
@@ -4183,11 +4967,6 @@ lang_enter_output_section_statement (const char *output_section_statement_name,
     lang_output_section_statement_lookup_1 (output_section_statement_name,
                                            constraint);
 
-  /* Add this statement to tree.  */
-#if 0
-  add_statement (lang_output_section_statement_enum,
-                output_section_statement);
-#endif
   /* Make next things chain into subchain of this.  */
 
   if (os->addr_tree == NULL)
@@ -4325,14 +5104,23 @@ lang_gc_sections (void)
        }
     }
 
-  if (command_line.gc_sections)
+  if (link_info.gc_sections)
     bfd_gc_sections (output_bfd, &link_info);
 }
 
+static void
+lang_mark_used_section (void)
+{
+  unsigned int gc_sections = link_info.gc_sections;
+
+  link_info.gc_sections = 0;
+  bfd_gc_sections (output_bfd, &link_info);
+  link_info.gc_sections = gc_sections;
+}
+
 void
 lang_process (void)
 {
-  lang_reasonable_defaults ();
   current_target = default_target;
 
   /* Open the output file.  */
@@ -4344,7 +5132,8 @@ lang_process (void)
   /* Add to the hash table all undefineds on the command line.  */
   lang_place_undefineds ();
 
-  already_linked_table_init ();
+  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;
@@ -4356,7 +5145,7 @@ lang_process (void)
 
   ldemul_after_open ();
 
-  already_linked_table_free ();
+  bfd_section_already_linked_table_free ();
 
   /* Make sure that we're not mixing architectures.  We call this
      after all the input files have been opened, but before we do any
@@ -4379,6 +5168,9 @@ lang_process (void)
   /* Size up the common data.  */
   lang_common ();
 
+  /* Update wild statements.  */
+  update_wild_statements (statement_list.head);
+
   /* Run through the contours of the script and attach input sections
      to the correct output sections.  */
   map_input_to_output_sections (statement_list.head, NULL, NULL);
@@ -4487,7 +5279,7 @@ lang_process (void)
     lang_check_section_addresses ();
 
   /* Final stuffs.  */
-
+  lang_mark_used_section ();
   ldemul_finish ();
   lang_finish ();
 }
@@ -4528,21 +5320,24 @@ lang_add_wild (struct wildcard_spec *filespec,
   if (filespec != NULL)
     {
       new->filename = filespec->name;
-      new->filenames_sorted = filespec->sorted;
+      new->filenames_sorted = filespec->sorted == by_name;
     }
   new->section_list = section_list;
   new->keep_sections = keep_sections;
   lang_list_init (&new->children);
+  analyze_walk_wild_section_handler (new);
 }
 
 void
-lang_section_start (const char *name, etree_type *address)
+lang_section_start (const char *name, etree_type *address,
+                   const segment_type *segment)
 {
   lang_address_statement_type *ad;
 
   ad = new_stat (lang_address_statement, stat_ptr);
   ad->section_name = name;
   ad->address = address;
+  ad->segment = segment;
 }
 
 /* Set the start symbol to NAME.  CMDLINE is nonzero if this is called
@@ -4877,7 +5672,7 @@ lang_record_phdrs (void)
   asection **secs;
   lang_output_section_phdr_list *last;
   struct lang_phdr *l;
-  lang_statement_union_type *u;
+  lang_output_section_statement_type *os;
 
   alc = 10;
   secs = xmalloc (alc * sizeof (asection *));
@@ -4889,14 +5684,12 @@ lang_record_phdrs (void)
       bfd_vma at;
 
       c = 0;
-      for (u = lang_output_section_statement.head;
-          u != NULL;
-          u = u->output_section_statement.next)
+      for (os = &lang_output_section_statement.head->output_section_statement;
+          os != NULL;
+          os = os->next)
        {
-         lang_output_section_statement_type *os;
          lang_output_section_phdr_list *pl;
 
-         os = &u->output_section_statement;
          if (os->constraint == -1)
            continue;
 
@@ -4952,22 +5745,22 @@ lang_record_phdrs (void)
   free (secs);
 
   /* Make sure all the phdr assignments succeeded.  */
-  for (u = lang_output_section_statement.head;
-       u != NULL;
-       u = u->output_section_statement.next)
+  for (os = &lang_output_section_statement.head->output_section_statement;
+       os != NULL;
+       os = os->next)
     {
       lang_output_section_phdr_list *pl;
 
-      if (u->output_section_statement.constraint == -1
-         || u->output_section_statement.bfd_section == NULL)
+      if (os->constraint == -1
+         || os->bfd_section == NULL)
        continue;
 
-      for (pl = u->output_section_statement.phdrs;
+      for (pl = os->phdrs;
           pl != NULL;
           pl = pl->next)
        if (! pl->used && strcmp (pl->name, "NONE") != 0)
          einfo (_("%X%P: section `%s' assigned to non-existent phdr `%s'\n"),
-                u->output_section_statement.name, pl->name);
+                os->name, pl->name);
     }
 }
 
This page took 0.046939 seconds and 4 git commands to generate.