* ldlang.h (lang_output_section_statement_type): Add prev.
[deliverable/binutils-gdb.git] / ld / ldlang.c
index b4f767d6e89b687b88f68be7f2d5770ab896fa06..f51f68ef4b09054443d600bb8018f596dd2efb97 100644 (file)
@@ -101,6 +101,9 @@ bfd_boolean delete_output_file_on_failure = FALSE;
 struct lang_nocrossrefs *nocrossref_list;
 static struct unique_sections *unique_section_list;
 static bfd_boolean ldlang_sysrooted_script = FALSE;
+
+ /* Functions that traverse the linker script and might evaluate
+    DEFINED() need to increment this.  */
 int lang_statement_iteration = 0;
 
 etree_type *base; /* Relocation base - or null */
@@ -780,6 +783,7 @@ new_afile (const char *name,
   else
     {
       p = stat_alloc (sizeof (lang_input_statement_type));
+      p->header.type = lang_input_statement_enum;
       p->header.next = NULL;
     }
 
@@ -865,6 +869,81 @@ lang_add_input_file (const char *name,
   return new_afile (name, file_type, target, TRUE);
 }
 
+struct output_statement_hash_entry
+{
+  struct bfd_hash_entry root;
+  lang_output_section_statement_type os;
+};
+
+/* The hash table.  */
+
+static struct bfd_hash_table output_statement_table;
+
+/* Support routines for the hash table used by lang_output_section_find,
+   initialize the table, fill in an entry and remove the table.  */
+
+static struct bfd_hash_entry *
+output_statement_newfunc (struct bfd_hash_entry *entry, 
+                         struct bfd_hash_table *table,
+                         const char *string)
+{
+  lang_output_section_statement_type **nextp;
+  struct output_statement_hash_entry *ret;
+
+  if (entry == NULL)
+    {
+      entry = bfd_hash_allocate (table, sizeof (*ret));
+      if (entry == NULL)
+       return entry;
+    }
+
+  entry = bfd_hash_newfunc (entry, table, string);
+  if (entry == NULL)
+    return entry;
+
+  ret = (struct output_statement_hash_entry *) entry;
+  memset (&ret->os, 0, sizeof (ret->os));
+  ret->os.header.type = lang_output_section_statement_enum;
+  ret->os.subsection_alignment = -1;
+  ret->os.section_alignment = -1;
+  ret->os.block_value = 1;
+  lang_list_init (&ret->os.children);
+  lang_statement_append (stat_ptr,
+                        (lang_statement_union_type *) &ret->os,
+                        &ret->os.header.next);
+
+  /* For every output section statement added to the list, except the
+     first one, lang_output_section_statement.tail points to the "next"
+     field of the last element of the list.  */
+  if (lang_output_section_statement.head != NULL)
+    ret->os.prev = (lang_output_section_statement_type *)
+      ((char *) lang_output_section_statement.tail
+       - offsetof (lang_output_section_statement_type, next));
+
+  /* GCC's strict aliasing rules prevent us from just casting the
+     address, so we store the pointer in a variable and cast that
+     instead.  */
+  nextp = &ret->os.next;
+  lang_statement_append (&lang_output_section_statement,
+                        (lang_statement_union_type *) &ret->os,
+                        (lang_statement_union_type **) nextp);
+  return &ret->root;
+}
+
+static void
+output_statement_table_init (void)
+{
+  if (! bfd_hash_table_init_n (&output_statement_table,
+                              output_statement_newfunc, 61))
+    einfo (_("%P%F: can not create hash table: %E\n"));
+}
+
+static void
+output_statement_table_free (void)
+{
+  bfd_hash_table_free (&output_statement_table);
+}
+
 /* Build enough state so that the parser can build its tree.  */
 
 void
@@ -874,6 +953,8 @@ lang_init (void)
 
   stat_ptr = &statement_list;
 
+  output_statement_table_init ();
+
   lang_list_init (stat_ptr);
 
   lang_list_init (&input_file_chain);
@@ -894,10 +975,13 @@ lang_init (void)
      looks like other code here.  */
   if (!bfd_hash_table_init_n (&lang_definedness_table,
                              lang_definedness_newfunc, 3))
-    einfo (_("%P%F: out of memory during initialization"));
+    einfo (_("%P%F: can not create hash table: %E\n"));
+}
 
-  /* Callers of exp_fold_tree need to increment this.  */
-  lang_statement_iteration = 0;
+void
+lang_finish (void)
+{
+  output_statement_table_free ();
 }
 
 /*----------------------------------------------------------------------
@@ -981,68 +1065,79 @@ lang_memory_default (asection *section)
   return lang_memory_region_lookup (DEFAULT_MEMORY_REGION, FALSE);
 }
 
-static lang_output_section_statement_type *
-lang_output_section_find_1 (const char *const name, int constraint)
+lang_output_section_statement_type *
+lang_output_section_find (const char *const name)
 {
-  lang_output_section_statement_type *lookup;
+  struct output_statement_hash_entry *entry;
+  unsigned long hash;
+
+  entry = ((struct output_statement_hash_entry *)
+          bfd_hash_lookup (&output_statement_table, name, FALSE, FALSE));
+  if (entry == NULL)
+    return NULL;
 
-  for (lookup = &lang_output_section_statement.head->output_section_statement;
-       lookup != NULL;
-       lookup = lookup->next)
+  hash = entry->root.hash;
+  do
     {
-      if (strcmp (name, lookup->name) == 0
-         && lookup->constraint != -1
-         && (constraint == 0
-             || (constraint == lookup->constraint
-                 && constraint != SPECIAL)))
-       return lookup;
+      if (entry->os.constraint != -1)
+       return &entry->os;
+      entry = (struct output_statement_hash_entry *) entry->root.next;
     }
-  return NULL;
-}
+  while (entry != NULL
+        && entry->root.hash == hash
+        && strcmp (name, entry->os.name) == 0);
 
-lang_output_section_statement_type *
-lang_output_section_find (const char *const name)
-{
-  return lang_output_section_find_1 (name, 0);
+  return NULL;
 }
 
 static lang_output_section_statement_type *
 lang_output_section_statement_lookup_1 (const char *const name, int constraint)
 {
-  lang_output_section_statement_type *lookup;
+  struct output_statement_hash_entry *entry;
+  struct output_statement_hash_entry *last_ent;
+  unsigned long hash;
 
-  lookup = lang_output_section_find_1 (name, constraint);
-  if (lookup == NULL)
+  entry = ((struct output_statement_hash_entry *)
+          bfd_hash_lookup (&output_statement_table, name, TRUE, FALSE));
+  if (entry == NULL)
     {
-      lookup = new_stat (lang_output_section_statement, stat_ptr);
-      lookup->region = NULL;
-      lookup->lma_region = NULL;
-      lookup->fill = 0;
-      lookup->block_value = 1;
-      lookup->name = name;
-
-      lookup->next = NULL;
-      lookup->bfd_section = NULL;
-      lookup->processed = 0;
-      lookup->constraint = constraint;
-      lookup->ignored = FALSE;
-      lookup->sectype = normal_section;
-      lookup->addr_tree = NULL;
-      lang_list_init (&lookup->children);
+      einfo (_("%P%F: failed creating section `%s': %E\n"), name);
+      return NULL;
+    }
 
-      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 (entry->os.name != NULL)
+    {
+      /* We have a section of this name, but it might not have the correct
+        constraint.  */
+      hash = entry->root.hash;
+      do
+       {
+         if (entry->os.constraint != -1
+             && (constraint == 0
+                 || (constraint == entry->os.constraint
+                     && constraint != SPECIAL)))
+           return &entry->os;
+         last_ent = entry;
+         entry = (struct output_statement_hash_entry *) entry->root.next;
+       }
+      while (entry != NULL
+            && entry->root.hash == hash
+            && strcmp (name, entry->os.name) == 0);
 
