* lexsup.c (parse_args): Add support for new options -( -) with
[binutils-gdb.git] / ld / ldlang.c
index 71a03888486d420dd944cfc2f7af9db493dddfb9..6a4ab5fffb976309b32a744013c4d8b9af1c769a 100644 (file)
@@ -1,5 +1,5 @@
 /* Linker command language support.
-   Copyright 1991, 1992, 1993 Free Software Foundation, Inc.
+   Copyright (C) 1991, 92, 93, 94 Free Software Foundation, Inc.
 
 This file is part of GLD, the Gnu Linker.
 
@@ -19,6 +19,7 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
 
 #include "bfd.h"
 #include "sysdep.h"
+#include "libiberty.h"
 #include "bfdlink.h"
 
 #include "ld.h"
@@ -44,15 +45,10 @@ static lang_statement_union_type *new_statement PARAMS ((enum statement_enum,
 /* LOCALS */
 static struct obstack stat_obstack;
 
-#define obstack_chunk_alloc ldmalloc
+#define obstack_chunk_alloc xmalloc
 #define obstack_chunk_free free
 static CONST char *startup_file;
 static lang_statement_list_type input_file_chain;
-
-/* Points to the last statement in the .data section, so we can add
-   stuff to the data section without pain */
-static lang_statement_list_type end_of_data_section_statement_list;
-
 static boolean placed_commons = false;
 static lang_output_section_statement_type *default_common_section;
 static boolean map_option_f;
@@ -73,20 +69,19 @@ static void lang_for_each_statement_worker
           lang_statement_union_type *s));
 static lang_input_statement_type *new_afile
   PARAMS ((const char *name, lang_input_file_enum_type file_type,
-          const char *target));
+          const char *target, boolean add_to_list));
 static void print_flags PARAMS ((int *ignore_flags));
 static void init_os PARAMS ((lang_output_section_statement_type *s));
 static void wild_doit PARAMS ((lang_statement_list_type *ptr,
                               asection *section,
                               lang_output_section_statement_type *output,
                               lang_input_statement_type *file));
-static asection *our_bfd_get_section_by_name PARAMS ((bfd *abfd,
-                                                     const char *section));
 static void wild_section PARAMS ((lang_wild_statement_type *ptr,
                                  const char *section,
                                  lang_input_statement_type *file,
                                  lang_output_section_statement_type *output));
 static lang_input_statement_type *lookup_name PARAMS ((const char *name));
