* config.bfd (sh*eb-*-linux*, sh*-*-linux*): Add the alternative
[deliverable/binutils-gdb.git] / ld / ldlang.c
index d463d7b7d4c6c8bd906010965e7c6df1288a43f0..8ebd1bd2eaad389399db5d6089b99263e30a447f 100644 (file)
@@ -1,24 +1,24 @@
 /* Linker command language support.
    Copyright 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
-   2001
+   2001, 2002
    Free Software Foundation, Inc.
 
-This file is part of GLD, the Gnu Linker.
+   This file is part of GLD, the Gnu Linker.
 
-GLD is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2, or (at your option)
-any later version.
+   GLD is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
 
-GLD is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
+   GLD is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
 
-You should have received a copy of the GNU General Public License
-along with GLD; see the file COPYING.  If not, write to the Free
-Software Foundation, 59 Temple Place - Suite 330, Boston, MA
-02111-1307, USA.  */
+   You should have received a copy of the GNU General Public License
+   along with GLD; see the file COPYING.  If not, write to the Free
+   Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+   02111-1307, USA.  */
 
 #include "bfd.h"
 #include "sysdep.h"
@@ -29,9 +29,9 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 
 #include "ld.h"
 #include "ldmain.h"
-#include "ldgram.h"
 #include "ldexp.h"
 #include "ldlang.h"
+#include "ldgram.h"
 #include "ldlex.h"
 #include "ldmisc.h"
 #include "ldctor.h"
@@ -40,6 +40,10 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 #include "fnmatch.h"
 #include "demangle.h"
 
+#ifndef offsetof
+#define offsetof(TYPE,MEMBER) ((size_t)&(((TYPE*)0)->MEMBER))
+#endif
+
 /* FORWARDS */
 static lang_statement_union_type *new_statement
   PARAMS ((enum statement_enum, size_t, lang_statement_list_type *));
@@ -92,10 +96,12 @@ static bfd *open_output PARAMS ((const char *));
 static void ldlang_open_output PARAMS ((lang_statement_union_type *));
 static void open_input_bfds PARAMS ((lang_statement_union_type *, boolean));
 static void lang_reasonable_defaults PARAMS ((void));
+static void insert_undefined PARAMS ((const char *));
 static void lang_place_undefineds PARAMS ((void));
 static void map_input_to_output_sections
   PARAMS ((lang_statement_union_type *, const char *,
           lang_output_section_statement_type *));
+static void strip_excluded_output_sections PARAMS ((void));
 static void print_output_section_statement
   PARAMS ((lang_output_section_statement_type *));
 static void print_assignment
@@ -119,11 +125,11 @@ static void print_statement_list
   PARAMS ((lang_statement_union_type *, lang_output_section_statement_type *));
 static void print_statements PARAMS ((void));
 static void insert_pad
-  PARAMS ((lang_statement_union_type **, fill_type,
+  PARAMS ((lang_statement_union_type **, fill_type *,
           unsigned int, asection *, bfd_vma));
 static bfd_vma size_input_section
   PARAMS ((lang_statement_union_type **, lang_output_section_statement_type *,
-          fill_type, bfd_vma));
+          fill_type *, bfd_vma));
 static void lang_finish PARAMS ((void));
 static void ignore_bfd_errors PARAMS ((const char *, ...));
 static void lang_check PARAMS ((void));
@@ -132,10 +138,12 @@ static boolean lang_one_common PARAMS ((struct bfd_link_hash_entry *, PTR));
 static void lang_place_orphans PARAMS ((void));
 static int topower PARAMS ((int));
 static void lang_set_startof PARAMS ((void));
-static void reset_memory_regions PARAMS ((void));
 static void gc_section_callback
   PARAMS ((lang_wild_statement_type *, struct wildcard_list *, asection *,
           lang_input_statement_type *, PTR));
+static void lang_get_regions PARAMS ((struct memory_region_struct **,
+                                     struct memory_region_struct **,
+                                     const char *, const char *, int));
 static void lang_record_phdrs PARAMS ((void));
 static void lang_gc_wild PARAMS ((lang_wild_statement_type *));
 static void lang_gc_sections_1 PARAMS ((lang_statement_union_type *));
@@ -151,6 +159,9 @@ static void lang_check_section_addresses PARAMS ((void));
 static void os_region_check
   PARAMS ((lang_output_section_statement_type *,
           struct memory_region_struct *, etree_type *, bfd_vma));
+static bfd_vma lang_size_sections_1
+  PARAMS ((lang_statement_union_type *, lang_output_section_statement_type *,
+          lang_statement_union_type **, fill_type *, bfd_vma, boolean *));
 
 typedef void (*callback_t) PARAMS ((lang_wild_statement_type *,
                                    struct wildcard_list *,
@@ -178,7 +189,8 @@ lang_output_section_statement_type *abs_output_section;
 lang_statement_list_type lang_output_section_statement;
 lang_statement_list_type *stat_ptr = &statement_list;
 lang_statement_list_type file_chain = { NULL, NULL };
-const char *entry_symbol = NULL;
+struct bfd_sym_chain entry_symbol = { NULL, NULL };
+const char *entry_section = ".text";
 boolean entry_from_cmdline;
 boolean lang_has_input_file = false;
 boolean had_output_filename = false;
@@ -251,47 +263,59 @@ walk_wild_section (ptr, file, callback, data)
       struct wildcard_list *sec;
 
       sec = ptr->section_list;
-      do
+      if (sec == NULL)
+       (*callback) (ptr, sec, s, file, data);
+
+      while (sec != NULL)
        {
          boolean skip = false;
+         struct name_list *list_tmp;
 
-         if (sec != NULL)
+         /* Don't process sections from files which were
+            excluded.  */
+         for (list_tmp = sec->spec.exclude_name_list;
+              list_tmp;
+              list_tmp = list_tmp->next)
            {
-             struct name_list *list_tmp;
+             if (wildcardp (list_tmp->name))
+               skip = fnmatch (list_tmp->name, file->filename, 0) == 0;
+             else
+               skip = strcmp (list_tmp->name, file->filename) == 0;
 
-             /* Don't process sections from files which were
-                excluded.  */
-             for (list_tmp = sec->spec.exclude_name_list;
-                  list_tmp;
-                  list_tmp = list_tmp->next)
+             /* If this file is part of an archive, and the archive is
+                excluded, exclude this file.  */
+             if (! skip && file->the_bfd != NULL
+                 && file->the_bfd->my_archive != NULL
+                 && file->the_bfd->my_archive->filename != NULL)
                {
                  if (wildcardp (list_tmp->name))
-                   skip = fnmatch (list_tmp->name, file->filename, 0) == 0;
+                   skip = fnmatch (list_tmp->name,
+                                   file->the_bfd->my_archive->filename,
+                                   0) == 0;
                  else
-                   skip = strcmp (list_tmp->name, file->filename) == 0;
-
-                 if (skip)
-                   break;
+                   skip = strcmp (list_tmp->name,
+                                  file->the_bfd->my_archive->filename) == 0;
                }
 
-             if (!skip && sec->spec.name != NULL)
-               {
-                 const char *sname = bfd_get_section_name (file->the_bfd, s);
+             if (skip)
+               break;
+           }
 
-                 if (wildcardp (sec->spec.name))
-                   skip = fnmatch (sec->spec.name, sname, 0) != 0;
-                 else
-                   skip = strcmp (sec->spec.name, sname) != 0;
-               }
+         if (!skip && sec->spec.name != NULL)
+           {
+             const char *sname = bfd_get_section_name (file->the_bfd, s);
+
+             if (wildcardp (sec->spec.name))
+               skip = fnmatch (sec->spec.name, sname, 0) != 0;
+             else
+               skip = strcmp (sec->spec.name, sname) != 0;
            }
 
          if (!skip)
            (*callback) (ptr, sec, s, file, data);
 
-         if (sec != NULL)
-           sec = sec->next;
+         sec = sec->next;
        }
-      while (sec != NULL);
     }
 }
 
