OSDN Git Service

PR 2434
[pf3gnuchains/pf3gnuchains3x.git] / ld / ldlang.c
index fb5454c..f6d849e 100644 (file)
@@ -1,6 +1,6 @@
 /* Linker command language support.
    Copyright 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
-   2001, 2002, 2003, 2004, 2005
+   2001, 2002, 2003, 2004, 2005, 2006
    Free Software Foundation, Inc.
 
    This file is part of GLD, the Gnu Linker.
@@ -783,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;
     }
 
@@ -868,6 +869,83 @@ 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,
+                             sizeof (struct output_statement_hash_entry),
+                             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
@@ -877,6 +955,8 @@ lang_init (void)
 
   stat_ptr = &statement_list;
 
+  output_statement_table_init ();
+
   lang_list_init (stat_ptr);
 
   lang_list_init (&input_file_chain);
@@ -896,8 +976,16 @@ lang_init (void)
      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))
-    einfo (_("%P%F: out of memory during initialization"));
+                             lang_definedness_newfunc,
+                             sizeof (struct lang_definedness_hash_entry),
+                             3))
+    einfo (_("%P%F: can not create hash table: %E\n"));
+}
+
+void
+lang_finish (void)
+{
+  output_statement_table_free ();
 }
 
 /*----------------------------------------------------------------------
@@ -981,73 +1069,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;
-  lang_output_section_statement_type **nextp;
+  struct output_statement_hash_entry *entry;
+  struct output_statement_hash_entry *last_ent;
+  unsigned long hash;
+
+  entry = ((struct output_statement_hash_entry *)
+          bfd_hash_lookup (&output_statement_table, name, TRUE, FALSE));
+  if (entry == NULL)
+    {
+      einfo (_("%P%F: failed creating section `%s': %E\n"), name);
+      return NULL;
+    }
 
-  lookup = lang_output_section_find_1 (name, constraint);
-  if (lookup == 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);
-
-      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;
-
-      /* 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 = &lookup->next;
-      lang_statement_append (&lang_output_section_statement,
-                            (lang_statement_union_type *) lookup,
-                            (lang_statement_union_type **) nextp);
-    }
-  return lookup;
+  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);
+
+      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;
+    }
+
+  entry->os.name = name;
+  entry->os.constraint = constraint;
+  return &entry->os;
 }
 
 lang_output_section_statement_type *
@@ -1063,7 +1157,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;
@@ -1079,7 +1174,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)))
@@ -1087,7 +1187,8 @@ lang_output_section_find_by_flags (const asection *sec,
     }
   if (found != NULL)
     {
-      *exact = found;
+      if (exact != NULL)
+       *exact = found;
       return found;
     }
 
@@ -1098,40 +1199,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))
@@ -1139,37 +1251,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.
@@ -1178,28 +1302,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,
@@ -1270,7 +1388,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);
 
@@ -1353,13 +1471,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)
@@ -1373,9 +1498,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:
@@ -1424,7 +1551,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;
 
@@ -1568,7 +1700,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;
@@ -1585,9 +1717,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)
     {
@@ -1605,6 +1734,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
@@ -1650,7 +1788,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;
@@ -1690,8 +1828,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;
@@ -1727,7 +1864,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;
@@ -1749,7 +1886,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;
@@ -1822,10 +1958,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)
        {
@@ -1929,15 +2061,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;
            }
 
@@ -1952,7 +2083,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)
@@ -1998,8 +2129,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;
@@ -2007,8 +2137,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.  */
@@ -2563,7 +2692,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;
@@ -2993,7 +3122,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;
@@ -3007,11 +3136,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.  */
@@ -3039,7 +3168,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;
@@ -3434,7 +3563,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;
 
@@ -3501,7 +3630,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;
 
@@ -3786,7 +3915,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;
@@ -3974,6 +4104,20 @@ lang_size_sections_1
            lang_output_section_statement_type *os;
 
            os = &s->output_section_statement;