+static void load_symbols PARAMS ((lang_input_statement_type *entry));
 static void wild PARAMS ((lang_wild_statement_type *s,
                          const char *section, const char *file,
                          const char *target,
@@ -96,7 +91,6 @@ static void ldlang_open_output PARAMS ((lang_statement_union_type *statement));
 static void open_input_bfds PARAMS ((lang_statement_union_type *statement));
 static void lang_reasonable_defaults PARAMS ((void));
 static void lang_place_undefineds PARAMS ((void));
-static void lang_create_output_section_statements PARAMS ((void));
 static void map_input_to_output_sections
   PARAMS ((lang_statement_union_type *s,
           const char *target,
@@ -107,10 +101,10 @@ static void print_assignment
   PARAMS ((lang_assignment_statement_type *assignment,
           lang_output_section_statement_type *output_section));
 static void print_input_statement PARAMS ((lang_input_statement_type *statm));
-static void print_symbol PARAMS ((asymbol *q));
 static void print_input_section PARAMS ((lang_input_section_type *in));
 static void print_fill_statement PARAMS ((lang_fill_statement_type *fill));
 static void print_data_statement PARAMS ((lang_data_statement_type *data));
+static void print_reloc_statement PARAMS ((lang_reloc_statement_type *reloc));
 static void print_padding_statement PARAMS ((lang_padding_statement_type *s));
 static void print_wild_statement
   PARAMS ((lang_wild_statement_type *w,
@@ -126,11 +120,6 @@ static bfd_vma size_input_section
   PARAMS ((lang_statement_union_type **this_ptr,
           lang_output_section_statement_type *output_section_statement,
           fill_type fill, bfd_vma dot, boolean relax));
-static bfd_vma lang_size_sections
-  PARAMS ((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));
 static bfd_vma lang_do_assignments
   PARAMS ((lang_statement_union_type * s,
           lang_output_section_statement_type *output_section_statement,
@@ -147,10 +136,8 @@ static void reset_memory_regions PARAMS ((void));
 /* EXPORTS */
 lang_output_section_statement_type *abs_output_section;
 lang_statement_list_type *stat_ptr = &statement_list;
-lang_statement_list_type file_chain =
-{0};
-CONST char *entry_symbol = 0;
-bfd_size_type largest_section = 0;
+lang_statement_list_type file_chain = { 0 };
+static const char *entry_symbol = 0;
 boolean lang_has_input_file = false;
 boolean had_output_filename = false;
 boolean lang_float_flag = false;
@@ -159,7 +146,7 @@ boolean delete_output_file_on_failure = false;
 etree_type *base; /* Relocation base - or null */
 
 
-#ifdef __STDC__
+#if defined(__STDC__) || defined(ALMOST_STDC)
 #define cat(a,b) a##b
 #else
 #define cat(a,b) a/**/b
@@ -236,6 +223,7 @@ lang_for_each_statement_worker (func, s)
             s->wild_statement.children.head);
          break;
        case lang_data_statement_enum:
+       case lang_reloc_statement_enum:
        case lang_object_symbols_statement_enum:
        case lang_output_statement_enum:
        case lang_target_statement_enum:
@@ -303,14 +291,22 @@ new_statement (type, size, list)
 
  */
 static lang_input_statement_type *
-new_afile (name, file_type, target)
+new_afile (name, file_type, target, add_to_list)
      CONST char *name;
      lang_input_file_enum_type file_type;
      CONST char *target;
+     boolean add_to_list;
 {
+  lang_input_statement_type *p;
 
-  lang_input_statement_type *p = new_stat (lang_input_statement,
-                                          stat_ptr);
+  if (add_to_list)
+    p = new_stat (lang_input_statement, stat_ptr);
+  else
+    {
+      p = ((lang_input_statement_type *)
+          stat_alloc (sizeof (lang_input_statement_type)));
+      p->header.next = NULL;
+    }
 
   lang_has_input_file = true;
   p->target = target;
@@ -337,12 +333,19 @@ new_afile (name, file_type, target)
       p->is_archive = true;
       p->filename = name;
       p->real = true;
-      p->local_sym_name = concat ("-l", name, "");
+      p->local_sym_name = concat ("-l", name, (const char *) NULL);
       p->just_syms_flag = false;
       p->search_dirs_flag = true;
       break;
-    case lang_input_file_is_search_file_enum:
     case lang_input_file_is_marker_enum:
+      p->filename = name;
+      p->is_archive = false;
+      p->real = false;
+      p->local_sym_name = name;
+      p->just_syms_flag = false;
+      p->search_dirs_flag = true;
+      break;
+    case lang_input_file_is_search_file_enum:
       p->filename = name;
       p->is_archive = false;
       p->real = true;
@@ -361,8 +364,8 @@ new_afile (name, file_type, target)
     default:
       FAIL ();
     }
+  p->the_bfd = (bfd *) NULL;
   p->asymbols = (asymbol **) NULL;
-  p->superfile = (lang_input_statement_type *) NULL;
   p->next_real_file = (lang_statement_union_type *) NULL;
   p->next = (lang_statement_union_type *) NULL;
   p->symbol_count = 0;
@@ -380,26 +383,8 @@ lang_add_input_file (name, file_type, target)
      lang_input_file_enum_type file_type;
      CONST char *target;
 {
-  /* Look it up or build a new one */
   lang_has_input_file = true;
-
-#if 0
-  lang_input_statement_type *p;
-
-  for (p = (lang_input_statement_type *) input_file_chain.head;
-       p != (lang_input_statement_type *) NULL;
-       p = (lang_input_statement_type *) (p->next_real_file))
-    {
-      /* Sometimes we have incomplete entries in here */
-      if (p->filename != (char *) NULL)
-       {
-         if (strcmp (name, p->filename) == 0)
-           return p;
-       }
-
-    }
-#endif
-  return new_afile (name, file_type, target);
+  return new_afile (name, file_type, target, true);
 }
 
 /* Build enough state so that the parser can build its tree */
@@ -420,7 +405,7 @@ lang_init ()
                                    (char *) NULL);
   abs_output_section = lang_output_section_statement_lookup (BFD_ABS_SECTION_NAME);
 
-  abs_output_section->bfd_section = &bfd_abs_section;
+  abs_output_section->bfd_section = bfd_abs_section_ptr;
 
 }
 
@@ -649,18 +634,7 @@ wild_doit (ptr, section, output, file)
      lang_input_statement_type * file;
 {
   if (output->bfd_section == (asection *) NULL)
-  {
     init_os (output);
-    /* Initialize the vma and size to the existing section.  This will
-       be overriden in lang_size_sections unless SEC_NEVER_LOAD gets
-       set.  */
-    if (section != (asection *) NULL)
-    {
-      bfd_set_section_vma (0, output->bfd_section,
-                          bfd_section_vma (0, section));
-      output->bfd_section->_raw_size = section->_raw_size;
-    }
-  }
 
   if (section != (asection *) NULL
       && section->output_section == (asection *) NULL)
@@ -672,14 +646,14 @@ wild_doit (ptr, section, output, file)
     new->ifile = file;
     section->output_section = output->bfd_section;
 
-    /* Be selective about what the output section inherits from the
-       input section */
-
-    if ((section->flags & SEC_SHARED_LIBRARY) != 0)
-      section->output_section->flags |= section->flags;
-    else
-      section->output_section->flags |=
-       section->flags & (flagword) (~ SEC_NEVER_LOAD);
+    /* We don't copy the SEC_NEVER_LOAD flag from an input section to
+       an output section, because we want to be able to include a
+       SEC_NEVER_LOAD section in the middle of an otherwise loaded
+       section (I don't know why we want to do this, but we do).
+       build_link_order in ldwrite.c handles this case by turning the
+       embedded SEC_NEVER_LOAD section into a fill.  */
+    section->output_section->flags |=
+      section->flags & (flagword) (~ SEC_NEVER_LOAD);
 
     if (!output->loadable) 
     {
@@ -699,14 +673,6 @@ wild_doit (ptr, section, output, file)
   }
 }
 
-static asection *
-our_bfd_get_section_by_name (abfd, section)
-     bfd * abfd;
-     CONST char *section;
-{
-  return bfd_get_section_by_name (abfd, section);
-}
-
 static void
 wild_section (ptr, section, file, output)
      lang_wild_statement_type * ptr;
@@ -721,21 +687,21 @@ wild_section (ptr, section, file, output)
       if (section == (char *) NULL)
        {
          /* Do the creation to all sections in the file */
-         for (s = file->the_bfd->sections; s != (asection *) NULL; s = s->next)
-         {
-           /* except for bss */
-           if ((s->flags & SEC_IS_COMMON)  == 0)
+         for (s = file->the_bfd->sections; s != NULL; s = s->next)
            {
-             wild_doit (&ptr->children, s, output, file);
+             /* except for bss */
+             if ((s->flags & SEC_IS_COMMON)  == 0)
+               {
+                 wild_doit (&ptr->children, s, output, file);
+               }
            }
-         }
        }
       else
        {
          /* Do the creation to the named section only */
-         wild_doit (&ptr->children,
-                    our_bfd_get_section_by_name (file->the_bfd, section),
-                    output, file);
+         s = bfd_get_section_by_name (file->the_bfd, section);
+         if (s != NULL)
+           wild_doit (&ptr->children, s, output, file);
        }
     }
 }
@@ -748,8 +714,7 @@ wild_section (ptr, section, file, output)
    not define anything we need at the time, they won't have all their
    symbols read. If we need them later, we'll have to redo it.
    */
-static
-lang_input_statement_type *
+static lang_input_statement_type *
 lookup_name (name)
      CONST char *name;
 {
@@ -768,12 +733,8 @@ lookup_name (name)
     }
 
   if (search == (lang_input_statement_type *) NULL)
-    {
-      /* There isn't an afile entry for this file yet, this must be
-        because the name has only appeared inside a load script and
-        not on the command line */
-      search = new_afile (name, lang_input_file_is_file_enum, default_target);
-    }
+    search = new_afile (name, lang_input_file_is_file_enum, default_target,
+                       false);
 
   /* If we have already added this file, or this file is not real
      (FIXME: can that ever actually happen?) or the name is NULL
@@ -783,29 +744,41 @@ lookup_name (name)
       || search->filename == (const char *) NULL)
     return search;
 
-  ldfile_open_file (search);
+  load_symbols (search);
+
+  return search;
+}
+
+/* Get the symbols for an input file.  */
+
+static void
+load_symbols (entry)
+     lang_input_statement_type *entry;
+{
+  if (entry->loaded)
+    return;
+
+  ldfile_open_file (entry);
 
-  if (bfd_check_format (search->the_bfd, bfd_object))
+  if (bfd_check_format (entry->the_bfd, bfd_object))
     {
-      ldlang_add_file (search);
+      ldlang_add_file (entry);
       if (trace_files || trace_file_tries)
-       info_msg ("%I\n", search);
+       info_msg ("%I\n", entry);
     }
-  else if (bfd_check_format (search->the_bfd, bfd_archive))
+  else if (bfd_check_format (entry->the_bfd, bfd_archive))
     {
       /* There is nothing to do here; the add_symbols routine will
         call ldlang_add_file (via the add_archive_element callback)
         for each element of the archive which is used.  */
     }
   else
-    einfo ("%F%B: file not recognized: %E\n", search->the_bfd);
+    einfo ("%F%B: file not recognized: %E\n", entry->the_bfd);
 
-  if (bfd_link_add_symbols (search->the_bfd, &link_info) == false)
-    einfo ("%F%B: could not read symbols: %E\n", search->the_bfd);
+  if (bfd_link_add_symbols (entry->the_bfd, &link_info) == false)
+    einfo ("%F%B: could not read symbols: %E\n", entry->the_bfd);
 
-  search->loaded = true;
-
-  return search;
+  entry->loaded = true;
 }
 
 static void
@@ -864,7 +837,7 @@ open_output (name)
 
   if (output == (bfd *) NULL)
     {
-      if (bfd_error == invalid_target)
+      if (bfd_get_error () == bfd_error_invalid_target)
        {
          einfo ("%P%F: target %s not found\n", output_target);
        }
@@ -911,6 +884,10 @@ ldlang_open_output (statement)
        output_bfd->flags |= WP_TEXT;
       else
        output_bfd->flags &= ~WP_TEXT;
+      if (config.traditional_format)
+       output_bfd->flags |= BFD_TRADITIONAL_FORMAT;
+      else
+       output_bfd->flags &= ~BFD_TRADITIONAL_FORMAT;
       break;
 
     case lang_target_statement_enum:
@@ -941,7 +918,7 @@ open_input_bfds (statement)
       if (statement->input_statement.real == true)
        {
          statement->input_statement.target = current_target;
-         lookup_name (statement->input_statement.filename);
+         load_symbols (&statement->input_statement);
        }
       break;
     default:
@@ -1029,27 +1006,6 @@ lang_place_undefineds ()
     }
 }
 
-/* Copy important data from out internal form to the bfd way. Also
-   create a section for the dummy file
- */
-
-static void
-lang_create_output_section_statements ()
-{
-  lang_statement_union_type *os;
-
-  for (os = lang_output_section_statement.head;
-       os != (lang_statement_union_type *) NULL;
-       os = os->output_section_statement.next)
-    {
-      lang_output_section_statement_type *s =
-      &os->output_section_statement;
-
-      init_os (s);
-    }
-
-}
-
 /* Open input files and attatch to output sections */
 static void
 map_input_to_output_sections (s, target, output_section_statement)
@@ -1088,8 +1044,13 @@ map_input_to_output_sections (s, target, output_section_statement)
        case lang_input_section_enum:
        case lang_object_symbols_statement_enum:
        case lang_data_statement_enum:
+       case lang_reloc_statement_enum:
        case lang_assignment_statement_enum:
        case lang_padding_statement_enum:
+       case lang_input_statement_enum:
+         if (output_section_statement != NULL
+             && output_section_statement->bfd_section == NULL)
+           init_os (output_section_statement);
          break;
        case lang_afile_asection_pair_statement_enum:
          FAIL ();
@@ -1098,20 +1059,14 @@ map_input_to_output_sections (s, target, output_section_statement)
          /* Mark the specified section with the supplied address */
          {
            lang_output_section_statement_type *os =
-           lang_output_section_statement_lookup
-           (s->address_statement.section_name);
+             lang_output_section_statement_lookup
+               (s->address_statement.section_name);
 
+           if (os->bfd_section == NULL)
+             init_os (os);
            os->addr_tree = s->address_statement.address;
-           if (os->bfd_section == (asection *) NULL)
-             {
-               einfo ("%P%F: cannot set the address of undefined section %s\n",
-                      s->address_statement.section_name);
-             }
          }
          break;
-       case lang_input_statement_enum:
-         /* A standard input statement, has no wildcards */
-         break;
        }
     }
 }