@@ -601,6 +625,10 @@ lang_memory_region_lookup (name)
 {
   lang_memory_region_type *p;
 
+  /* NAME is NULL for LMA memspecs if no region was specified.  */
+  if (name == NULL)
+    return NULL;
+
   for (p = lang_memory_region_list;
        p != (lang_memory_region_type *) NULL;
        p = p->next)
@@ -706,7 +734,7 @@ lang_output_section_statement_lookup (name)
        new_stat (lang_output_section_statement, stat_ptr);
       lookup->region = (lang_memory_region_type *) NULL;
       lookup->lma_region = (lang_memory_region_type *) NULL;
-      lookup->fill = 0;
+      lookup->fill = (fill_type *) 0;
       lookup->block_value = 1;
       lookup->name = name;
 
@@ -722,6 +750,7 @@ lang_output_section_statement_lookup (name)
       lookup->subsection_alignment = -1;
       lookup->section_alignment = -1;
       lookup->load_base = (union etree_union *) NULL;
+      lookup->update_dot_tree = NULL;
       lookup->phdrs = NULL;
 
       lang_statement_append (&lang_output_section_statement,
@@ -938,8 +967,7 @@ section_already_linked (abfd, sec, data)
      discard all sections.  */
   if (entry->just_syms_flag)
     {
-      sec->output_section = bfd_abs_section_ptr;
-      sec->output_offset = sec->vma;
+      bfd_link_just_syms (sec, &link_info);
       return;
     }
 
@@ -962,7 +990,7 @@ section_already_linked (abfd, sec, data)
      of having link once sections in the first place.
 
      Also, not merging link once sections in a relocatable link
-     causes trouble for MIPS ELF, which relies in link once semantics
+     causes trouble for MIPS ELF, which relies on link once semantics
      to handle the .reginfo section correctly.  */
 
   name = bfd_get_section_name (abfd, sec);
@@ -1016,6 +1044,9 @@ section_already_linked (abfd, sec, data)
             section.  */
          sec->output_section = bfd_abs_section_ptr;
 
+         if (flags & SEC_GROUP)
+           bfd_discard_group (abfd, sec);
+
          return;
        }
     }
@@ -1072,7 +1103,7 @@ already_linked_table_free ()
 /* Return true if the PATTERN argument is a wildcard pattern.
    Although backslashes are treated specially if a pattern contains
    wildcards, we do not consider the mere presence of a backslash to
-   be enough to cause the the pattern to be treated as a wildcard.
+   be enough to cause the pattern to be treated as a wildcard.
    That lets us handle DOS filenames more naturally.  */
 
 static boolean
@@ -1190,6 +1221,10 @@ lang_add_section (ptr, section, output, file)
          flags &= ~ (SEC_MERGE | SEC_STRINGS);
        }
 
+      /* For now make .tbss normal section.  */
+      if ((flags & SEC_THREAD_LOCAL) && ! link_info.relocateable)
+       flags |= SEC_LOAD;
+
       section->output_section->flags |= flags;
 
       if (flags & SEC_MERGE)
@@ -1458,7 +1493,7 @@ load_symbols (entry, place)
       bfd_error_type err;
       lang_statement_list_type *hold;
       boolean bad_load = true;
-      
+
       err = bfd_get_error ();
 
       /* See if the emulation has some special knowledge.  */
@@ -1480,7 +1515,7 @@ load_symbols (entry, place)
          einfo (_("%F%B: file not recognized: %E\n"), entry->the_bfd);
       else
        bad_load = false;
-      
+
       bfd_close (entry->the_bfd);
       entry->the_bfd = NULL;
 