+           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;
@@ -4003,6 +4147,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.  */
@@ -4010,6 +4155,8 @@ lang_size_sections_1
              }
            else
              {
+               int align;
+
                if (os->addr_tree == NULL)
                  {
                    /* No address specified for this section, get one
@@ -4059,44 +4206,26 @@ lang_size_sections_1
                      }
 
                    newdot = os->region->current;
-
-                   if (os->section_alignment == -1)
-                     {
-                       bfd_vma savedot = newdot;
-                       newdot = align_power (newdot,
-                                             os->bfd_section->alignment_power);
-
-                       if (newdot != savedot
-                           && config.warn_section_align
-                           && expld.phase != lang_mark_phase_enum)
-                         einfo (_("%P: warning: changing start of section"
-                                  " %s by %lu bytes\n"),
-                                os->name, (unsigned long) (newdot - savedot));
-                     }
+                   align = os->bfd_section->alignment_power;
                  }
                else
+                 align = os->section_alignment;
+
+               /* Align to what the section needs.  */
+               if (align > 0)
                  {
-                   newdot = dot;
-                   os->processed = -1;
-                   exp_fold_tree (os->addr_tree, bfd_abs_section_ptr,
-                                  &newdot);
-                   os->processed = 0;
+                   bfd_vma savedot = newdot;
+                   newdot = align_power (newdot, align);
 
-                   if (!expld.result.valid_p
+                   if (newdot != savedot
+                       && (config.warn_section_align
+                           || os->addr_tree != NULL)
                        && expld.phase != lang_mark_phase_enum)
-                     einfo (_("%F%S: non constant or forward reference"
-                              " address expression for section %s\n"),
-                            os->name);
-
-                   newdot = expld.result.value + expld.result.section->vma;
+                     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)
-                 newdot = align_power (newdot, os->section_alignment);
-
                bfd_set_section_vma (0, os->bfd_section, newdot);
 
                os->bfd_section->output_offset = 0;
@@ -4105,7 +4234,7 @@ lang_size_sections_1
            lang_size_sections_1 (os->children.head, os, &os->children.head,
                                  os->fill, newdot, relax, check_regions);
 
-           os->processed = 1;
+           os->processed = TRUE;
 
            if (bfd_is_abs_section (os->bfd_section) || os->ignored)
              {
@@ -4182,7 +4311,7 @@ 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;
@@ -4220,7 +4349,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;
@@ -4638,7 +4767,7 @@ lang_set_startof (void)
 }
 
 static void
-lang_finish (void)
+lang_end (void)
 {
   struct bfd_link_hash_entry *h;
   bfd_boolean warn;
@@ -4950,17 +5079,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);
                }
            }
        }
@@ -5108,10 +5237,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.  */
 
@@ -5139,9 +5267,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;
 }
 
@@ -5163,7 +5291,7 @@ lang_reset_memory_regions (void)
   for (os = &lang_output_section_statement.head->output_section_statement;
        os != NULL;
        os = os->next)
-    os->processed = 0;
+    os->processed = FALSE;
 
   for (o = output_bfd->sections; o != NULL; o = o->next)
     {
@@ -5414,7 +5542,7 @@ lang_process (void)
 
   /* Final stuffs.  */
   ldemul_finish ();
-  lang_finish ();
+  lang_end ();
 }
 
 /* EXPORTED TO YACC */
@@ -5503,11 +5631,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
@@ -5528,22 +5655,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
@@ -5570,15 +5695,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;
 }
@@ -5586,7 +5711,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
@@ -5594,7 +5719,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;
@@ -6153,8 +6278,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:
@@ -6165,8 +6290,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:
@@ -6177,8 +6302,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:
@@ -6191,10 +6316,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;
 
@@ -6206,7 +6334,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:
@@ -6261,21 +6388,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;
@@ -6559,7 +6689,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;
        }
 
@@ -6569,7 +6699,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);
 }