@@ -1156,7 +1111,7 @@ print_output_section_statement (output_section_statement)
   }
   else
   {
-    fprintf (config.map_file, "No attached output section");
+    fprintf (config.map_file, " (no attached output section)");
   }
   print_nl ();
   if (output_section_statement->load_base)
@@ -1228,19 +1183,31 @@ print_input_statement (statm)
     }
 }
 
-static void
-print_symbol (q)
-     asymbol * q;
+/* Print all the defined symbols for the abfd provided by in the supplied
+   section.
+*/
+
+static boolean 
+print_one_symbol (hash_entry, ptr)
+struct  bfd_link_hash_entry *hash_entry;
+PTR ptr;
 {
-  print_section ("");
-  fprintf (config.map_file, " ");
-  print_section ("");
-  fprintf (config.map_file, " ");
-  print_address (outside_symbol_address (q));
-  fprintf (config.map_file, "              %s", q->name ? q->name : " ");
-  if (q->flags & BSF_WEAK)
-    fprintf (config.map_file, " *weak*");
-  print_nl ();
+  asection * sec = (asection *)ptr;
+
+  if (hash_entry->type == bfd_link_hash_defined) 
+    {
+      if (sec == hash_entry->u.def.section) {
+       print_section ("");
+       fprintf (config.map_file, " ");
+       print_section ("");
+       fprintf (config.map_file, " ");
+       print_address (hash_entry->u.def.value + outside_section_address (sec));
+       fprintf (config.map_file, "              %s", hash_entry->root.string);
+       print_nl ();
+      }
+    }
+
+  return true;
 }
 
 static void