@@ -1521,7 +1556,7 @@ load_symbols (entry, place)
     case bfd_archive:
       if (entry->whole_archive)
        {
-         bfd * member = NULL;
+         bfd *member = NULL;
          boolean loaded = true;
 
          for (;;)
@@ -1530,7 +1565,7 @@ load_symbols (entry, place)
 
              if (member == NULL)
                break;
-             
+
              if (! bfd_check_format (member, bfd_object))
                {
                  einfo (_("%F%B: member %B in archive is not an object\n"),
@@ -1586,7 +1621,7 @@ wild (s, target, output)
       if (sec->spec.name != NULL && strcmp (sec->spec.name, "COMMON") == 0)
        {
          /* Remember the section that common is going to in case we
-            later get something which doesn't know where to put it.  */ 
+            later get something which doesn't know where to put it.  */
          default_common_section = output;
        }
     }
@@ -1752,6 +1787,29 @@ get_first_input_target ()
   return target;
 }
 
+const char *
+lang_get_output_target ()
+{
+  const char *target;
+
+  /* Has the user told us which output format to use?  */
+  if (output_target != (char *) NULL)
+    return output_target;
+
+  /* No - has the current target been set to something other than
+     the default?  */
+  if (current_target != default_target)
+    return current_target;
+
+  /* No - can we determine the format of the first input file?  */
+  target = get_first_input_target ();
+  if (target != NULL)
+    return target;
+
+  /* Failed - use the default output target.  */
+  return default_target;
+}
+
 /* Open the output file.  */
 
 static bfd *
@@ -1760,24 +1818,7 @@ open_output (name)
 {
   bfd *output;
 
-  /* Has the user told us which output format to use?  */
-  if (output_target == (char *) NULL)
-    {
-      /* No - has the current target been set to something other than
-         the default?  */
-      if (current_target != default_target)
-       output_target = current_target;
-
-      /* No - can we determine the format of the first input file?  */
-      else
-       {
-         output_target = get_first_input_target ();
-
-         /* Failed - use the default output target.  */
-         if (output_target == NULL)
-           output_target = default_target;
-       }
-    }
+  output_target = lang_get_output_target ();
 
   /* Has the user requested a particular endianness on the command
      line?  */
@@ -1995,14 +2036,14 @@ lang_reasonable_defaults ()
 }
 
 /* Add the supplied name to the symbol table as an undefined reference.
-   Remove items from the chain as we open input bfds.  */
-typedef struct ldlang_undef_chain_list
-{
-  struct ldlang_undef_chain_list *next;
-  char *name;
-}                       ldlang_undef_chain_list_type;
+   This is a two step process as the symbol table doesn't even exist at
+   the time the ld command line is processed.  First we put the name
+   on a list, then, once the output file has been opened, transfer the
+   name to the symbol table.  */
+
+typedef struct bfd_sym_chain ldlang_undef_chain_list_type;
 
-static ldlang_undef_chain_list_type *ldlang_undef_chain_list_head;
+#define ldlang_undef_chain_list_head entry_symbol.next
 
 void
 ldlang_add_undef (name)
@@ -2016,6 +2057,28 @@ ldlang_add_undef (name)
   ldlang_undef_chain_list_head = new;
 
   new->name = xstrdup (name);
+
+  if (output_bfd != NULL)
+    insert_undefined (new->name);
+}
+
+/* Insert NAME as undefined in the symbol table.  */
+
+static void
+insert_undefined (name)
+     const char *name;
+{
+  struct bfd_link_hash_entry *h;
+
+  h = bfd_link_hash_lookup (link_info.hash, name, true, false, true);
+  if (h == (struct bfd_link_hash_entry *) NULL)
+    einfo (_("%P%F: bfd_link_hash_lookup failed: %E\n"));
+  if (h->type == bfd_link_hash_new)
+    {
+      h->type = bfd_link_hash_undefined;
+      h->u.undef.abfd = NULL;
+      bfd_link_add_undef (link_info.hash, h);
+    }
 }
 
 /* Run through the list of undefineds created above and place them
@@ -2031,17 +2094,7 @@ lang_place_undefineds ()
        ptr != (ldlang_undef_chain_list_type *) NULL;
        ptr = ptr->next)
     {
-      struct bfd_link_hash_entry *h;
-
-      h = bfd_link_hash_lookup (link_info.hash, ptr->name, true, false, true);
-      if (h == (struct bfd_link_hash_entry *) NULL)
-       einfo (_("%P%F: bfd_link_hash_lookup failed: %E\n"));
-      if (h->type == bfd_link_hash_new)
-       {
-         h->type = bfd_link_hash_undefined;
-         h->u.undef.abfd = NULL;
-         bfd_link_add_undef (link_info.hash, h);
-       }
+      insert_undefined (ptr->name);
     }
 }
 
@@ -2059,6 +2112,7 @@ map_input_to_output_sections (s, target, output_section_statement)
        {
        case lang_wild_statement_enum:
          wild (&s->wild_statement, target, output_section_statement);
+         break;
        case lang_constructors_statement_enum:
          map_input_to_output_sections (constructor_list.head,
                                        target,
@@ -2118,6 +2172,41 @@ map_input_to_output_sections (s, target, output_section_statement)
     }
 }
 
+/* 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.  */
+
+static void
+strip_excluded_output_sections ()
+{
+  lang_statement_union_type *u;
+
+  for (u = lang_output_section_statement.head;
+       u != NULL;
+       u = u->output_section_statement.next)
+    {
+      lang_output_section_statement_type *os;
+      asection *s;
+
+      os = &u->output_section_statement;
+      s = os->bfd_section;
+      if (s != NULL && (s->flags & SEC_EXCLUDE) != 0)
+       {
+         asection **p;
+
+         os->bfd_section = NULL;
+
+         for (p = &output_bfd->sections; *p; p = &(*p)->next)
+           if (*p == s)
+             {
+               bfd_section_list_remove (output_bfd, p);
+               output_bfd->section_count--;
+               break;
+             }
+       }
+    }
+}
+
 static void
 print_output_section_statement (output_section_statement)
      lang_output_section_statement_type *output_section_statement;
@@ -2178,7 +2267,17 @@ print_assignment (assignment, output_section)
   result = exp_fold_tree (assignment->exp->assign.src, output_section,
                          lang_final_phase_enum, print_dot, &print_dot);
   if (result.valid_p)
-    minfo ("0x%V", result.value + result.section->bfd_section->vma);
+    {
+      const char *dst;
+      bfd_vma value;
+
+      value = result.value + result.section->bfd_section->vma;
+      dst = assignment->exp->assign.dst;
+
+      minfo ("0x%V", value);
+      if (dst[0] == '.' && dst[1] == 0)
+       print_dot = value;
+    }
   else
     {
       minfo ("*undef*   ");
@@ -2297,7 +2396,12 @@ static void
 print_fill_statement (fill)
      lang_fill_statement_type *fill;
 {
-  fprintf (config.map_file, " FILL mask 0x%x\n", fill->fill);
+  size_t size;
+  unsigned char *p;
+  fputs (" FILL mask 0x", config.map_file);
+  for (p = fill->fill->data, size = fill->fill->size; size != 0; p++, size--)
+    fprintf (config.map_file, "%02x", *p);
+  fputs ("\n", config.map_file);
 }
 
 static void
@@ -2426,10 +2530,15 @@ print_padding_statement (s)
   addr = s->output_offset;
   if (s->output_section != NULL)
     addr += s->output_section->vma;
-  minfo ("0x%V %W", addr, s->size);
+  minfo ("0x%V %W ", addr, s->size);
 
-  if (s->fill != 0)
-    minfo (" %u", s->fill);
+  if (s->fill->size != 0)
+    {
+      size_t size;
+      unsigned char *p;
+      for (p = s->fill->data, size = s->fill->size; size != 0; p++, size--)
+       fprintf (config.map_file, "%02x", *p);
+    }
 
   print_nl ();
 
@@ -2462,10 +2571,10 @@ print_wild_statement (w, os)
       if (sec->spec.exclude_name_list != NULL)
        {
          name_list *tmp;
-         minfo ("EXCLUDE_FILE ( %s", sec->spec.exclude_name_list->name);
+         minfo ("EXCLUDE_FILE(%s", sec->spec.exclude_name_list->name);
          for (tmp = sec->spec.exclude_name_list->next; tmp; tmp = tmp->next)
-           minfo (", %s", tmp->name);
-         minfo (")");
+           minfo (" %s", tmp->name);
+         minfo (") ");
        }
       if (sec->spec.name != NULL)
        minfo ("%s", sec->spec.name);
@@ -2473,6 +2582,8 @@ print_wild_statement (w, os)
        minfo ("*");
       if (sec->spec.sorted)
        minfo (")");
+      if (sec->next)
+       minfo (" ");
     }
   minfo (")");
 
@@ -2620,11 +2731,12 @@ dprint_statement (s, n)
 static void
 insert_pad (ptr, fill, alignment_needed, output_section, dot)
      lang_statement_union_type **ptr;