-      lang_statement_append (&lang_output_section_statement,
-                            (lang_statement_union_type *) lookup,
-                            (lang_statement_union_type **) &lookup->next);
+      entry = ((struct output_statement_hash_entry *)
+              output_statement_newfunc (NULL, &output_statement_table, name));
+      if (entry == NULL)
+       {
+         einfo (_("%P%F: failed creating section `%s': %E\n"), name);
+         return NULL;
+       }
+      entry->root = last_ent->root;
+      last_ent->root.next = &entry->root;
     }
-  return lookup;
+
+  entry->os.name = name;
+  entry->os.constraint = constraint;
+  return &entry->os;
 }
 
 lang_output_section_statement_type *
@@ -1058,7 +1153,8 @@ lang_output_section_statement_lookup (const char *const name)
 
 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 **exact,
+                                  lang_match_sec_type_func match_type)
 {
   lang_output_section_statement_type *first, *look, *found;
   flagword flags;
@@ -1074,7 +1170,12 @@ lang_output_section_find_by_flags (const asection *sec,
     {
       flags = look->flags;
       if (look->bfd_section != NULL)
-       flags = look->bfd_section->flags;
+       {
+         flags = look->bfd_section->flags;
+         if (match_type && !match_type (output_bfd, look->bfd_section,
+                                        sec->owner, sec))
+           continue;
+       }
       flags ^= sec->flags;
       if (!(flags & (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_READONLY
                     | SEC_CODE | SEC_SMALL_DATA | SEC_THREAD_LOCAL)))
@@ -1082,7 +1183,8 @@ lang_output_section_find_by_flags (const asection *sec,
     }
   if (found != NULL)
     {
-      *exact = found;
+      if (exact != NULL)
+       *exact = found;
       return found;
     }
 
@@ -1093,40 +1195,51 @@ lang_output_section_find_by_flags (const asection *sec,
        {
          flags = look->flags;
          if (look->bfd_section != NULL)
-           flags = look->bfd_section->flags;
+           {
+             flags = look->bfd_section->flags;
+             if (match_type && !match_type (output_bfd, look->bfd_section,
+                                            sec->owner, sec))
+               continue;
+           }
          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))
+  else 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 = look->bfd_section->flags;
+             if (match_type && !match_type (output_bfd, look->bfd_section,
+                                            sec->owner, sec))
+               continue;
+           }
          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)
+  else 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 = look->bfd_section->flags;
+             if (match_type && !match_type (output_bfd, look->bfd_section,
+                                            sec->owner, sec))
+               continue;
+           }
          flags ^= sec->flags;
          if (!(flags & (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD
                         | SEC_THREAD_LOCAL))
@@ -1134,37 +1247,49 @@ lang_output_section_find_by_flags (const asection *sec,
                  && !(sec->flags & SEC_HAS_CONTENTS)))
            found = look;
        }
-      return found;
     }
-
-  if (sec->flags & SEC_HAS_CONTENTS)
+  else 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 = look->bfd_section->flags;
+             if (match_type && !match_type (output_bfd, look->bfd_section,
+                                            sec->owner, sec))
+               continue;
+           }
          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)
+  else
     {
-      flags = look->flags;
-      if (look->bfd_section != NULL)
-       flags = look->bfd_section->flags;
-      flags ^= sec->flags;
-      if (!(flags & SEC_ALLOC))
-       found = look;
+      /* .bss goes last.  */
+      for (look = first; look; look = look->next)
+       {
+         flags = look->flags;
+         if (look->bfd_section != NULL)
+           {
+             flags = look->bfd_section->flags;
+             if (match_type && !match_type (output_bfd, look->bfd_section,
+                                            sec->owner, sec))
+               continue;
+           }
+         flags ^= sec->flags;
+         if (!(flags & SEC_ALLOC))
+           found = look;
+       }
     }
 
-  return found;
+  if (found || !match_type)
+    return found;
+
+  return lang_output_section_find_by_flags (sec, NULL, NULL);
 }
 
 /* Find the last output section before given output statement.
@@ -1173,28 +1298,22 @@ lang_output_section_find_by_flags (const asection *sec,
 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)
+  for (lookup = os->prev; lookup != NULL; lookup = lookup->prev)
     {
       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 lookup->bfd_section;
     }
 
   return NULL;
 }
 
 lang_output_section_statement_type *
-lang_insert_orphan (lang_input_statement_type *file,
-                   asection *s,
+lang_insert_orphan (asection *s,
                    const char *secname,
                    lang_output_section_statement_type *after,
                    struct orphan_save *place,
@@ -1265,7 +1384,7 @@ lang_insert_orphan (lang_input_statement_type *file,
 
   if (add_child == NULL)
     add_child = &os->children;
-  lang_add_section (add_child, s, os, file);
+  lang_add_section (add_child, s, os);
 
   lang_leave_output_section_statement (0, "*default*", NULL, NULL);
 
@@ -1348,13 +1467,20 @@ lang_insert_orphan (lang_input_statement_type *file,
            {
              lang_statement_union_type **where;
              lang_statement_union_type **assign = NULL;
+             bfd_boolean ignore_first;
 
              /* 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.  */
+                belong to it.  An exception to this rule is made for
+                the first assignment to dot, otherwise we might put an
+                orphan before . = . + SIZEOF_HEADERS or similar
+                assignments that set the initial address.  */
+
+             ignore_first = after == (&lang_output_section_statement.head
+                                      ->output_section_statement);
              for (where = &after->header.next;
                   *where != NULL;
                   where = &(*where)->header.next)
@@ -1368,9 +1494,11 @@ lang_insert_orphan (lang_input_statement_type *file,
                          ass = &(*where)->assignment_statement;
                          if (ass->exp->type.node_class != etree_assert
                              && ass->exp->assign.dst[0] == '.'
-                             && ass->exp->assign.dst[1] == 0)
+                             && ass->exp->assign.dst[1] == 0
+                             && !ignore_first)
                            assign = where;
                        }
+                     ignore_first = FALSE;
                      continue;
                    case lang_wild_statement_enum:
                    case lang_input_section_enum:
@@ -1419,7 +1547,12 @@ lang_insert_orphan (lang_input_statement_type *file,
          /* Do the same for the list of output section statements.  */
          newly_added_os = *os_tail;
          *os_tail = NULL;
+         newly_added_os->prev = (lang_output_section_statement_type *)
+           ((char *) place->os_tail
+            - offsetof (lang_output_section_statement_type, next));
          newly_added_os->next = *place->os_tail;
+         if (newly_added_os->next != NULL)
+           newly_added_os->next->prev = newly_added_os;
          *place->os_tail = newly_added_os;
          place->os_tail = &newly_added_os->next;
 
@@ -1563,7 +1696,7 @@ sort_def_symbol (hash_entry, info)
 /* Initialize an output section.  */
 
 static void
-init_os (lang_output_section_statement_type *s)
+init_os (lang_output_section_statement_type *s, asection *isec)
 {
   if (s->bfd_section != NULL)
     return;
@@ -1580,9 +1713,6 @@ init_os (lang_output_section_statement_type *s)
             output_bfd->xvec->name, s->name);
     }
   s->bfd_section->output_section = s->bfd_section;