@@ -1248,9 +1215,7 @@ print_input_section (in)
      lang_input_section_type * in;
 {
   asection *i = in->section;
-  int size = i->reloc_done ?
-  bfd_get_section_size_after_reloc (i) :
-  bfd_get_section_size_before_reloc (i);
+  bfd_size_type size = i->_cooked_size != 0 ? i->_cooked_size : i->_raw_size;
 
   if (size != 0)
     {
@@ -1291,23 +1256,8 @@ print_input_section (in)
              fprintf (config.map_file, "(overhead %d bytes)", (int) bfd_alloc_size (abfd));
              print_nl ();
 
-             /* Find all the symbols in this file defined in this section */
-
-             if (in->ifile->symbol_count)
-               {
-                 asymbol **p;
-
-                 for (p = in->ifile->asymbols; *p; p++)
-                   {
-                     asymbol *q = *p;
-
-                     if (bfd_get_section (q) == i
-                         && (q->flags & (BSF_GLOBAL | BSF_WEAK)) != 0)
-                       {
-                         print_symbol (q);
-                       }
-                   }
-               }
+             /* Print all the symbols */
+             bfd_link_hash_traverse (link_info.hash, print_one_symbol, (PTR) i);
            }
          else
            {
@@ -1372,6 +1322,32 @@ print_data_statement (data)
   fprintf (config.map_file, "\n");
 }
 
+/* Print a reloc statement.  */
+
+static void
+print_reloc_statement (reloc)
+     lang_reloc_statement_type *reloc;
+{
+  print_section ("");
+  print_space ();
+  print_section ("");
+  print_space ();
+
+/*  ASSERT(print_dot == data->output_vma);*/
+
+  print_address (reloc->output_vma + reloc->output_section->vma);
+  print_space ();
+  print_address (reloc->addend_value);
+  print_space ();
+
+  fprintf (config.map_file, "RELOC %s ", reloc->howto->name);
+
+  print_dot += bfd_get_reloc_size (reloc->howto);
+
+  exp_print_tree (reloc->addend_exp);
+
+  fprintf (config.map_file, "\n");
+}  
 
 static void
 print_padding_statement (s)
@@ -1450,6 +1426,9 @@ print_statement (s, os)
        case lang_data_statement_enum:
          print_data_statement (&s->data_statement);
          break;
+       case lang_reloc_statement_enum:
+         print_reloc_statement (&s->reloc_statement);
+         break;
        case lang_input_section_enum:
          print_input_section (&s->input_section);
          break;
@@ -1558,29 +1537,16 @@ size_input_section (this_ptr, output_section_statement, fill, dot, relax)
       dot = insert_pad (this_ptr, fill, i->alignment_power,
                        output_section_statement->bfd_section, dot);
 
-      /* remember the largest size so we can malloc the largest area
-         needed for the output stage. Only remember the size of sections
-         which we will actually allocate  */
-      if ((i->flags & SEC_HAS_CONTENTS) != 0
-         && (bfd_get_section_size_before_reloc (i) > largest_section))
-       {
-         largest_section = bfd_get_section_size_before_reloc (i);
-       }
-
       /* Remember where in the output section this input section goes */
 
       i->output_offset = dot - output_section_statement->bfd_section->vma;
 
       /* Mark how big the output section must be to contain this now
         */
-      if (relax)
-       {
-         dot += i->_cooked_size;
-       }
+      if (i->_cooked_size != 0)
+       dot += i->_cooked_size;
       else
-       {
-         dot += i->_raw_size;
-       }
+       dot += i->_raw_size;
       output_section_statement->bfd_section->_raw_size = dot - output_section_statement->bfd_section->vma;
     }
   else