-     fill_type fill;
+     fill_type *fill;
      unsigned int alignment_needed;
      asection *output_section;
      bfd_vma dot;
 {
+  static fill_type zero_fill = { 1, { 0 } };
   lang_statement_union_type *pad;
 
   pad = ((lang_statement_union_type *)
@@ -2645,6 +2757,8 @@ insert_pad (ptr, fill, alignment_needed, output_section, dot)
       *ptr = pad;
       pad->header.type = lang_padding_statement_enum;
       pad->padding_statement.output_section = output_section;
+      if (fill == (fill_type *) 0)
+       fill = &zero_fill;
       pad->padding_statement.fill = fill;
     }
   pad->padding_statement.output_offset = dot - output_section->vma;
@@ -2658,7 +2772,7 @@ static bfd_vma
 size_input_section (this_ptr, output_section_statement, fill, dot)
      lang_statement_union_type **this_ptr;
      lang_output_section_statement_type *output_section_statement;
-     fill_type fill;
+     fill_type *fill;
      bfd_vma dot;
 {
   lang_input_section_type *is = &((*this_ptr)->input_section);
@@ -2786,23 +2900,23 @@ os_region_check (os, region, tree, base)
   if ((region->current < region->origin
        || (region->current - region->origin > region->length))
       && ((region->current != region->origin + region->length)
-           || base == 0))
+         || base == 0))
     {
       if (tree != (etree_type *) NULL)
-        {
-          einfo (_("%X%P: address 0x%v of %B section %s is not within region %s\n"),
-                 region->current,
-                 os->bfd_section->owner,
-                 os->bfd_section->name,
-                 region->name);
-        }
+       {
+         einfo (_("%X%P: address 0x%v of %B section %s is not within region %s\n"),
+                region->current,
+                os->bfd_section->owner,
+                os->bfd_section->name,
+                region->name);
+       }
       else
-        {
-          einfo (_("%X%P: region %s is full (%B section %s)\n"),
-                 region->name,
-                 os->bfd_section->owner,
-                 os->bfd_section->name);
-        }
+       {
+         einfo (_("%X%P: region %s is full (%B section %s)\n"),
+                region->name,
+                os->bfd_section->owner,
+                os->bfd_section->name);
+       }
       /* Reset the region pointer.  */
       region->current = region->origin;
     }
@@ -2810,12 +2924,12 @@ os_region_check (os, region, tree, base)
 
 /* Set the sizes for all the output sections.  */
 
-bfd_vma
-lang_size_sections (s, output_section_statement, prev, fill, dot, relax)
+static bfd_vma
+lang_size_sections_1 (s, output_section_statement, prev, fill, dot, relax)
      lang_statement_union_type *s;
      lang_output_section_statement_type *output_section_statement;
      lang_statement_union_type **prev;
-     fill_type fill;
+     fill_type *fill;
      bfd_vma dot;
      boolean *relax;
 {
@@ -2884,6 +2998,8 @@ lang_size_sections (s, output_section_statement, prev, fill, dot, relax)
                       defined, issue a warning.  */
                    if ((bfd_get_section_flags (output_bfd, os->bfd_section)
                         & (SEC_ALLOC | SEC_LOAD)) != 0
+                       && (bfd_get_section_flags (output_bfd, os->bfd_section)
+                           & SEC_NEVER_LOAD) == 0
                        && ! link_info.relocateable
                        && strcmp (os->region->name, "*default*") == 0
                        && lang_memory_region_list != NULL
@@ -2936,24 +3052,32 @@ lang_size_sections (s, output_section_statement, prev, fill, dot, relax)
                os->bfd_section->output_offset = 0;
              }
 
-           lang_size_sections (os->children.head, os, &os->children.head,
-                               os->fill, dot, relax);
+           lang_size_sections_1 (os->children.head, os, &os->children.head,
+                                 os->fill, dot, relax);
 
            /* Put the section within the requested block size, or
               align at the block boundary.  */
-           after = ALIGN_N (os->bfd_section->vma
+           after = align_n (os->bfd_section->vma
                             + os->bfd_section->_raw_size / opb,
-                            /* The coercion here is important, see ld.h.  */
                             (bfd_vma) os->block_value);
 
            if (bfd_is_abs_section (os->bfd_section))
              ASSERT (after == os->bfd_section->vma);
+           else if ((os->bfd_section->flags & SEC_HAS_CONTENTS) == 0
+                    && (os->bfd_section->flags & SEC_THREAD_LOCAL)
+                    && ! link_info.relocateable)
+             os->bfd_section->_raw_size = 0;
            else
              os->bfd_section->_raw_size =
                (after - os->bfd_section->vma) * opb;
+
            dot = os->bfd_section->vma + os->bfd_section->_raw_size / opb;
            os->processed = true;
 
+           if (os->update_dot_tree != 0)
+             exp_fold_tree (os->update_dot_tree, abs_output_section,
+                            lang_allocating_phase_enum, dot, &dot);
+
            /* Update dot in the region ?
               We only do this if the section is going to be allocated,
               since unallocated sections do not contribute to the region's
@@ -2979,36 +3103,24 @@ lang_size_sections (s, output_section_statement, prev, fill, dot, relax)
                if (os->lma_region == NULL && os->load_base == NULL)
                  os->lma_region = os->region;
 
-               if (os->lma_region != NULL)
+               if (os->lma_region != NULL && os->lma_region != os->region)
                  {
-                   if (os->load_base != NULL)
-                     {
-                       einfo (_("%X%P: use an absolute load address or a load memory region, not both\n"));
-                     }
-                   else
-                     {
-                       /* Don't allocate twice.  */
-                       if (os->lma_region != os->region)
-                         {
-                           /* Set load_base, which will be handled later.  */
-                           os->load_base =
-                             exp_intop (os->lma_region->current);
-                           os->lma_region->current +=
-                             os->bfd_section->_raw_size / opb;
-                           os_region_check (os, os->lma_region, NULL,
-                                            os->bfd_section->lma);
-                         }
-                     }
+                   /* Set load_base, which will be handled later.  */
+                   os->load_base = exp_intop (os->lma_region->current);
+                   os->lma_region->current +=
+                     os->bfd_section->_raw_size / opb;
+                   os_region_check (os, os->lma_region, NULL,
+                                    os->bfd_section->lma);
                  }
              }
          }
          break;
 
        case lang_constructors_statement_enum:
-         dot = lang_size_sections (constructor_list.head,
-                                   output_section_statement,
-                                   &s->wild_statement.children.head,
-                                   fill, dot, relax);
+         dot = lang_size_sections_1 (constructor_list.head,
+                                     output_section_statement,
+                                     &s->wild_statement.children.head,
+                                     fill, dot, relax);
          break;
 
        case lang_data_statement_enum:
@@ -3069,10 +3181,10 @@ lang_size_sections (s, output_section_statement, prev, fill, dot, relax)
 
        case lang_wild_statement_enum:
 