-
-  /* 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;
   if (!command_line.reduce_memory_overheads)
     {
@@ -1600,6 +1730,15 @@ init_os (lang_output_section_statement_type *s)
 
   if (s->load_base != NULL)
     exp_init_os (s->load_base);
+
+  /* If supplied an alignment, set it.  */
+  if (s->section_alignment != -1)
+    s->bfd_section->alignment_power = s->section_alignment;
+
+  if (isec)
+    bfd_init_private_section_data (isec->owner, isec,
+                                  output_bfd, s->bfd_section,
+                                  &link_info);
 }
 
 /* Make sure that all output sections mentioned in an expression are
@@ -1611,6 +1750,7 @@ exp_init_os (etree_type *exp)
   switch (exp->type.node_class)
     {
     case etree_assign:
+    case etree_provide:
       exp_init_os (exp->assign.src);
       break;
 
@@ -1644,7 +1784,7 @@ exp_init_os (etree_type *exp)
 
            os = lang_output_section_find (exp->name.name);
            if (os != NULL && os->bfd_section == NULL)
-             init_os (os);
+             init_os (os, NULL);
          }
        }
       break;
@@ -1684,8 +1824,7 @@ section_already_linked (bfd *abfd, asection *sec, void *data)
 void
 lang_add_section (lang_statement_list_type *ptr,
                  asection *section,
-                 lang_output_section_statement_type *output,
-                 lang_input_statement_type *file)
+                 lang_output_section_statement_type *output)
 {
   flagword flags = section->flags;
   bfd_boolean discard;
@@ -1721,7 +1860,7 @@ lang_add_section (lang_statement_list_type *ptr,
       flagword flags;
 
       if (output->bfd_section == NULL)
-       init_os (output);
+       init_os (output, section);
 
       first = ! output->bfd_section->linker_has_input;
       output->bfd_section->linker_has_input = 1;
@@ -1743,7 +1882,6 @@ lang_add_section (lang_statement_list_type *ptr,
       new = new_stat (lang_input_section, ptr);
 
       new->section = section;
-      new->ifile = file;
       section->output_section = output->bfd_section;
 
       flags = section->flags;
@@ -1816,10 +1954,6 @@ lang_add_section (lang_statement_list_type *ptr,
       if (section->alignment_power > output->bfd_section->alignment_power)
        output->bfd_section->alignment_power = section->alignment_power;
 
-      /* If supplied an alignment, then force it.  */
-      if (output->section_alignment != -1)
-       output->bfd_section->alignment_power = output->section_alignment;
-
       if (bfd_get_arch (section->owner) == bfd_arch_tic54x
          && (section->flags & SEC_TIC54X_BLOCK) != 0)
        {
@@ -1923,15 +2057,14 @@ wild_sort (lang_wild_statement_type *wild,
              fa = FALSE;
            }
 
-         if (ls->ifile->the_bfd != NULL
-             && bfd_my_archive (ls->ifile->the_bfd) != NULL)
+         if (bfd_my_archive (ls->section->owner) != NULL)
            {
-             ln = bfd_get_filename (bfd_my_archive (ls->ifile->the_bfd));
+             ln = bfd_get_filename (bfd_my_archive (ls->section->owner));
              la = TRUE;
            }
          else
            {
-             ln = ls->ifile->filename;
+             ln = ls->section->owner->filename;
              la = FALSE;
            }
 
@@ -1946,7 +2079,7 @@ wild_sort (lang_wild_statement_type *wild,
              if (fa)
                fn = file->filename;
              if (la)
-               ln = ls->ifile->filename;
+               ln = ls->section->owner->filename;
 
              i = strcmp (fn, ln);
              if (i > 0)
@@ -1960,11 +2093,8 @@ wild_sort (lang_wild_statement_type *wild,
         looking at the sections for this file.  */
 
       if (sec != NULL && sec->spec.sorted != none)
-       {
-         if (compare_section (sec->spec.sorted, section,
-                              ls->section) < 0)
-           break;
-       }
+       if (compare_section (sec->spec.sorted, section, ls->section) < 0)
+         break;
     }
 
   return l;
@@ -1995,8 +2125,7 @@ output_section_callback (lang_wild_statement_type *ptr,
 
   if (before == NULL)
     lang_add_section (&ptr->children, section,
-                     (lang_output_section_statement_type *) output,
-                     file);
+                     (lang_output_section_statement_type *) output);
   else
     {
       lang_statement_list_type list;
@@ -2004,8 +2133,7 @@ output_section_callback (lang_wild_statement_type *ptr,
 
       lang_list_init (&list);
       lang_add_section (&list, section,
-                       (lang_output_section_statement_type *) output,
-                       file);
+                       (lang_output_section_statement_type *) output);
 
       /* If we are discarding the section, LIST.HEAD will
         be NULL.  */
@@ -2560,7 +2688,7 @@ open_output (const char *name)
 
   link_info.hash = bfd_link_hash_table_create (output);
   if (link_info.hash == NULL)
-    einfo (_("%P%F: can not create link hash table: %E\n"));
+    einfo (_("%P%F: can not create hash table: %E\n"));
 
   bfd_set_gp_size (output, g_switch_value);
   return output;
@@ -2990,7 +3118,7 @@ map_input_to_output_sections
             are initialized.  */
          exp_init_os (s->data_statement.exp);
          if (os != NULL && os->bfd_section == NULL)
-           init_os (os);
+           init_os (os, NULL);
          /* 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;
@@ -3004,11 +3132,11 @@ map_input_to_output_sections
        case lang_padding_statement_enum:
        case lang_input_statement_enum:
          if (os != NULL && os->bfd_section == NULL)
-           init_os (os);
+           init_os (os, NULL);
          break;
        case lang_assignment_statement_enum:
          if (os != NULL && os->bfd_section == NULL)
-           init_os (os);
+           init_os (os, NULL);
 
          /* Make sure that any sections mentioned in the assignment
             are initialized.  */
@@ -3036,7 +3164,7 @@ map_input_to_output_sections
                   (s->address_statement.section_name));
              
              if (aos->bfd_section == NULL)
-               init_os (aos);
+               init_os (aos, NULL);
              aos->addr_tree = s->address_statement.address;
            }
          break;
@@ -3044,90 +3172,6 @@ map_input_to_output_sections
     }
 }
 
-/* Worker function for lang_mark_used_section.  Recursiveness goes
-   here.  */
-
-static void
-lang_mark_used_section_1
-  (lang_statement_union_type *s,
-   lang_output_section_statement_type *output_section_statement)
-{
-  for (; s != NULL; s = s->header.next)
-    {
-      switch (s->header.type)
-       {
-       case lang_constructors_statement_enum:
-         break;
-
-       case lang_output_section_statement_enum:
-         {
-           lang_output_section_statement_type *os;
-
-           os = &(s->output_section_statement);
-           if (os->bfd_section != NULL)
-             lang_mark_used_section_1 (os->children.head, os);
-         }
-         break;
-       case lang_wild_statement_enum:
-         lang_mark_used_section_1 (s->wild_statement.children.head,
-                                   output_section_statement);
-
-         break;
-
-       case lang_object_symbols_statement_enum:
-       case lang_output_statement_enum:
-       case lang_target_statement_enum:
-         break;
-       case lang_data_statement_enum:
-         exp_mark_used_section (s->data_statement.exp,
-                                bfd_abs_section_ptr);
-         break;
-
-       case lang_reloc_statement_enum:
-         break;
-
-       case lang_input_section_enum:
-         break;
-
-       case lang_input_statement_enum:
-         break;
-       case lang_fill_statement_enum:
-         break;
-       case lang_assignment_statement_enum:
-         exp_mark_used_section (s->assignment_statement.exp,
-                                output_section_statement->bfd_section);
-         break;
-       case lang_padding_statement_enum:
-         break;
-
-       case lang_group_statement_enum:
-         lang_mark_used_section_1 (s->group_statement.children.head,
-                                   output_section_statement);
-         break;
-
-       default:
-         FAIL ();
-         break;
-       case lang_address_statement_enum:
-         break;
-       }
-    }
-}
-
-static void
-lang_mark_used_section (void)
-{
-  unsigned int gc_sections = link_info.gc_sections;
-
-  /* Callers of exp_fold_tree need to increment this.  */
-  lang_statement_iteration++;
-  lang_mark_used_section_1 (statement_list.head, abs_output_section);
-
-  link_info.gc_sections = 0;
-  bfd_gc_sections (output_bfd, &link_info);
-  link_info.gc_sections = gc_sections;
-}
-
 /* An output section might have been removed after its statement was
    added.  For example, ldemul_before_allocation can remove dynamic
    sections if they turn out to be not needed.  Clean them up here.  */