@@ -1591,13 +1557,14 @@ size_input_section (this_ptr, output_section_statement, fill, dot, relax)
   return dot;
 }
 
-/* Sizing happens in two passes, first pass we allocate worst case
-   stuff. The second pass (if relaxing), we use what we learnt to
-   change the size of some relocs from worst case to better
-   */
-static boolean had_relax;
+/* This variable indicates whether bfd_relax_section should be called
+   again.  */
 
-static bfd_vma
+static boolean relax_again;
+
+/* Set the sizes for all the output sections.  */
+
+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;
@@ -1617,15 +1584,38 @@ lang_size_sections (s, output_section_statement, prev, fill, dot, relax)
        bfd_vma after;
        lang_output_section_statement_type *os = &s->output_section_statement;
 
-       /* If this is a shared library section, don't change the size
-         and address.  */
-       if (os->bfd_section->flags & SEC_SHARED_LIBRARY)
-        break;
+       if (os->bfd_section == NULL)
+        {
+          /* This section was never actually created.  */
+          break;
+        }
 
-       if (os->bfd_section == &bfd_abs_section)
+       /* If this is a COFF shared library section, use the size and
+         address from the input section.  FIXME: This is COFF
+         specific; it would be cleaner if there were some other way
+         to do this, but nothing simple comes to mind.  */
+       if ((os->bfd_section->flags & SEC_COFF_SHARED_LIBRARY) != 0)
+        {
+          asection *input;
+
+          if (os->children.head == NULL
+              || os->children.head->next != NULL
+              || os->children.head->header.type != lang_input_section_enum)
+            einfo ("%P%X: Internal error on COFF shared library section %s",
+                   os->name);
+
+          input = os->children.head->input_section.section;
+          bfd_set_section_vma (os->bfd_section->owner,
+                               os->bfd_section,
+                               bfd_section_vma (input->owner, input));
+          os->bfd_section->_raw_size = input->_raw_size;
+          break;
+        }
+
+       if (bfd_is_abs_section (os->bfd_section))
        {
         /* No matter what happens, an abs section starts at zero */
-        bfd_set_section_vma (0, os->bfd_section, 0);
+        ASSERT (os->bfd_section->vma == 0);
        }
        else
        {
@@ -1639,6 +1629,8 @@ lang_size_sections (s, output_section_statement, prev, fill, dot, relax)
             os->region = lang_memory_region_lookup ("*default*");
           }
           dot = os->region->current;
+          if (os->section_alignment == -1)
+            dot = align_power (dot, os->bfd_section->alignment_power);
         }
         else
         {
@@ -1658,18 +1650,18 @@ lang_size_sections (s, output_section_statement, prev, fill, dot, relax)
         /* The section starts here */
         /* First, align to what the section needs */
 
+        if (os->section_alignment != -1)
+          dot = align_power (dot, os->section_alignment);
 
-        dot = align_power (dot, os->bfd_section->alignment_power);
         bfd_set_section_vma (0, os->bfd_section, dot);
         
         if (os->load_base) {
           os->bfd_section->lma 
             = exp_get_value_int(os->load_base, 0,"load base", lang_final_phase_enum);
         }
-       }
-
 
-       os->bfd_section->output_offset = 0;
+        os->bfd_section->output_offset = 0;
+       }
 
        (void) lang_size_sections (os->children.head, os, &os->children.head,
                                  os->fill, dot, relax);
@@ -1681,13 +1673,15 @@ lang_size_sections (s, output_section_statement, prev, fill, dot, relax)
                        /* The coercion here is important, see ld.h.  */
                        (bfd_vma) os->block_value);
 
-       os->bfd_section->_raw_size = after - os->bfd_section->vma;
+       if (bfd_is_abs_section (os->bfd_section))
+        ASSERT (after == os->bfd_section->vma);
+       else
+        os->bfd_section->_raw_size = after - os->bfd_section->vma;
        dot = os->bfd_section->vma + os->bfd_section->_raw_size;
        os->processed = true;
 
        /* Replace into region ? */