-         dot = lang_size_sections (s->wild_statement.children.head,
-                                   output_section_statement,
-                                   &s->wild_statement.children.head,
-                                   fill, dot, relax);
+         dot = lang_size_sections_1 (s->wild_statement.children.head,
+                                     output_section_statement,
+                                     &s->wild_statement.children.head,
+                                     fill, dot, relax);
 
          break;
 
@@ -3156,13 +3268,21 @@ lang_size_sections (s, output_section_statement, prev, fill, dot, relax)
             padding to shrink.  If padding is needed on this pass, it
             will be added back in.  */
          s->padding_statement.size = 0;
+
+         /* Make sure output_offset is valid.  If relaxation shrinks
+            the section and this pad isn't needed, it's possible to
+            have output_offset larger than the final size of the
+            section.  bfd_set_section_contents will complain even for
+            a pad size of zero.  */
+         s->padding_statement.output_offset
+           = dot - output_section_statement->bfd_section->vma;
          break;
 
        case lang_group_statement_enum:
-         dot = lang_size_sections (s->group_statement.children.head,
-                                   output_section_statement,
-                                   &s->group_statement.children.head,
-                                   fill, dot, relax);
+         dot = lang_size_sections_1 (s->group_statement.children.head,
+                                     output_section_statement,
+                                     &s->group_statement.children.head,
+                                     fill, dot, relax);
          break;
 
        default:
@@ -3178,11 +3298,47 @@ lang_size_sections (s, output_section_statement, prev, fill, dot, relax)
   return dot;
 }
 
+bfd_vma
+lang_size_sections (s, output_section_statement, prev, fill, dot, relax)
+     lang_statement_union_type *s;
+     lang_output_section_statement_type *output_section_statement;
+     lang_statement_union_type **prev;
+     fill_type *fill;
+     bfd_vma dot;
+     boolean *relax;
+{
+  bfd_vma result;
+
+  exp_data_seg.phase = exp_dataseg_none;
+  result = lang_size_sections_1 (s, output_section_statement, prev, fill,
+                                dot, relax);
+  if (exp_data_seg.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);
+      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)
+       {
+         exp_data_seg.phase = exp_dataseg_adjust;
+         result = lang_size_sections_1 (s, output_section_statement, prev,
+                                        fill, dot, relax);
+       }
+    }
+
+  return result;
+}
+
 bfd_vma
 lang_do_assignments (s, output_section_statement, fill, dot)
      lang_statement_union_type *s;
      lang_output_section_statement_type *output_section_statement;