@@ -3137,7 +3181,14 @@ strip_excluded_output_sections (void)
 {
   lang_output_section_statement_type *os;
 
-  lang_mark_used_section ();
+  /* Run lang_size_sections (if not already done).  */
+  if (expld.phase != lang_mark_phase_enum)
+    {
+      expld.phase = lang_mark_phase_enum;
+      expld.dataseg.phase = exp_dataseg_none;
+      one_lang_size_sections_pass (NULL, FALSE);
+      lang_reset_memory_regions ();
+    }
 
   for (os = &lang_output_section_statement.head->output_section_statement;
        os != NULL;
@@ -3153,40 +3204,40 @@ strip_excluded_output_sections (void)
       if (output_section == NULL)
        continue;
 
-      exclude = FALSE;
-      if (output_section->map_head.s != NULL)
+      exclude = (output_section->rawsize == 0
+                && (output_section->flags & SEC_KEEP) == 0
+                && !bfd_section_removed_from_list (output_bfd,
+                                                   output_section));
+
+      /* Some sections have not yet been sized, notably .gnu.version,
+        .dynsym, .dynstr and .hash.  These all have SEC_LINKER_CREATED
+        input sections, so don't drop output sections that have such
+        input sections unless they are also marked SEC_EXCLUDE.  */
+      if (exclude && output_section->map_head.s != NULL)
        {
          asection *s;
 
-         for (s = output_section->map_head.s; s != NULL;
-              s = s->map_head.s)
-           if ((s->flags & SEC_EXCLUDE) == 0)
-             break;
-
-         output_section->map_head.link_order = NULL;
-         output_section->map_tail.link_order = NULL;
-
-         if (s == NULL)
-           exclude = TRUE;
+         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)
+             {
+               exclude = FALSE;
+               break;
+             }
        }
 
-      if (exclude
-         || (output_section->linker_has_input == 0
-             && ((output_section->flags
-                  & (SEC_KEEP | SEC_HAS_CONTENTS)) == 0)))
+      /* TODO: Don't just junk map_head.s, turn them into link_orders.  */
+      output_section->map_head.link_order = NULL;
+      output_section->map_tail.link_order = NULL;
+
+      if (exclude)
        {
-         if (exclude)
-           os->bfd_section = NULL;
-         else
-           /* We don't set bfd_section to NULL since bfd_section of the
-            * removed output section statement may still be used.  */
-           os->ignored = TRUE;
-         if (!bfd_section_removed_from_list (output_bfd,
-                                             output_section))
-           {
-             bfd_section_list_remove (output_bfd, output_section);
-             output_bfd->section_count--;
-           }
+         /* We don't set bfd_section to NULL since bfd_section of the
+            removed output section statement may still be used.  */
+         os->ignored = TRUE;
+         output_section->flags |= SEC_EXCLUDE;
+         bfd_section_list_remove (output_bfd, output_section);
+         output_bfd->section_count--;
        }
     }
 
@@ -3229,7 +3280,7 @@ print_output_section_statement
              bfd_vma addr;
 
              addr = exp_get_abs_int (output_section_statement->load_base, 0,
-                                     "load base", lang_final_phase_enum);
+                                     "load base");
              minfo (_(" load address 0x%V"), addr);
            }
        }