-       if (os->addr_tree == (etree_type *) NULL
-          && os->region != (lang_memory_region_type *) NULL)
+       if (os->region != (lang_memory_region_type *) NULL)
        {
         os->region->current = dot;
         /* Make sure this isn't silly */
@@ -1745,6 +1739,20 @@ lang_size_sections (s, output_section_statement, prev, fill, dot, relax)
      }
       break;
 
+     case lang_reloc_statement_enum:
+     {
+       int size;
+
+       s->reloc_statement.output_vma =
+        dot - output_section_statement->bfd_section->vma;
+       s->reloc_statement.output_section =
+        output_section_statement->bfd_section;
+       size = bfd_get_reloc_size (s->reloc_statement.howto);
+       dot += size;
+       output_section_statement->bfd_section->_raw_size += size;
+     }
+     break;
+     
      case lang_wild_statement_enum:
 
       dot = lang_size_sections (s->wild_statement.children.head,
@@ -1763,47 +1771,26 @@ lang_size_sections (s, output_section_statement, prev, fill, dot, relax)
      case lang_target_statement_enum:
       break;
      case lang_input_section_enum:
-      if (relax)
       {
-       lang_input_section_type *is;
        asection *i;
 
-       is = &(*prev)->input_section;
-       i = is->section;
-
-       /* FIXME: The interface to bfd_relax_section should be changed
-          to not require the generic symbols to be read.  Changing
-          this would require changing both b_out_relax_section and
-          bfd_coff_relax16_section.  */
-       if (is->ifile->asymbols == (asymbol **) NULL)
+       i = (*prev)->input_section.section;
+       if (! relax)
+         i->_cooked_size = i->_raw_size;
+       else
          {
-           unsigned int symsize;
-
-           symsize = get_symtab_upper_bound (i->owner);
-           is->ifile->asymbols = (asymbol **) ldmalloc (symsize);
-           is->ifile->symbol_count =
-             bfd_canonicalize_symtab (i->owner, is->ifile->asymbols);
-
-           /* The generic linker code in BFD requires that these
-              symbols be stored in the outsymbols and symcount
-              fields.  When the bfd_relax_section is interface is
-              fixed this should also be fixed.  */
-           i->owner->outsymbols = is->ifile->asymbols;
-           i->owner->symcount = is->ifile->symbol_count;
-         }
-
-       if (bfd_relax_section (i->owner, i, &link_info, is->ifile->asymbols))
-         had_relax = true;
-      }
-      else  {
-       (*prev)->input_section.section->_cooked_size = 
-        (*prev)->input_section.section->_raw_size ;
+           boolean again;
 
+           if (! bfd_relax_section (i->owner, i, &link_info, &again))
+             einfo ("%P%F: can't relax section: %E\n");
+           if (again)
+             relax_again = true;
+         }
+       dot = size_input_section (prev,
+                                 output_section_statement,
+                                 output_section_statement->fill,
+                                 dot, relax);
       }
-      dot = size_input_section (prev,
-                               output_section_statement,
-                               output_section_statement->fill,
-                               dot, relax);
       break;
      case lang_input_statement_enum:
       break;
@@ -1823,34 +1810,55 @@ lang_size_sections (s, output_section_statement, prev, fill, dot, relax)
                      &newdot);
 
        if (newdot != dot && !relax)
-       /* We've been moved ! so insert a pad */
-       {
-        lang_statement_union_type *new =
-         (lang_statement_union_type *)
-          stat_alloc ((bfd_size_type) (sizeof (lang_padding_statement_type)));
-
-        /* Link into existing chain */
-        new->header.next = *prev;
-        *prev = new;
-        new->header.type = lang_padding_statement_enum;
-        new->padding_statement.output_section =
-         output_section_statement->bfd_section;
-        new->padding_statement.output_offset =
-         dot - output_section_statement->bfd_section->vma;
-        new->padding_statement.fill = fill;
-        new->padding_statement.size = newdot - dot;
-        output_section_statement->bfd_section->_raw_size +=
-         new->padding_statement.size;
-        dot = newdot;
-       }
+        {
+          /* The assignment changed dot.  Insert a pad.  */
+          if (output_section_statement == abs_output_section)
+            {
+              /* If we don't have an output section, then just adjust
+                 the default memory address.  */
+              lang_memory_region_lookup ("*default*")->current = newdot;
+            }
+          else
+            {
+              lang_statement_union_type *new =
+                ((lang_statement_union_type *)
+                 stat_alloc (sizeof (lang_padding_statement_type)));
+
+              /* Link into existing chain */
+              new->header.next = *prev;
+              *prev = new;
+              new->header.type = lang_padding_statement_enum;
+              new->padding_statement.output_section =
+                output_section_statement->bfd_section;
+              new->padding_statement.output_offset =
+                dot - output_section_statement->bfd_section->vma;
+              new->padding_statement.fill = fill;
+              new->padding_statement.size = newdot - dot;
+              output_section_statement->bfd_section->_raw_size +=
+                new->padding_statement.size;
+            }
+
+          dot = newdot;
+        }
      }