-     fill_type fill;
+     fill_type *fill;
      bfd_vma dot;
 {
   unsigned opb = bfd_arch_mach_octets_per_byte (ldfile_output_architecture,
@@ -3251,8 +3407,8 @@ lang_do_assignments (s, output_section_statement, fill, dot)
            if (value.valid_p == false)
              einfo (_("%F%P: invalid data statement\n"));
          }
-          {
-            unsigned int size;
+         {
+           unsigned int size;
            switch (s->data_statement.type)
              {
              default:
@@ -3376,9 +3532,9 @@ lang_set_startof ()
       h = bfd_link_hash_lookup (link_info.hash, buf, false, false, true);
       if (h != NULL && h->type == bfd_link_hash_undefined)
        {
-          unsigned opb;
+         unsigned opb;
 
-          opb = bfd_arch_mach_octets_per_byte (ldfile_output_architecture,
+         opb = bfd_arch_mach_octets_per_byte (ldfile_output_architecture,
                                               ldfile_output_machine);
          h->type = bfd_link_hash_defined;
          if (s->_cooked_size != 0)
@@ -3403,15 +3559,16 @@ lang_finish ()
   else
     warn = true;
 
-  if (entry_symbol == (char *) NULL)
+  if (entry_symbol.name == (const char *) NULL)
     {
       /* No entry has been specified.  Look for start, but don't warn
         if we don't find it.  */
-      entry_symbol = "start";
+      entry_symbol.name = "start";
       warn = false;
     }
 
-  h = bfd_link_hash_lookup (link_info.hash, entry_symbol, false, false, true);
+  h = bfd_link_hash_lookup (link_info.hash, entry_symbol.name,
+                           false, false, true);
   if (h != (struct bfd_link_hash_entry *) NULL
       && (h->type == bfd_link_hash_defined
          || h->type == bfd_link_hash_defweak)
@@ -3424,7 +3581,7 @@ lang_finish ()
                                    h->u.def.section->output_section)
             + h->u.def.section->output_offset);
       if (! bfd_set_start_address (output_bfd, val))
-       einfo (_("%P%F:%s: can't set start address\n"), entry_symbol);
+       einfo (_("%P%F:%s: can't set start address\n"), entry_symbol.name);
     }
   else
     {
@@ -3433,7 +3590,7 @@ lang_finish ()
 
       /* We couldn't find the entry symbol.  Try parsing it as a
          number.  */
-      val = bfd_scan_vma (entry_symbol, &send, 0);
+      val = bfd_scan_vma (entry_symbol.name, &send, 0);
       if (*send == '\0')
        {
          if (! bfd_set_start_address (output_bfd, val))
@@ -3445,12 +3602,13 @@ lang_finish ()
 
          /* Can't find the entry symbol, and it's not a number.  Use
             the first address in the text section.  */
-         ts = bfd_get_section_by_name (output_bfd, ".text");
+         ts = bfd_get_section_by_name (output_bfd, entry_section);
          if (ts != (asection *) NULL)
            {
              if (warn)
                einfo (_("%P: warning: cannot find entry symbol %s; defaulting to %V\n"),
-                      entry_symbol, bfd_get_section_vma (output_bfd, ts));
+                      entry_symbol.name,
+                      bfd_get_section_vma (output_bfd, ts));
              if (! bfd_set_start_address (output_bfd,
                                           bfd_get_section_vma (output_bfd,
                                                                ts)))
@@ -3460,7 +3618,7 @@ lang_finish ()
            {
              if (warn)
                einfo (_("%P: warning: cannot find entry symbol %s; not setting start address\n"),
-                      entry_symbol);
+                      entry_symbol.name);
            }
        }
     }
@@ -3496,8 +3654,25 @@ lang_check ()
        file = file->input_statement.next)
     {
       input_bfd = file->input_statement.the_bfd;
-      compatible = bfd_arch_get_compatible (input_bfd,
-                                           output_bfd);
+      compatible = bfd_arch_get_compatible (input_bfd, output_bfd);
+
+      /* In general it is not possible to perform a relocatable
+        link between differing object formats when the input
+        file has relocations, because the relocations in the
+        input format may not have equivalent representations in
+        the output format (and besides BFD does not translate
+        relocs for other link purposes than a final link).  */
+      if ((link_info.relocateable || link_info.emitrelocations)
+         && (compatible == NULL
+             || bfd_get_flavour (input_bfd) != bfd_get_flavour (output_bfd))
+         && (bfd_get_file_flags (input_bfd) & HAS_RELOC) != 0)
+       {
+         einfo (_("%P%F: Relocatable linking with relocations from format %s (%B) to format %s (%B) is not supported\n"),
+                bfd_get_target (input_bfd), input_bfd,
+                bfd_get_target (output_bfd), output_bfd);
+         /* einfo with %F exits.  */
+       }
+
       if (compatible == NULL)
        {
          if (command_line.warn_mismatch)
@@ -3505,22 +3680,10 @@ lang_check ()
                   bfd_printable_name (input_bfd), input_bfd,
                   bfd_printable_name (output_bfd));
        }
-      else if (link_info.relocateable
-              /* In general it is not possible to perform a relocatable
-                 link between differing object formats when the input
-                 file has relocations, because the relocations in the
-                 input format may not have equivalent representations in
-                 the output format (and besides BFD does not translate
-                 relocs for other link purposes than a final link).  */
-              && bfd_get_flavour (input_bfd) != bfd_get_flavour (output_bfd)
-              && (bfd_get_file_flags (input_bfd) & HAS_RELOC) != 0)
-       einfo (_("%P%F: Relocatable linking with relocations from format %s (%B) to format %s (%B) is not supported\n"),
-              bfd_get_target (input_bfd), input_bfd,
-              bfd_get_target (output_bfd), output_bfd);
       else if (bfd_count_sections (input_bfd))
        {
          /* If the input bfd has no contents, it shouldn't set the
-            private data of the output bfd. */
+            private data of the output bfd.  */
 
          bfd_error_handler_type pfn = NULL;
 
@@ -3594,8 +3757,8 @@ lang_one_common (h, info)
   section = h->u.c.p->section;
 
   /* Increase the size of the section.  */
-  section->_cooked_size = ALIGN_N ((section->_cooked_size + opb - 1) / opb,
-                                  (bfd_size_type) (1 << power_of_two)) * opb;
+  section->_cooked_size = align_n ((section->_cooked_size + opb - 1) / opb,
+                                  (bfd_vma) 1 << power_of_two) * opb;
 
   /* Adjust the alignment if necessary.  */
   if (power_of_two > section->alignment_power)
@@ -3686,11 +3849,7 @@ lang_place_orphans ()
 
              if (file->just_syms_flag)
                {
-                 /* We are only retrieving symbol values from this
-                     file.  We want the symbols to act as though the
-                     values in the file are absolute.  */
-                 s->output_section = bfd_abs_section_ptr;
-                 s->output_offset = s->vma;
+                 abort ();
                }
              else if (strcmp (s->name, "COMMON") == 0)
                {
@@ -3951,8 +4110,8 @@ lang_final ()
 
 /* Reset the current counters in the regions.  */
 
-static void
-reset_memory_regions ()
+void
+lang_reset_memory_regions ()
 {
   lang_memory_region_type *p = lang_memory_region_list;
   asection *o;
@@ -4005,6 +4164,7 @@ lang_gc_sections_1 (s)
        {
        case lang_wild_statement_enum:
          lang_gc_wild (&s->wild_statement);
+         break;
        case lang_constructors_statement_enum:
          lang_gc_sections_1 (constructor_list.head);
          break;
@@ -4024,25 +4184,16 @@ static void
 lang_gc_sections ()
 {
   struct bfd_link_hash_entry *h;
-  ldlang_undef_chain_list_type *ulist, fake_list_start;
+  ldlang_undef_chain_list_type *ulist;
 
   /* Keep all sections so marked in the link script.  */
 
   lang_gc_sections_1 (statement_list.head);
 
-  /* Keep all sections containing symbols undefined on the command-line.
-     Handle the entry symbol at the same time.  */
+  /* Keep all sections containing symbols undefined on the command-line,
+     and the section containing the entry symbol.  */
 
-  if (entry_symbol != NULL)
-    {
-      fake_list_start.next = ldlang_undef_chain_list_head;
-      fake_list_start.name = (char *) entry_symbol;
-      ulist = &fake_list_start;
-    }
-  else
-    ulist = ldlang_undef_chain_list_head;
-
-  for (; ulist; ulist = ulist->next)
+  for (ulist = link_info.gc_sym_list; ulist; ulist = ulist->next)
     {
       h = bfd_link_hash_lookup (link_info.hash, ulist->name,
                                false, false, false);
@@ -4079,6 +4230,10 @@ lang_process ()
   current_target = default_target;
   open_input_bfds (statement_list.head, false);
 
+  link_info.gc_sym_list = &entry_symbol;
+  if (entry_symbol.name == NULL)
+    link_info.gc_sym_list = ldlang_undef_chain_list_head;
+
   ldemul_after_open ();
 
   already_linked_table_free ();
@@ -4119,8 +4274,27 @@ lang_process ()
   /* Find any sections not attached explicitly and handle them.  */
   lang_place_orphans ();
 
+  if (! link_info.relocateable)
+    {
+      /* Look for a text section and set the readonly attribute in it.  */
+      asection *found = bfd_get_section_by_name (output_bfd, ".text");
+
+      if (found != (asection *) NULL)
+       {
+         if (config.text_read_only)
+           found->flags |= SEC_READONLY;
+         else
+           found->flags &= ~SEC_READONLY;
+       }
+    }
+
+  /* Do anything special before sizing sections.  This is where ELF
+     and other back-ends size dynamic sections.  */
   ldemul_before_allocation ();
 
+  if (!link_info.relocateable)
+    strip_excluded_output_sections ();
+
   /* We must record the program headers before we try to fix the
      section positions, since they will affect SIZEOF_HEADERS.  */
   lang_record_phdrs ();
@@ -4138,7 +4312,7 @@ lang_process ()
 
       do
        {
-         reset_memory_regions ();
+         lang_reset_memory_regions ();
 
          relax_again = false;
 
@@ -4150,13 +4324,13 @@ lang_process ()
             section sizes.  */
          lang_do_assignments (statement_list.head,
                               abs_output_section,
-                              (fill_type) 0, (bfd_vma) 0);
+                              (fill_type *) 0, (bfd_vma) 0);
 
          /* Perform another relax pass - this time we know where the
-            globals are, so can make better guess.  */
+            globals are, so can make better guess.  */
          lang_size_sections (statement_list.head,
                              abs_output_section,
-                             &(statement_list.head), 0, (bfd_vma) 0,
+                             &statement_list.head, 0, (bfd_vma) 0,
                              &relax_again);
        }
       while (relax_again);
@@ -4174,7 +4348,7 @@ lang_process ()
 
   lang_do_assignments (statement_list.head,
                       abs_output_section,
-                      (fill_type) 0, (bfd_vma) 0);
+                      (fill_type *) 0, (bfd_vma) 0);
 
   /* Make sure that the section addresses make sense.  */
   if (! link_info.relocateable
@@ -4253,11 +4427,11 @@ lang_add_entry (name, cmdline)
      const char *name;
      boolean cmdline;
 {
-  if (entry_symbol == NULL
+  if (entry_symbol.name == NULL
       || cmdline
       || ! entry_from_cmdline)
     {
-      entry_symbol = name;
+      entry_symbol.name = name;
       entry_from_cmdline = cmdline;
     }
 }
@@ -4290,13 +4464,13 @@ lang_add_map (name)
 }
 
 void
-lang_add_fill (exp)
-     int exp;
+lang_add_fill (fill)
+     fill_type *fill;
 {
   lang_fill_statement_type *new = new_stat (lang_fill_statement,
                                            stat_ptr);
 
-  new->fill = exp;
+  new->fill = fill;
 }
 
 void
@@ -4381,23 +4555,48 @@ lang_float (maybe)
   lang_float_flag = maybe;
 }
 
+
+/* Work out the load- and run-time regions from a script statement, and
+   store them in *LMA_REGION and *REGION respectively.
+
+   MEMSPEC is the name of the run-time region, or "*default*" if the
+   statement didn't specify one.  LMA_MEMSPEC is the name of the
+   load-time region, or null if the statement didn't specify one.
+   HAVE_LMA_P is true if the statement had an explicit load address.
+
+   It is an error to specify both a load region and a load address.  */
+
+static void
+lang_get_regions (region, lma_region, memspec, lma_memspec, have_lma_p)
+     struct memory_region_struct **region, **lma_region;
+     const char *memspec, *lma_memspec;
+     int have_lma_p;
+{
+  *lma_region = lang_memory_region_lookup (lma_memspec);
+
+  /* If no runtime region has been given, but the load region has
+     been, use the load region.  */
+  if (lma_memspec != 0 && strcmp (memspec, "*default*") == 0)
+    *region = *lma_region;
+  else
+    *region = lang_memory_region_lookup (memspec);
+
+  if (have_lma_p && lma_memspec != 0)
+    einfo (_("%X%P:%S: section has both a load address and a load region\n"));
+}
+
 void
 lang_leave_output_section_statement (fill, memspec, phdrs, lma_memspec)
-     bfd_vma fill;
+     fill_type *fill;
      const char *memspec;
      struct lang_output_section_phdr_list *phdrs;
      const char *lma_memspec;
 {
+  lang_get_regions (&current_section->region,
+                   &current_section->lma_region,
+                   memspec, lma_memspec,
+                   current_section->load_base != 0);
   current_section->fill = fill;
-  current_section->region = lang_memory_region_lookup (memspec);
-  if (strcmp (lma_memspec, "*default*") != 0)
-    {
-      current_section->lma_region = lang_memory_region_lookup (lma_memspec);
-      /* If no runtime region has been given, but the load region has
-         been, use the load region.  */
-      if (strcmp (memspec, "*default*") == 0)
-        current_section->region = lang_memory_region_lookup (lma_memspec);
-    }
   current_section->phdrs = phdrs;
   stat_ptr = &statement_list;
 }
@@ -4679,12 +4878,6 @@ lang_add_nocrossref (l)
 /* The overlay virtual address.  */
 static etree_type *overlay_vma;
 
-/* The overlay load address.  */
-static etree_type *overlay_lma;
-
-/* Whether nocrossrefs is set for this overlay.  */
-static int overlay_nocrossrefs;
-
 /* An expression for the maximum section size seen so far.  */
 static etree_type *overlay_max;
 
@@ -4700,24 +4893,18 @@ static struct overlay_list *overlay_list;
 /* Start handling an overlay.  */
 
 void
-lang_enter_overlay (vma_expr, lma_expr, nocrossrefs)
+lang_enter_overlay (vma_expr)
      etree_type *vma_expr;
-     etree_type *lma_expr;
-     int nocrossrefs;
 {
   /* The grammar should prevent nested overlays from occurring.  */
-  ASSERT (overlay_vma == NULL
-         && overlay_lma == NULL
-         && overlay_list == NULL
-         && overlay_max == NULL);
+  ASSERT (overlay_vma == NULL && overlay_max == NULL);
 
   overlay_vma = vma_expr;
-  overlay_lma = lma_expr;
-  overlay_nocrossrefs = nocrossrefs;
 }
 
 /* Start a section in an overlay.  We handle this by calling
-   lang_enter_output_section_statement with the correct VMA and LMA.  */
+   lang_enter_output_section_statement with the correct VMA.
+   lang_leave_overlay sets up the LMA and memory regions.  */
 
 void
 lang_enter_overlay_section (name)
@@ -4727,16 +4914,13 @@ lang_enter_overlay_section (name)
   etree_type *size;
 
   lang_enter_output_section_statement (name, overlay_vma, normal_section,
-                                      0, 0, 0, overlay_lma);
+                                      0, 0, 0, 0);
 
-  /* If this is the first section, then base the VMA and LMA of future
+  /* If this is the first section, then base the VMA of future
      sections on this one.  This will work correctly even if `.' is
      used in the addresses.  */
   if (overlay_list == NULL)
-    {
-      overlay_vma = exp_nameop (ADDR, name);
-      overlay_lma = exp_nameop (LOADADDR, name);
-    }
+    overlay_vma = exp_nameop (ADDR, name);
 
   /* Remember the section.  */
   n = (struct overlay_list *) xmalloc (sizeof *n);
@@ -4746,9 +4930,6 @@ lang_enter_overlay_section (name)
 
   size = exp_nameop (SIZEOF, name);
 
-  /* Adjust the LMA for the next section.  */
-  overlay_lma = exp_binop ('+', overlay_lma, size);
-
   /* Arrange to work out the maximum section end address.  */
   if (overlay_max == NULL)
     overlay_max = size;
@@ -4761,7 +4942,7 @@ lang_enter_overlay_section (name)
 
 void
 lang_leave_overlay_section (fill, phdrs)
-     bfd_vma fill;
+     fill_type *fill;
      struct lang_output_section_phdr_list *phdrs;
 {
   const char *name;
@@ -4771,8 +4952,10 @@ lang_leave_overlay_section (fill, phdrs)
 
   name = current_section->name;
 
-  lang_leave_output_section_statement (fill, "*default*",
-                                       phdrs, "*default*");
+  /* For now, assume that "*default*" is the run-time memory region and
+     that no load-time region has been specified.  It doesn't really
+     matter what we say here, since lang_leave_overlay will override it.  */
+  lang_leave_output_section_statement (fill, "*default*", phdrs, 0);
 
   /* Define the magic symbols.  */
 
@@ -4802,62 +4985,57 @@ lang_leave_overlay_section (fill, phdrs)
    looks through all the sections in the overlay and sets them.  */
 
 void
-lang_leave_overlay (fill, memspec, phdrs, lma_memspec)
-     bfd_vma fill;
+lang_leave_overlay (lma_expr, nocrossrefs, fill, memspec, phdrs, lma_memspec)
+     etree_type *lma_expr;
+     int nocrossrefs;
+     fill_type *fill;
      const char *memspec;
      struct lang_output_section_phdr_list *phdrs;
      const char *lma_memspec;
 {
   lang_memory_region_type *region;
-  lang_memory_region_type * default_region;
   lang_memory_region_type *lma_region;
   struct overlay_list *l;
   struct lang_nocrossref *nocrossref;
 
-  default_region = lang_memory_region_lookup ("*default*");
-
-  if (memspec == NULL)
-    region = NULL;
-  else
-    region = lang_memory_region_lookup (memspec);
-
-  if (lma_memspec == NULL)
-    lma_region = NULL;
-  else
-    lma_region = lang_memory_region_lookup (lma_memspec);
+  lang_get_regions (&region, &lma_region,
+                   memspec, lma_memspec,
+                   lma_expr != 0);
 
   nocrossref = NULL;
 
+  /* After setting the size of the last section, set '.' to end of the
+     overlay region.  */
+  if (overlay_list != NULL)
+    overlay_list->os->update_dot_tree
+      = exp_assop ('=', ".", exp_binop ('+', overlay_vma, overlay_max));
+
   l = overlay_list;
   while (l != NULL)
     {
       struct overlay_list *next;
 
-      if (fill != 0 && l->os->fill == 0)
+      if (fill != (fill_type *) 0 && l->os->fill == (fill_type *) 0)
        l->os->fill = fill;
 
-      /* Assign a region to the sections, if one has been specified.
-        Override the assignment of the default section, but not
-        other sections.  */
-      if (region != NULL &&
-         (l->os->region == NULL ||
-          l->os->region == default_region))
-       l->os->region = region;
-
-      /* We only set lma_region for the first overlay section, as
-        subsequent overlay sections will have load_base set relative
-        to the first section.  Also, don't set lma_region if
-        load_base is specified.  FIXME:  There should really be a test
-        that `AT ( LDADDR )' doesn't conflict with `AT >LMA_REGION'
-        rather than letting LDADDR simply override LMA_REGION.  */
-      if (lma_region != NULL && l->os->lma_region == NULL
-         && l->next == NULL && l->os->load_base == NULL)
-       l->os->lma_region = lma_region;
+      l->os->region = region;
+      l->os->lma_region = lma_region;
+
+      /* The first section has the load address specified in the
+        OVERLAY statement.  The rest are worked out from that.
+        The base address is not needed (and should be null) if
+        an LMA region was specified.  */
+      if (l->next == 0)
+       l->os->load_base = lma_expr;
+      else if (lma_region == 0)
+       l->os->load_base = exp_binop ('+',
+                                     exp_nameop (LOADADDR, l->next->os->name),
+                                     exp_nameop (SIZEOF, l->next->os->name));
 
       if (phdrs != NULL && l->os->phdrs == NULL)
        l->os->phdrs = phdrs;
 
-      if (overlay_nocrossrefs)
+      if (nocrossrefs)
        {
          struct lang_nocrossref *nc;
 
@@ -4875,13 +5053,7 @@ lang_leave_overlay (fill, memspec, phdrs, lma_memspec)
   if (nocrossref != NULL)
     lang_add_nocrossref (nocrossref);
 
-  /* Update . for the end of the overlay.  */
-  lang_add_assignment (exp_assop ('=', ".",
-                                 exp_binop ('+', overlay_vma, overlay_max)));
-
   overlay_vma = NULL;
-  overlay_lma = NULL;
-  overlay_nocrossrefs = 0;
   overlay_list = NULL;
   overlay_max = NULL;
 }
@@ -4959,7 +5131,7 @@ lang_vers_match_lang_java (expr, sym)
 /* This is called for each variable name or match expression.  */
 
 struct bfd_elf_version_expr *
-lang_new_vers_regex (orig, new, lang)
+lang_new_vers_pattern (orig, new, lang)
      struct bfd_elf_version_expr *orig;
      const char *new;
      const char *lang;
@@ -4969,6 +5141,8 @@ lang_new_vers_regex (orig, new, lang)
   ret = (struct bfd_elf_version_expr *) xmalloc (sizeof *ret);
   ret->next = orig;
   ret->pattern = new;
+  ret->symver = 0;
+  ret->script = 0;
 
   if (lang == NULL || strcasecmp (lang, "C") == 0)
     ret->match = lang_vers_match_lang_c;
@@ -4983,7 +5157,7 @@ lang_new_vers_regex (orig, new, lang)
       ret->match = lang_vers_match_lang_c;
     }
 
-  return ret;
+  return ldemul_new_vers_pattern (ret);
 }
 
 /* This is called for each set of variable names and match
@@ -5024,6 +5198,16 @@ lang_register_vers_node (name, version, deps)
   struct bfd_elf_version_tree *t, **pp;
   struct bfd_elf_version_expr *e1;
 
+  if (name == NULL)
+    name = "";
+
+  if ((name[0] == '\0' && lang_elf_version_info != NULL)
+      || (lang_elf_version_info && lang_elf_version_info->name[0] == '\0'))
+    {
+      einfo (_("%X%P: anonymous version tag cannot be combined with other version tags\n"));
+      return;
+    }
+
   /* Make sure this node has a unique name.  */
   for (t = lang_elf_version_info; t != NULL; t = t->next)
     if (strcmp (t->name, name) == 0)
@@ -5060,8 +5244,13 @@ lang_register_vers_node (name, version, deps)
 
   version->deps = deps;
   version->name = name;
-  ++version_index;
-  version->vernum = version_index;
+  if (name[0] != '\0')
+    {
+      ++version_index;
+      version->vernum = version_index;
+    }
+  else
+    version->vernum = 0;
 
   for (pp = &lang_elf_version_info; *pp != NULL; pp = &(*pp)->next)
     ;
@@ -5107,7 +5296,7 @@ lang_do_version_exports_section ()
       bfd_size_type len;
 
       if (sec == NULL)
-        continue;
+       continue;
 
       len = bfd_section_size (is->the_bfd, sec);
       contents = xmalloc (len);
@@ -5117,7 +5306,7 @@ lang_do_version_exports_section ()
       p = contents;
       while (p < contents + len)
        {
-         greg = lang_new_vers_regex (greg, p, NULL);
+         greg = lang_new_vers_pattern (greg, p, NULL);
          p = strchr (p, '\0') + 1;
        }
 
@@ -5128,7 +5317,7 @@ lang_do_version_exports_section ()
        bfd_get_section_flags (is->the_bfd, sec) | SEC_EXCLUDE);
     }
 
-  lreg = lang_new_vers_regex (NULL, "*", NULL);
+  lreg = lang_new_vers_pattern (NULL, "*", NULL);
   lang_register_vers_node (command_line.version_exports_section,
                           lang_new_vers_node (greg, lreg), NULL);
 }
This page took 0.0424 seconds and 4 git commands to generate.