@@ -3299,7 +3350,6 @@ print_assignment (lang_assignment_statement_type *assignment,
   bfd_boolean is_dot;
   bfd_boolean computation_is_valid = TRUE;
   etree_type *tree;
-  etree_value_type result;
 
   for (i = 0; i < SECTION_NAME_MAP_LENGTH; i++)
     print_space ();
@@ -3319,18 +3369,17 @@ print_assignment (lang_assignment_statement_type *assignment,
       computation_is_valid = is_dot || (scan_for_self_assignment (dst, tree) == FALSE);
     }
 
-  result = exp_fold_tree (tree, output_section->bfd_section,
-                         lang_final_phase_enum, print_dot, &print_dot);
-  if (result.valid_p)
+  exp_fold_tree (tree, output_section->bfd_section, &print_dot);
+  if (expld.result.valid_p)
     {
       bfd_vma value;
 
       if (computation_is_valid)
        {
-         value = result.value;
+         value = expld.result.value;
 
-         if (result.section)
-           value += result.section->vma;
+         if (expld.result.section)
+           value += expld.result.section->vma;
 
          minfo ("0x%V", value);
          if (is_dot)
@@ -3346,8 +3395,8 @@ print_assignment (lang_assignment_statement_type *assignment,
            {
              value = h->u.def.value;
 
-             if (result.section)
-             value += result.section->vma;
+             if (expld.result.section)
+             value += expld.result.section->vma;
 
              minfo ("[0x%V]", value);
            }
@@ -3510,7 +3559,7 @@ print_data_statement (lang_data_statement_type *data)
   for (i = 0; i < SECTION_NAME_MAP_LENGTH; i++)
     print_space ();
 
-  addr = data->output_vma;
+  addr = data->output_offset;
   if (data->output_section != NULL)
     addr += data->output_section->vma;
 
@@ -3577,7 +3626,7 @@ print_reloc_statement (lang_reloc_statement_type *reloc)
   for (i = 0; i < SECTION_NAME_MAP_LENGTH; i++)
     print_space ();
 
-  addr = reloc->output_vma;
+  addr = reloc->output_offset;
   if (reloc->output_section != NULL)
     addr += reloc->output_section->vma;
 
@@ -3816,16 +3865,22 @@ insert_pad (lang_statement_union_type **ptr,
            bfd_vma dot)
 {
   static fill_type zero_fill = { 1, { 0 } };
-  lang_statement_union_type *pad;
+  lang_statement_union_type *pad = NULL;
 
-  pad = ((lang_statement_union_type *)
-        ((char *) ptr - offsetof (lang_statement_union_type, header.next)));
-  if (ptr != &statement_list.head
+  if (ptr != &statement_list.head)
+    pad = ((lang_statement_union_type *)
+          ((char *) ptr - offsetof (lang_statement_union_type, header.next)));
+  if (pad != NULL
+      && pad->header.type == lang_padding_statement_enum
+      && pad->padding_statement.output_section == output_section)
+    {
+      /* Use the existing pad statement.  */
+    }
+  else if ((pad = *ptr) != NULL
       && pad->header.type == lang_padding_statement_enum
       && pad->padding_statement.output_section == output_section)
     {
-      /* Use the existing pad statement.  The above test on output
-        section is probably redundant, but it doesn't hurt to check.  */
+      /* Use the existing pad statement.  */
     }
   else
     {
@@ -3856,7 +3911,8 @@ size_input_section
   lang_input_section_type *is = &((*this_ptr)->input_section);
   asection *i = is->section;
 
-  if (!is->ifile->just_syms_flag && (i->flags & SEC_EXCLUDE) == 0)
+  if (!((lang_input_statement_type *) i->owner->usrdata)->just_syms_flag
+      && (i->flags & SEC_EXCLUDE) == 0)
     {
       unsigned int alignment_needed;
       asection *o;
@@ -4040,11 +4096,25 @@ lang_size_sections_1
        {
        case lang_output_section_statement_enum:
          {
-           bfd_vma after;
+           bfd_vma newdot, after;
            lang_output_section_statement_type *os;
 
            os = &s->output_section_statement;
-           if (os->bfd_section == NULL || os->ignored)
+           if (os->addr_tree != NULL)
+             {
+               os->processed = FALSE;
+               exp_fold_tree (os->addr_tree, bfd_abs_section_ptr, &dot);
+
+               if (!expld.result.valid_p
+                   && expld.phase != lang_mark_phase_enum)
+                 einfo (_("%F%S: non constant or forward reference"
+                          " address expression for section %s\n"),
+                        os->name);
+
+               dot = expld.result.value + expld.result.section->vma;
+             }
+
+           if (os->bfd_section == NULL)
              /* This section was removed or never actually created.  */
              break;
 
@@ -4073,6 +4143,7 @@ lang_size_sections_1
                break;
              }
 
+           newdot = dot;
            if (bfd_is_abs_section (os->bfd_section))
              {
                /* No matter what happens, an abs section starts at zero.  */
@@ -4080,6 +4151,8 @@ lang_size_sections_1
              }
            else
              {
+               int align;
+
                if (os->addr_tree == NULL)
                  {
                    /* No address specified for this section, get one
@@ -4104,7 +4177,8 @@ lang_size_sections_1
                        && lang_memory_region_list != NULL
                        && (strcmp (lang_memory_region_list->name,
                                    DEFAULT_MEMORY_REGION) != 0
-                           || lang_memory_region_list->next != NULL))
+                           || lang_memory_region_list->next != NULL)
+                       && expld.phase != lang_mark_phase_enum)
                      {
                        /* By default this is an error rather than just a
                           warning because if we allocate the section to the
@@ -4127,80 +4201,62 @@ lang_size_sections_1
                                                       os->bfd_section));
                      }
 
-                   dot = os->region->current;
-
-                   if (os->section_alignment == -1)
-                     {
-                       bfd_vma olddot;
-
-                       olddot = dot;
-                       dot = align_power (dot,
-                                          os->bfd_section->alignment_power);
-
-                       if (dot != olddot && config.warn_section_align)
-                         einfo (_("%P: warning: changing start of section"
-                                  " %s by %u bytes\n"),
-                                os->name, (unsigned int) (dot - olddot));
-                     }
+                   newdot = os->region->current;
+                   align = os->bfd_section->alignment_power;
                  }
                else
-                 {
-                   etree_value_type r;
-
-                   os->processed = -1;
-                   r = exp_fold_tree (os->addr_tree,
-                                      bfd_abs_section_ptr,
-                                      lang_allocating_phase_enum,
-                                      dot, &dot);
-                   os->processed = 0;
+                 align = os->section_alignment;
 
-                   if (!r.valid_p)
-                     einfo (_("%F%S: non constant or forward reference"
-                              " address expression for section %s\n"),
-                            os->name);
-
-                   dot = r.value + r.section->vma;
+               /* Align to what the section needs.  */
+               if (align > 0)
+                 {
+                   bfd_vma savedot = newdot;
+                   newdot = align_power (newdot, align);
+
+                   if (newdot != savedot
+                       && (config.warn_section_align
+                           || os->addr_tree != NULL)
+                       && expld.phase != lang_mark_phase_enum)
+                     einfo (_("%P: warning: changing start of section"
+                              " %s by %lu bytes\n"),
+                            os->name, (unsigned long) (newdot - savedot));
                  }
 
-               /* The section starts here.
-                  First, align to what the section needs.  */
-
-               if (os->section_alignment != -1)
-                 dot = align_power (dot, os->section_alignment);
-
-               bfd_set_section_vma (0, os->bfd_section, dot);
+               bfd_set_section_vma (0, os->bfd_section, newdot);
 
                os->bfd_section->output_offset = 0;
              }
 
            lang_size_sections_1 (os->children.head, os, &os->children.head,
-                                 os->fill, dot, relax, check_regions);
+                                 os->fill, newdot, relax, check_regions);
+
+           os->processed = TRUE;
+
+           if (bfd_is_abs_section (os->bfd_section) || os->ignored)
+             {
+               ASSERT (os->bfd_section->size == 0);
+               break;
+             }
+
+           dot = os->bfd_section->vma;
 
            /* Put the section within the requested block size, or
               align at the block boundary.  */
-           after = ((os->bfd_section->vma
+           after = ((dot
                      + TO_ADDR (os->bfd_section->size)
                      + os->block_value - 1)
                     & - (bfd_vma) os->block_value);
 
-           if (bfd_is_abs_section (os->bfd_section))
-             ASSERT (after == os->bfd_section->vma);
-           else
-             os->bfd_section->size
-               = TO_SIZE (after - os->bfd_section->vma);
+           os->bfd_section->size = TO_SIZE (after - os->bfd_section->vma);
 
-           dot = os->bfd_section->vma;
            /* .tbss sections effectively have zero size.  */
            if ((os->bfd_section->flags & SEC_HAS_CONTENTS) != 0
                || (os->bfd_section->flags & SEC_THREAD_LOCAL) == 0
                || link_info.relocatable)
              dot += TO_ADDR (os->bfd_section->size);
 
-           os->processed = 1;
-
            if (os->update_dot_tree != 0)
-             exp_fold_tree (os->update_dot_tree, bfd_abs_section_ptr,
-                            lang_allocating_phase_enum, dot, &dot);
+             exp_fold_tree (os->update_dot_tree, bfd_abs_section_ptr, &dot);
 
            /* Update dot in the region ?
               We only do this if the section is going to be allocated,
@@ -4251,15 +4307,14 @@ lang_size_sections_1
          {
            unsigned int size = 0;
 
-           s->data_statement.output_vma =
+           s->data_statement.output_offset =
              dot - output_section_statement->bfd_section->vma;
            s->data_statement.output_section =
              output_section_statement->bfd_section;
 
            /* We might refer to provided symbols in the expression, and
               need to mark them as needed.  */
-           exp_fold_tree (s->data_statement.exp, bfd_abs_section_ptr,
-                          lang_allocating_phase_enum, dot, &dot);
+           exp_fold_tree (s->data_statement.exp, bfd_abs_section_ptr, &dot);
 
            switch (s->data_statement.type)
              {
@@ -4290,7 +4345,7 @@ lang_size_sections_1
          {
            int size;
 
-           s->reloc_statement.output_vma =
+           s->reloc_statement.output_offset =
              dot - output_section_statement->bfd_section->vma;
            s->reloc_statement.output_section =
              output_section_statement->bfd_section;
@@ -4301,21 +4356,21 @@ lang_size_sections_1
          break;
 
        case lang_wild_statement_enum:
-
          dot = lang_size_sections_1 (s->wild_statement.children.head,
                                      output_section_statement,
                                      &s->wild_statement.children.head,
                                      fill, dot, relax, check_regions);
-
          break;
 
        case lang_object_symbols_statement_enum:
          link_info.create_object_symbols_section =
            output_section_statement->bfd_section;
          break;
+
        case lang_output_statement_enum:
        case lang_target_statement_enum:
          break;
+
        case lang_input_section_enum:
          {
            asection *i;
@@ -4334,25 +4389,26 @@ lang_size_sections_1
                                      output_section_statement->fill, dot);
          }
          break;
+
        case lang_input_statement_enum:
          break;
+
        case lang_fill_statement_enum:
          s->fill_statement.output_section =
            output_section_statement->bfd_section;
 
          fill = s->fill_statement.fill;
          break;
+
        case lang_assignment_statement_enum:
          {
            bfd_vma newdot = dot;
 
            exp_fold_tree (s->assignment_statement.exp,
                           output_section_statement->bfd_section,
-                          lang_allocating_phase_enum,
-                          dot,
                           &newdot);
 
-           if (newdot != dot)
+           if (newdot != dot && !output_section_statement->ignored)
              {
                if (output_section_statement == abs_output_section)
                  {
@@ -4371,15 +4427,15 @@ lang_size_sections_1
 
                    /* Don't neuter the pad below when relaxing.  */
                    s = s->header.next;
-                 }
-
-               /* If dot is advanced, this implies that the section should
-                  have space allocated to it, unless the user has explicitly
-                  stated that the section should never be loaded.  */
-               if (!(output_section_statement->flags
-                     & (SEC_NEVER_LOAD | SEC_ALLOC)))
-                 output_section_statement->bfd_section->flags |= SEC_ALLOC;
 
+                   /* If dot is advanced, this implies that the section
+                      should have space allocated to it, unless the
+                      user has explicitly stated that the section
+                      should never be loaded.  */
+                   if (!(output_section_statement->flags
+                         & (SEC_NEVER_LOAD | SEC_ALLOC)))
+                     output_section_statement->bfd_section->flags |= SEC_ALLOC;
+                 }
                dot = newdot;
              }
          }
@@ -4422,47 +4478,43 @@ lang_size_sections_1
   return dot;
 }
 
-bfd_vma
-lang_size_sections
-  (lang_statement_union_type *s,
-   lang_output_section_statement_type *output_section_statement,
-   lang_statement_union_type **prev,
-   fill_type *fill,
-   bfd_vma dot,
-   bfd_boolean *relax,
-   bfd_boolean check_regions)
+void
+one_lang_size_sections_pass (bfd_boolean *relax, bfd_boolean check_regions)
 {
-  bfd_vma result;
-
-  /* Callers of exp_fold_tree need to increment this.  */
   lang_statement_iteration++;
+  lang_size_sections_1 (statement_list.head, abs_output_section,
+                       &statement_list.head, 0, 0, relax, check_regions);
+}
+
+void
+lang_size_sections (bfd_boolean *relax, bfd_boolean check_regions)
+{
+  expld.phase = lang_allocating_phase_enum;
+  expld.dataseg.phase = exp_dataseg_none;
 
-  exp_data_seg.phase = exp_dataseg_none;
-  result = lang_size_sections_1 (s, output_section_statement, prev, fill,
-                                dot, relax, check_regions);
-  if (exp_data_seg.phase == exp_dataseg_end_seen
-      && link_info.relro && exp_data_seg.relro_end)
+  one_lang_size_sections_pass (relax, check_regions);
+  if (expld.dataseg.phase == exp_dataseg_end_seen
+      && link_info.relro && expld.dataseg.relro_end)
     {
       /* If DATA_SEGMENT_ALIGN DATA_SEGMENT_RELRO_END pair was seen, try
-        to put exp_data_seg.relro on a (common) page boundary.  */
+        to put expld.dataseg.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));
+      expld.dataseg.phase = exp_dataseg_relro_adjust;
+      old_min_base = expld.dataseg.min_base;
+      maxpage = expld.dataseg.maxpagesize;
+      expld.dataseg.base += (-expld.dataseg.relro_end
+                            & (expld.dataseg.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)
+      relro_end = (expld.dataseg.relro_end + expld.dataseg.pagesize - 1)
+                 & ~(expld.dataseg.pagesize - 1);
+      if (old_min_base + maxpage < expld.dataseg.base)
        {
-         exp_data_seg.base -= maxpage;
+         expld.dataseg.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)
+      one_lang_size_sections_pass (relax, check_regions);
+      if (expld.dataseg.relro_end > relro_end)
        {
          /* The alignment of sections between DATA_SEGMENT_ALIGN
             and DATA_SEGMENT_RELRO_END caused huge padding to be
@@ -4473,46 +4525,42 @@ lang_size_sections
          /* 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
+           if (sec->vma >= expld.dataseg.base
+               && sec->vma < expld.dataseg.relro_end
                && sec->alignment_power > max_alignment_power)
              max_alignment_power = sec->alignment_power;
 
-         if (((bfd_vma) 1 << max_alignment_power) < exp_data_seg.pagesize)
+         if (((bfd_vma) 1 << max_alignment_power) < expld.dataseg.pagesize)
            {
-             if (exp_data_seg.base - (1 << max_alignment_power)
+             if (expld.dataseg.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);
+               expld.dataseg.base += expld.dataseg.pagesize;
+             expld.dataseg.base -= (1 << max_alignment_power);
+             one_lang_size_sections_pass (relax, check_regions);
            }
        }
-      link_info.relro_start = exp_data_seg.base;
-      link_info.relro_end = exp_data_seg.relro_end;
+      link_info.relro_start = expld.dataseg.base;
+      link_info.relro_end = expld.dataseg.relro_end;
     }
-  else if (exp_data_seg.phase == exp_dataseg_end_seen)
+  else if (expld.dataseg.phase == exp_dataseg_end_seen)
     {
       /* If DATA_SEGMENT_ALIGN DATA_SEGMENT_END pair was seen, check whether
         a page could be saved in the data segment.  */
       bfd_vma first, last;
 
-      first = -exp_data_seg.base & (exp_data_seg.pagesize - 1);
-      last = exp_data_seg.end & (exp_data_seg.pagesize - 1);
+      first = -expld.dataseg.base & (expld.dataseg.pagesize - 1);
+      last = expld.dataseg.end & (expld.dataseg.pagesize - 1);
       if (first && last
-         && ((exp_data_seg.base & ~(exp_data_seg.pagesize - 1))
-             != (exp_data_seg.end & ~(exp_data_seg.pagesize - 1)))
-         && first + last <= exp_data_seg.pagesize)
+         && ((expld.dataseg.base & ~(expld.dataseg.pagesize - 1))
+             != (expld.dataseg.end & ~(expld.dataseg.pagesize - 1)))
+         && first + last <= expld.dataseg.pagesize)
        {
-         exp_data_seg.phase = exp_dataseg_adjust;
-         lang_statement_iteration++;
-         result = lang_size_sections_1 (s, output_section_statement, prev,
-                                        fill, dot, relax, check_regions);
+         expld.dataseg.phase = exp_dataseg_adjust;
+         one_lang_size_sections_pass (relax, check_regions);
        }
     }
 
-  return result;
+  expld.phase = lang_final_phase_enum;
 }
 
 /* Worker function for lang_do_assignments.  Recursiveness goes here.  */
@@ -4557,36 +4605,31 @@ lang_do_assignments_1
                if (os->bfd_section && !os->ignored)
                  {
                    os->bfd_section->lma
-                     = exp_get_abs_int (os->load_base, 0, "load base",
-                                        lang_final_phase_enum);
+                     = exp_get_abs_int (os->load_base, 0, "load base");
                  }
              }
          }
          break;
+
        case lang_wild_statement_enum:
 
          dot = lang_do_assignments_1 (s->wild_statement.children.head,
                                       output_section_statement,
                                       fill, dot);
-
          break;
 
        case lang_object_symbols_statement_enum:
        case lang_output_statement_enum:
        case lang_target_statement_enum:
          break;
+
        case lang_data_statement_enum:
-         {
-           etree_value_type value;
-
-           value = exp_fold_tree (s->data_statement.exp,
-                                  bfd_abs_section_ptr,
-                                  lang_final_phase_enum, dot, &dot);
-           if (!value.valid_p)
-             einfo (_("%F%P: invalid data statement\n"));
-           s->data_statement.value
-             = value.value + value.section->vma;
-         }
+         exp_fold_tree (s->data_statement.exp, bfd_abs_section_ptr, &dot);
+         if (expld.result.valid_p)
+           s->data_statement.value = (expld.result.value
+                                      + expld.result.section->vma);
+         else
+           einfo (_("%F%P: invalid data statement\n"));
          {
            unsigned int size;
            switch (s->data_statement.type)
@@ -4614,16 +4657,12 @@ lang_do_assignments_1
          break;
 
        case lang_reloc_statement_enum:
-         {
-           etree_value_type value;
-
-           value = exp_fold_tree (s->reloc_statement.addend_exp,
-                                  bfd_abs_section_ptr,
-                                  lang_final_phase_enum, dot, &dot);
-           s->reloc_statement.addend_value = value.value;
-           if (!value.valid_p)
-             einfo (_("%F%P: invalid reloc statement\n"));
-         }
+         exp_fold_tree (s->reloc_statement.addend_exp,
+                        bfd_abs_section_ptr, &dot);
+         if (expld.result.valid_p)
+           s->reloc_statement.addend_value = expld.result.value;
+         else
+           einfo (_("%F%P: invalid reloc statement\n"));
          dot += TO_ADDR (bfd_get_reloc_size (s->reloc_statement.howto));
          break;
 
@@ -4638,19 +4677,17 @@ lang_do_assignments_1
 
        case lang_input_statement_enum:
          break;
+
        case lang_fill_statement_enum:
          fill = s->fill_statement.fill;
          break;
-       case lang_assignment_statement_enum:
-         {
-           exp_fold_tree (s->assignment_statement.exp,
-                          output_section_statement->bfd_section,
-                          lang_final_phase_enum,
-                          dot,
-                          &dot);
-         }
 
+       case lang_assignment_statement_enum:
+         exp_fold_tree (s->assignment_statement.exp,
+                        output_section_statement->bfd_section,
+                        &dot);
          break;
+
        case lang_padding_statement_enum:
          dot += TO_ADDR (s->padding_statement.size);
          break;
@@ -4659,30 +4696,24 @@ lang_do_assignments_1
          dot = lang_do_assignments_1 (s->group_statement.children.head,
                                       output_section_statement,
                                       fill, dot);
-
          break;
 
        default:
          FAIL ();
          break;
+
        case lang_address_statement_enum:
          break;
        }
-
     }
   return dot;
 }
 
 void
-lang_do_assignments
-  (lang_statement_union_type *s,
-   lang_output_section_statement_type *output_section_statement,
-   fill_type *fill,
-   bfd_vma dot)
+lang_do_assignments (void)
 {
-  /* Callers of exp_fold_tree need to increment this.  */
   lang_statement_iteration++;
-  lang_do_assignments_1 (s, output_section_statement, fill, dot);
+  lang_do_assignments_1 (statement_list.head, abs_output_section, NULL, 0);
 }
 
 /* Fix any .startof. or .sizeof. symbols.  When the assemblers see the
@@ -4732,7 +4763,7 @@ lang_set_startof (void)
 }
 
 static void
-lang_finish (void)
+lang_end (void)
 {
   struct bfd_link_hash_entry *h;
   bfd_boolean warn;
@@ -5044,17 +5075,17 @@ lang_place_orphans (void)
 
                        }
                      lang_add_section (&default_common_section->children, s,
-                                       default_common_section, file);
+                                       default_common_section);
                    }
                }
-             else if (ldemul_place_orphan (file, s))
+             else if (ldemul_place_orphan (s))
                ;
              else
                {
                  lang_output_section_statement_type *os;
 
                  os = lang_output_section_statement_lookup (s->name);
-                 lang_add_section (&os->children, s, os, file);
+                 lang_add_section (&os->children, s, os);
                }
            }
        }
@@ -5202,10 +5233,9 @@ lang_enter_output_section_statement (const char *output_section_statement_name,
 {
   lang_output_section_statement_type *os;
 
-  current_section =
-   os =
-    lang_output_section_statement_lookup_1 (output_section_statement_name,
-                                           constraint);
+   os = lang_output_section_statement_lookup_1 (output_section_statement_name,
+                                               constraint);
+   current_section = os;
 
   /* Make next things chain into subchain of this.  */
 
@@ -5222,9 +5252,9 @@ lang_enter_output_section_statement (const char *output_section_statement_name,
   stat_ptr = &os->children;
 
   os->subsection_alignment =
-    topower (exp_get_value_int (subalign, -1, "subsection alignment", 0));
+    topower (exp_get_value_int (subalign, -1, "subsection alignment"));
   os->section_alignment =
-    topower (exp_get_value_int (align, -1, "section alignment", 0));
+    topower (exp_get_value_int (align, -1, "section alignment"));
 
   os->load_base = ebase;
   return os;
@@ -5233,9 +5263,9 @@ lang_enter_output_section_statement (const char *output_section_statement_name,
 void
 lang_final (void)
 {
-  lang_output_statement_type *new =
-    new_stat (lang_output_statement, stat_ptr);
+  lang_output_statement_type *new;
 
+  new = new_stat (lang_output_statement, stat_ptr);
   new->name = output_filename;
 }
 
@@ -5246,6 +5276,7 @@ lang_reset_memory_regions (void)
 {
   lang_memory_region_type *p = lang_memory_region_list;
   asection *o;
+  lang_output_section_statement_type *os;
 
   for (p = lang_memory_region_list; p != NULL; p = p->next)
     {
@@ -5253,6 +5284,11 @@ lang_reset_memory_regions (void)
       p->current = p->origin;
     }
 
+  for (os = &lang_output_section_statement.head->output_section_statement;
+       os != NULL;
+       os = os->next)
+    os->processed = FALSE;
+
   for (o = output_bfd->sections; o != NULL; o = o->next)
     {
       /* Save the last size for possible use by bfd_relax_section.  */
@@ -5439,9 +5475,7 @@ lang_process (void)
   lang_record_phdrs ();
 
   /* Size up the sections.  */
-  lang_size_sections (statement_list.head, abs_output_section,
-                     &statement_list.head, 0, 0, NULL,
-                     command_line.relax ? FALSE : TRUE);
+  lang_size_sections (NULL, !command_line.relax);
 
   /* Now run around and relax if we can.  */
   if (command_line.relax)
@@ -5459,8 +5493,7 @@ lang_process (void)
 
          /* Do all the assignments with our current guesses as to
             section sizes.  */
-         lang_do_assignments (statement_list.head, abs_output_section,
-                              NULL, 0);
+         lang_do_assignments ();
 
          /* We must do this after lang_do_assignments, because it uses
             size.  */
@@ -5468,8 +5501,7 @@ lang_process (void)
 
          /* Perform another relax pass - this time we know where the
             globals are, so can make a better guess.  */
-         lang_size_sections (statement_list.head, abs_output_section,
-                             &statement_list.head, 0, 0, &relax_again, FALSE);
+         lang_size_sections (&relax_again, FALSE);
 
          /* If the normal relax is done and the relax finalize pass
             is not performed yet, we perform another relax pass.  */
@@ -5482,10 +5514,9 @@ lang_process (void)
       while (relax_again);
 
       /* Final extra sizing to report errors.  */
-      lang_do_assignments (statement_list.head, abs_output_section, NULL, 0);
+      lang_do_assignments ();
       lang_reset_memory_regions ();
-      lang_size_sections (statement_list.head, abs_output_section,
-                         &statement_list.head, 0, 0, NULL, TRUE);
+      lang_size_sections (NULL, TRUE);
     }
 
   /* See if anything special should be done now we know how big
@@ -5498,7 +5529,7 @@ lang_process (void)
   /* Do all the assignments, now that we know the final resting places
      of all the symbols.  */
 
-  lang_do_assignments (statement_list.head, abs_output_section, NULL, 0);
+  lang_do_assignments ();
 
   /* Make sure that the section addresses make sense.  */
   if (! link_info.relocatable
@@ -5507,7 +5538,7 @@ lang_process (void)
 
   /* Final stuffs.  */
   ldemul_finish ();
-  lang_finish ();
+  lang_end ();
 }
 
 /* EXPORTED TO YACC */
@@ -5596,11 +5627,10 @@ lang_default_entry (const char *name)
 void
 lang_add_target (const char *name)
 {
-  lang_target_statement_type *new = new_stat (lang_target_statement,
-                                             stat_ptr);
+  lang_target_statement_type *new;
 
+  new = new_stat (lang_target_statement, stat_ptr);
   new->target = name;
-
 }
 
 void
@@ -5621,22 +5651,20 @@ lang_add_map (const char *name)
 void
 lang_add_fill (fill_type *fill)
 {
-  lang_fill_statement_type *new = new_stat (lang_fill_statement,
-                                           stat_ptr);
+  lang_fill_statement_type *new;
 
+  new = new_stat (lang_fill_statement, stat_ptr);
   new->fill = fill;
 }
 
 void
 lang_add_data (int type, union etree_union *exp)
 {
+  lang_data_statement_type *new;
 
-  lang_data_statement_type *new = new_stat (lang_data_statement,
-                                           stat_ptr);
-
+  new = new_stat (lang_data_statement, stat_ptr);
   new->exp = exp;
   new->type = type;
-
 }
 
 /* Create a new reloc statement.  RELOC is the BFD relocation type to
@@ -5663,15 +5691,15 @@ lang_add_reloc (bfd_reloc_code_real_type reloc,
 
   p->addend_value = 0;
   p->output_section = NULL;
-  p->output_vma = 0;
+  p->output_offset = 0;
 }
 
 lang_assignment_statement_type *
 lang_add_assignment (etree_type *exp)
 {
-  lang_assignment_statement_type *new = new_stat (lang_assignment_statement,
-                                                 stat_ptr);
+  lang_assignment_statement_type *new;
 
+  new = new_stat (lang_assignment_statement, stat_ptr);
   new->exp = exp;
   return new;
 }
@@ -5679,7 +5707,7 @@ lang_add_assignment (etree_type *exp)
 void
 lang_add_attribute (enum statement_enum attribute)
 {
-  new_statement (attribute, sizeof (lang_statement_union_type), stat_ptr);
+  new_statement (attribute, sizeof (lang_statement_header_type), stat_ptr);
 }
 
 void
@@ -5687,7 +5715,7 @@ lang_startup (const char *name)
 {
   if (startup_file != NULL)
     {
-      einfo (_("%P%Fmultiple STARTUP files\n"));
+      einfo (_("%P%Fmultiple STARTUP files\n"));
     }
   first_file->filename = name;
   first_file->local_sym_name = name;
@@ -5886,8 +5914,7 @@ lang_new_phdr (const char *name,
   n = stat_alloc (sizeof (struct lang_phdr));
   n->next = NULL;
   n->name = name;
-  n->type = exp_get_value_int (type, 0, "program header type",
-                              lang_final_phase_enum);
+  n->type = exp_get_value_int (type, 0, "program header type");
   n->filehdr = filehdr;
   n->phdrs = phdrs;
   n->at = at;
@@ -5963,14 +5990,12 @@ lang_record_phdrs (void)
       if (l->flags == NULL)
        flags = 0;
       else
-       flags = exp_get_vma (l->flags, 0, "phdr flags",
-                            lang_final_phase_enum);
+       flags = exp_get_vma (l->flags, 0, "phdr flags");
 
       if (l->at == NULL)
        at = 0;
       else
-       at = exp_get_vma (l->at, 0, "phdr load address",
-                         lang_final_phase_enum);
+       at = exp_get_vma (l->at, 0, "phdr load address");
 
       if (! bfd_record_phdr (output_bfd, l->type,
                             l->flags != NULL, flags, l->at != NULL,
@@ -6249,8 +6274,8 @@ lang_vers_match (struct bfd_elf_version_expr_head *head,
                while (expr && strcmp (expr->symbol, sym) == 0)
                  if (expr->mask == BFD_ELF_VERSION_C_TYPE)
                    goto out_ret;
-               else
-                 expr = expr->next;
+                 else
+                   expr = expr->next;
              }
            /* Fallthrough */
          case BFD_ELF_VERSION_C_TYPE:
@@ -6261,8 +6286,8 @@ lang_vers_match (struct bfd_elf_version_expr_head *head,
                while (expr && strcmp (expr->symbol, cxx_sym) == 0)
                  if (expr->mask == BFD_ELF_VERSION_CXX_TYPE)
                    goto out_ret;
-               else
-                 expr = expr->next;
+                 else
+                   expr = expr->next;
              }
            /* Fallthrough */
          case BFD_ELF_VERSION_CXX_TYPE:
@@ -6273,8 +6298,8 @@ lang_vers_match (struct bfd_elf_version_expr_head *head,
                while (expr && strcmp (expr->symbol, java_sym) == 0)
                  if (expr->mask == BFD_ELF_VERSION_JAVA_TYPE)
                    goto out_ret;
-               else
-                 expr = expr->next;
+                 else
+                   expr = expr->next;
              }
            /* Fallthrough */
          default:
@@ -6287,10 +6312,13 @@ lang_vers_match (struct bfd_elf_version_expr_head *head,
     expr = head->remaining;
   else
     expr = prev->next;
-  while (expr)
+  for (; expr; expr = expr->next)
     {
       const char *s;
 
+      if (!expr->pattern)
+       continue;
+
       if (expr->pattern[0] == '*' && expr->pattern[1] == '\0')
        break;
 
@@ -6302,7 +6330,6 @@ lang_vers_match (struct bfd_elf_version_expr_head *head,
        s = sym;
       if (fnmatch (expr->pattern, s, 0) == 0)
        break;
-      expr = expr->next;
     }
 
 out_ret:
@@ -6357,21 +6384,24 @@ realsymbol (const char *pattern)
     }
 }
 
-/* This is called for each variable name or match expression.  */
+/* This is called for each variable name or match expression.  NEW is
+   the name of the symbol to match, or, if LITERAL_P is FALSE, a glob
+   pattern to be matched against symbol names.  */
 
 struct bfd_elf_version_expr *
 lang_new_vers_pattern (struct bfd_elf_version_expr *orig,
                       const char *new,
-                      const char *lang)
+                      const char *lang,
+                      bfd_boolean literal_p)
 {
   struct bfd_elf_version_expr *ret;
 
   ret = xmalloc (sizeof *ret);
   ret->next = orig;
-  ret->pattern = new;
+  ret->pattern = literal_p ? NULL : new;
   ret->symver = 0;
   ret->script = 0;
-  ret->symbol = realsymbol (new);
+  ret->symbol = literal_p ? new : realsymbol (new);
 
   if (lang == NULL || strcasecmp (lang, "C") == 0)
     ret->mask = BFD_ELF_VERSION_C_TYPE;
@@ -6655,7 +6685,7 @@ lang_do_version_exports_section (void)
       p = contents;
       while (p < contents + len)
        {
-         greg = lang_new_vers_pattern (greg, p, NULL);
+         greg = lang_new_vers_pattern (greg, p, NULL, FALSE);
          p = strchr (p, '\0') + 1;
        }
 
@@ -6665,7 +6695,7 @@ lang_do_version_exports_section (void)
       sec->flags |= SEC_EXCLUDE;
     }
 
-  lreg = lang_new_vers_pattern (NULL, "*", NULL);
+  lreg = lang_new_vers_pattern (NULL, "*", NULL, FALSE);
   lang_register_vers_node (command_line.version_exports_section,
                           lang_new_vers_node (greg, lreg), NULL);
 }
This page took 0.04678 seconds and 4 git commands to generate.