+     break;
+
+   case lang_padding_statement_enum:
+     /* If we are relaxing, and this is not the first pass, some
+       padding statements may have been inserted during previous
+       passes.  We may have to move the padding statement to a new
+       location if dot has a different value at this point in this
+       pass than it did at this point in the previous pass.  */
+     s->padding_statement.output_offset =
+       dot - output_section_statement->bfd_section->vma;
+     dot += s->padding_statement.size;
+     break;
 
-      break;
      default:
       FAIL ();
       break;
+
       /* This can only get here when relaxing is turned on */
-     case lang_padding_statement_enum:
 
      case lang_address_statement_enum:
       break;
@@ -1881,11 +1889,15 @@ lang_do_assignments (s, output_section_statement, fill, dot)
        case lang_output_section_statement_enum:
          {
            lang_output_section_statement_type *os =
-           &(s->output_section_statement);
+             &(s->output_section_statement);
 
-           dot = os->bfd_section->vma;
-           (void) lang_do_assignments (os->children.head, os, os->fill, dot);
-           dot = os->bfd_section->vma + os->bfd_section->_raw_size;
+           if (os->bfd_section != NULL)
+             {
+               dot = os->bfd_section->vma;
+               (void) lang_do_assignments (os->children.head, os,
+                                           os->fill, dot);
+               dot = os->bfd_section->vma + os->bfd_section->_raw_size;
+             }
          }
          break;
        case lang_wild_statement_enum:
@@ -1930,11 +1942,29 @@ lang_do_assignments (s, output_section_statement, fill, dot)
              break;
            }
          break;
+
+       case lang_reloc_statement_enum:
+         {
+           etree_value_type value;
+
+           value = exp_fold_tree (s->reloc_statement.addend_exp,
+                                  abs_output_section,
+                                  lang_final_phase_enum, dot, &dot);
+           s->reloc_statement.addend_value = value.value;
+           if (value.valid == false)
+             einfo ("%F%P: invalid reloc statement\n");
+         }
+         dot += bfd_get_reloc_size (s->reloc_statement.howto);
+         break;
+
        case lang_input_section_enum:
          {
            asection *in = s->input_section.section;
 
-           dot += bfd_get_section_size_before_reloc (in);
+           if (in->_cooked_size != 0)
+             dot += in->_cooked_size;
+           else
+             dot += in->_raw_size;
          }
          break;
 
@@ -2156,7 +2186,7 @@ lang_one_common (h, info)
   /* Increase the size of the section.  */
   section->_raw_size += size;
 
-  if (write_map && config.map_file != NULL)
+  if (config.map_file != NULL)
     fprintf (config.map_file, "Allocating common %s: %lx at %lx %s\n",
             h->root.string, (unsigned long) size,
             (unsigned long) h->u.def.value, section->owner->filename);
@@ -2182,6 +2212,9 @@ lang_place_orphans ()
     {
       asection *s;
 
+      if (file->just_syms_flag)
+       continue;
+
       for (s = file->the_bfd->sections;
           s != (asection *) NULL;
           s = s->next)
@@ -2265,7 +2298,24 @@ lang_set_flags (ptr, flags)
     }
 }
 
+/* Call a function on each input file.  This function will be called
+   on an archive, but not on the elements.  */
+
+void
+lang_for_each_input_file (func)
+     void (*func) PARAMS ((lang_input_statement_type *));
+{
+  lang_input_statement_type *f;
+
+  for (f = (lang_input_statement_type *) input_file_chain.head;
+       f != NULL;
+       f = (lang_input_statement_type *) f->next_real_file)
+    func (f);
+}
 
+/* Call a function on each file.  The function will be called on all
+   the elements of an archive which are included in the link, but will
+   not be called on the archive file itself.  */
 
 void
 lang_for_each_file (func)
@@ -2328,6 +2378,7 @@ ldlang_add_file (entry)
     ;
   *pp = entry->the_bfd;
   entry->the_bfd->usrdata = (PTR) entry;
+  bfd_set_gp_size (entry->the_bfd, g_switch_value);
 }
 
 void
@@ -2441,9 +2492,6 @@ lang_process ()
   current_target = default_target;
 
   lang_for_each_statement (ldlang_open_output);        /* Open the output file */
-  /* For each output section statement, create a section in the output
-     file */
-  lang_create_output_section_statements ();
 
   ldemul_create_output_section_statements ();
 
@@ -2458,6 +2506,9 @@ lang_process ()
      files.  */
   ldctor_build_sets ();
 
+  /* Size up the common data */
+  lang_common ();
+
   /* Run through the contours of the script and attatch input sections
      to the correct output sections
      */
@@ -2468,54 +2519,38 @@ lang_process ()
   /* Find any sections not attatched explicitly and handle them */
   lang_place_orphans ();
 
-  /* Size up the common data */
-  lang_common ();
-
   ldemul_before_allocation ();
 
-
-#if 0
-  had_relax = true;
-  while (had_relax)
-    {
-
-      had_relax = false;
-
-      lang_size_sections (statement_list.head,
-                         (lang_output_section_statement_type *) NULL,
-                         &(statement_list.head), 0, (bfd_vma) 0, true);
-      /* FIXME. Until the code in relax is fixed so that it only reads in
-         stuff once, we cant iterate since there is no way for the linker to
-         know what has been patched and what hasn't */
-      break;
-
-    }
-#endif
-
   /* Now run around and relax if we can */
   if (command_line.relax)
     {
       /* First time round is a trial run to get the 'worst case'
         addresses of the objects if there was no relaxing.  */
       lang_size_sections (statement_list.head,
-                         (lang_output_section_statement_type *) NULL,
+                         abs_output_section,
                          &(statement_list.head), 0, (bfd_vma) 0, false);
 
 
       reset_memory_regions ();
 
-      /* Do all the assignments, now that we know the final resting
-        places of all the symbols.  */
+      /* Keep relaxing until bfd_relax_section gives up.  */
+      do
+       {
+         relax_again = false;
 
-      lang_do_assignments (statement_list.head,
-                          abs_output_section,
-                          (fill_type) 0, (bfd_vma) 0);
+         /* Do all the assignments with our current guesses as to
+            section sizes.  */
+         lang_do_assignments (statement_list.head,
+                              abs_output_section,
+                              (fill_type) 0, (bfd_vma) 0);
 
-      /* Perform another relax pass - this time we know where the
-        globals are, so can make better guess.  */
-      lang_size_sections (statement_list.head,
-                         (lang_output_section_statement_type *) NULL,
-                         &(statement_list.head), 0, (bfd_vma) 0, true);
+         /* Perform another relax pass - this time we know where the
+            globals are, so can make better guess.  */
+         lang_size_sections (statement_list.head,
+                             abs_output_section,
+                             &(statement_list.head), 0, (bfd_vma) 0, true);
+       }
+      while (relax_again);
     }
   else
     {
@@ -2543,17 +2578,6 @@ lang_process ()
   /* Final stuffs */
 
   ldemul_finish ();
-
-#if 0
-  /* DO NOT REENABLE THIS CALL.  IF THIS CALL IS MADE, THE SUN4 LINKER
-     CAN NOT BOOTSTRAP!!  No, I don't know why, but don't change it
-     unless you fix it.  */
-  /* Size up the sections.  */
-  lang_size_sections (statement_list.head,
-                     abs_output_section,
-                     &(statement_list.head), 0, (bfd_vma) 0, false);
-#endif
-
   lang_finish ();
 }
 
@@ -2591,11 +2615,25 @@ lang_section_start (name, address)
   ad->address = address;
 }
 
+/* Set the start symbol to NAME.  CMDLINE is nonzero if this is called
+   because of a -e argument on the command line, or zero if this is
+   called by ENTRY in a linker script.  Command line arguments take
+   precedence.  */
+
 void
-lang_add_entry (name)
+lang_add_entry (name, cmdline)
      CONST char *name;
+     int cmdline;
 {
-  entry_symbol = name;
+  static int from_cmdline;
+
+  if (entry_symbol == NULL
+      || cmdline
+      || ! from_cmdline)
+    {
+      entry_symbol = name;
+      from_cmdline = cmdline;
+    }
 }
 
 void
@@ -2649,6 +2687,34 @@ lang_add_data (type, exp)
 
 }
 
+/* Create a new reloc statement.  RELOC is the BFD relocation type to
+   generate.  HOWTO is the corresponding howto structure (we could
+   look this up, but the caller has already done so).  SECTION is the
+   section to generate a reloc against, or NAME is the name of the
+   symbol to generate a reloc against.  Exactly one of SECTION and
+   NAME must be NULL.  ADDEND is an expression for the addend.  */
+
+void
+lang_add_reloc (reloc, howto, section, name, addend)
+     bfd_reloc_code_real_type reloc;
+     const reloc_howto_type *howto;
+     asection *section;
+     const char *name;
+     union etree_union *addend;
+{
+  lang_reloc_statement_type *p = new_stat (lang_reloc_statement, stat_ptr);
+  
+  p->reloc = reloc;
+  p->howto = howto;
+  p->section = section;
+  p->name = name;
+  p->addend_exp = addend;
+
+  p->addend_value = 0;
+  p->output_section = NULL;
+  p->output_vma = 0;
+}
+
 void
 lang_add_assignment (exp)
      etree_type * exp;
@@ -2676,6 +2742,7 @@ lang_startup (name)
     }
   first_file->filename = name;
   first_file->local_sym_name = name;
+  first_file->real = true;
 
   startup_file = name;
 }
@@ -2695,14 +2762,6 @@ lang_leave_output_section_statement (fill, memspec)
   current_section->fill = fill;
   current_section->region = lang_memory_region_lookup (memspec);
   stat_ptr = &statement_list;
-
-  /* We remember if we are closing a .data section, since we use it to
-     store constructors in */
-  if (strcmp (current_section->name, ".data") == 0)
-    {
-      end_of_data_section_statement_list = statement_list;
-
-    }
 }
 
 /*
@@ -2735,7 +2794,7 @@ lang_abs_symbol_at_beginning_of (secname, name)
       else
        h->u.def.value = bfd_get_section_vma (output_bfd, sec);
 
-      h->u.def.section = &bfd_abs_section;
+      h->u.def.section = bfd_abs_section_ptr;
     }
 }
 
@@ -2770,7 +2829,7 @@ lang_abs_symbol_at_end_of (secname, name)
        h->u.def.value = (bfd_get_section_vma (output_bfd, sec)
                          + bfd_section_size (output_bfd, sec));
 
-      h->u.def.section = &bfd_abs_section;
+      h->u.def.section = bfd_abs_section_ptr;
     }
 }