bfd/
[external/binutils.git] / ld / ldlang.c
index 0f5c630..6cc05a6 100644 (file)
@@ -47,6 +47,7 @@
 
 /* Locals variables.  */
 static struct obstack stat_obstack;
+static struct obstack map_obstack;
 
 #define obstack_chunk_alloc xmalloc
 #define obstack_chunk_free free
@@ -65,6 +66,7 @@ static struct bfd_hash_table lang_definedness_table;
 
 /* Forward declarations.  */
 static void exp_init_os (etree_type *);
+static void init_map_userdata (bfd *, asection *, void *);
 static bfd_boolean wildcardp (const char *);
 static lang_input_statement_type *lookup_name (const char *);
 static bfd_boolean load_symbols (lang_input_statement_type *,
@@ -72,6 +74,8 @@ static bfd_boolean load_symbols (lang_input_statement_type *,
 static struct bfd_hash_entry *lang_definedness_newfunc
  (struct bfd_hash_entry *, struct bfd_hash_table *, const char *);
 static void insert_undefined (const char *);
+static void print_all_symbols (asection *);
+static bfd_boolean sort_def_symbol (struct bfd_link_hash_entry *, void *);
 static void print_statement (lang_statement_union_type *,
                             lang_output_section_statement_type *);
 static void print_statement_list (lang_statement_union_type *,
@@ -121,10 +125,17 @@ stat_alloc (size_t size)
 }
 
 bfd_boolean
-unique_section_p (const char *secnam)
+unique_section_p (const asection *sec)
 {
   struct unique_sections *unam;
+  const char *secnam;
 
+  if (link_info.relocatable
+      && sec->owner != NULL
+      && bfd_is_group_section (sec->owner, sec))
+    return TRUE;
+
+  secnam = sec->name;
   for (unam = unique_section_list; unam; unam = unam->next)
     if (wildcardp (unam->name)
        ? fnmatch (unam->name, secnam, 0) == 0
@@ -295,13 +306,11 @@ lang_for_each_statement_worker (void (*func) (lang_statement_union_type *),
          break;
        case lang_output_section_statement_enum:
          lang_for_each_statement_worker
-           (func,
-            s->output_section_statement.children.head);
+           (func, s->output_section_statement.children.head);
          break;
        case lang_wild_statement_enum:
-         lang_for_each_statement_worker
-           (func,
-            s->wild_statement.children.head);
+         lang_for_each_statement_worker (func,
+                                         s->wild_statement.children.head);
          break;
        case lang_group_statement_enum:
          lang_for_each_statement_worker (func,
@@ -445,6 +454,8 @@ new_afile (const char *name,
   p->next = NULL;
   p->symbol_count = 0;
   p->dynamic = config.dynamic_link;
+  p->add_needed = add_needed;
+  p->as_needed = as_needed;
   p->whole_archive = whole_archive;
   p->loaded = FALSE;
   lang_statement_append (&input_file_chain,
@@ -514,7 +525,8 @@ lang_init (void)
   and so we issue a warning.  */
 
 static lang_memory_region_type *lang_memory_region_list;
-static lang_memory_region_type **lang_memory_region_list_tail = &lang_memory_region_list;
+static lang_memory_region_type **lang_memory_region_list_tail
+  = &lang_memory_region_list;
 
 lang_memory_region_type *
 lang_memory_region_lookup (const char *const name, bfd_boolean create)
@@ -530,7 +542,8 @@ lang_memory_region_lookup (const char *const name, bfd_boolean create)
     if (strcmp (p->name, name) == 0)
       {
        if (create)
-         einfo (_("%P:%S: warning: redeclaration of memory region '%s'\n"), name);
+         einfo (_("%P:%S: warning: redeclaration of memory region '%s'\n"),
+                name);
        return p;
       }
 
@@ -590,8 +603,8 @@ lang_memory_default (asection *section)
   return lang_memory_region_lookup (DEFAULT_MEMORY_REGION, FALSE);
 }
 
-lang_output_section_statement_type *
-lang_output_section_find (const char *const name)
+static lang_output_section_statement_type *
+lang_output_section_find_1 (const char *const name, int constraint)
 {
   lang_statement_union_type *u;
   lang_output_section_statement_type *lookup;
@@ -599,18 +612,26 @@ lang_output_section_find (const char *const name)
   for (u = lang_output_section_statement.head; u != NULL; u = lookup->next)
     {
       lookup = &u->output_section_statement;
-      if (strcmp (name, lookup->name) == 0)
+      if (strcmp (name, lookup->name) == 0
+         && lookup->constraint != -1
+         && (constraint == 0 || constraint == lookup->constraint))
        return lookup;
     }
   return NULL;
 }
 
 lang_output_section_statement_type *
-lang_output_section_statement_lookup (const char *const name)
+lang_output_section_find (const char *const name)
+{
+  return lang_output_section_find_1 (name, 0);
+}
+
+static lang_output_section_statement_type *
+lang_output_section_statement_lookup_1 (const char *const name, int constraint)
 {
   lang_output_section_statement_type *lookup;
 
-  lookup = lang_output_section_find (name);
+  lookup = lang_output_section_find_1 (name, constraint);
   if (lookup == NULL)
     {
       lookup = new_stat (lang_output_section_statement, stat_ptr);
@@ -623,6 +644,7 @@ lang_output_section_statement_lookup (const char *const name)
       lookup->next = NULL;
       lookup->bfd_section = NULL;
       lookup->processed = 0;
+      lookup->constraint = constraint;
       lookup->sectype = normal_section;
       lookup->addr_tree = NULL;
       lang_list_init (&lookup->children);
@@ -642,6 +664,12 @@ lang_output_section_statement_lookup (const char *const name)
   return lookup;
 }
 
+lang_output_section_statement_type *
+lang_output_section_statement_lookup (const char *const name)
+{
+  return lang_output_section_statement_lookup_1 (name, 0);
+}
+
 static void
 lang_map_flags (flagword flag)
 {
@@ -665,6 +693,7 @@ void
 lang_map (void)
 {
   lang_memory_region_type *m;
+  bfd *p;
 
   minfo (_("\nMemory Configuration\n\n"));
   fprintf (config.map_file, "%-16s %-18s %-18s %s\n",
@@ -710,15 +739,67 @@ lang_map (void)
 
   fprintf (config.map_file, _("\nLinker script and memory map\n\n"));
 
+  if (! command_line.reduce_memory_overheads)
+    {
+      obstack_begin (&map_obstack, 1000);
+      for (p = link_info.input_bfds; p != (bfd *) NULL; p = p->link_next)
+       bfd_map_over_sections (p, init_map_userdata, 0);
+      bfd_link_hash_traverse (link_info.hash, sort_def_symbol, 0);
+    }
   print_statements ();
 }
 
+static void
+init_map_userdata (abfd, sec, data)
+     bfd *abfd ATTRIBUTE_UNUSED;
+     asection *sec;
+     void *data ATTRIBUTE_UNUSED;
+{
+  fat_section_userdata_type *new_data
+    = ((fat_section_userdata_type *) (stat_alloc
+                                     (sizeof (fat_section_userdata_type))));
+
+  ASSERT (get_userdata (sec) == NULL);
+  get_userdata (sec) = new_data;
+  new_data->map_symbol_def_tail = &new_data->map_symbol_def_head;
+}
+
+static bfd_boolean
+sort_def_symbol (hash_entry, info)
+     struct bfd_link_hash_entry *hash_entry;
+     void *info ATTRIBUTE_UNUSED;
+{
+  if (hash_entry->type == bfd_link_hash_defined
+      || hash_entry->type == bfd_link_hash_defweak)
+    {
+      struct fat_user_section_struct *ud;
+      struct map_symbol_def *def;
+
+      ud = get_userdata (hash_entry->u.def.section);
+      if  (! ud)
+       {
+         /* ??? What do we have to do to initialize this beforehand?  */
+         /* The first time we get here is bfd_abs_section...  */
+         init_map_userdata (0, hash_entry->u.def.section, 0);
+         ud = get_userdata (hash_entry->u.def.section);
+       }
+      else if  (!ud->map_symbol_def_tail)
+       ud->map_symbol_def_tail = &ud->map_symbol_def_head;
+      
+      def = obstack_alloc (&map_obstack, sizeof *def);
+      def->entry = hash_entry;
+      *(ud->map_symbol_def_tail) = def;
+      ud->map_symbol_def_tail = &def->next;
+    }
+  return TRUE;
+}
+
 /* Initialize an output section.  */
 
 static void
 init_os (lang_output_section_statement_type *s)
 {
-  section_userdata_type *new;
+  lean_section_userdata_type *new;
 
   if (s->bfd_section != NULL)
     return;
@@ -726,7 +807,8 @@ init_os (lang_output_section_statement_type *s)
   if (strcmp (s->name, DISCARD_SECTION_NAME) == 0)
     einfo (_("%P%F: Illegal use of `%s' section\n"), DISCARD_SECTION_NAME);
 
-  new = stat_alloc (sizeof (section_userdata_type));
+  new = stat_alloc (SECTION_USERDATA_SIZE);
+  memset (new, 0, SECTION_USERDATA_SIZE);
 
   s->bfd_section = bfd_get_section_by_name (output_bfd, s->name);
   if (s->bfd_section == NULL)
@@ -804,44 +886,10 @@ exp_init_os (etree_type *exp)
     }
 }
 \f
-/* Sections marked with the SEC_LINK_ONCE flag should only be linked
-   once into the output.  This routine checks each section, and
-   arrange to discard it if a section of the same name has already
-   been linked.  If the section has COMDAT information, then it uses
-   that to decide whether the section should be included.  This code
-   assumes that all relevant sections have the SEC_LINK_ONCE flag set;
-   that is, it does not depend solely upon the section name.
-   section_already_linked is called via bfd_map_over_sections.  */
-
-/* This is the shape of the elements inside the already_linked hash
-   table. It maps a name onto a list of already_linked elements with
-   the same name.  It's possible to get more than one element in a
-   list if the COMDAT sections have different names.  */
-
-struct already_linked_hash_entry
-{
-  struct bfd_hash_entry root;
-  struct already_linked *entry;
-};
-
-struct already_linked
-{
-  struct already_linked *next;
-  asection *sec;
-};
-
-/* The hash table.  */
-
-static struct bfd_hash_table already_linked_table;
-
 static void
 section_already_linked (bfd *abfd, asection *sec, void *data)
 {
   lang_input_statement_type *entry = data;
-  flagword flags;
-  const char *name;
-  struct already_linked *l;
-  struct already_linked_hash_entry *already_linked_list;
 
   /* If we are only reading symbols from this object, then we want to
      discard all sections.  */
@@ -851,128 +899,7 @@ section_already_linked (bfd *abfd, asection *sec, void *data)
       return;
     }
 
-  flags = bfd_get_section_flags (abfd, sec);
-
-  if ((flags & SEC_LINK_ONCE) == 0)
-    return;
-
-  /* FIXME: When doing a relocatable link, we may have trouble
-     copying relocations in other sections that refer to local symbols
-     in the section being discarded.  Those relocations will have to
-     be converted somehow; as of this writing I'm not sure that any of
-     the backends handle that correctly.
-
-     It is tempting to instead not discard link once sections when
-     doing a relocatable link (technically, they should be discarded
-     whenever we are building constructors).  However, that fails,
-     because the linker winds up combining all the link once sections
-     into a single large link once section, which defeats the purpose
-     of having link once sections in the first place.
-
-     Also, not merging link once sections in a relocatable link
-     causes trouble for MIPS ELF, which relies on link once semantics
-     to handle the .reginfo section correctly.  */
-
-  name = bfd_get_section_name (abfd, sec);
-
-  already_linked_list =
-    ((struct already_linked_hash_entry *)
-     bfd_hash_lookup (&already_linked_table, name, TRUE, FALSE));
-
-  for (l = already_linked_list->entry; l != NULL; l = l->next)
-    {
-      if (sec->comdat == NULL
-         || l->sec->comdat == NULL
-         || strcmp (sec->comdat->name, l->sec->comdat->name) == 0)
-       {
-         /* The section has already been linked.  See if we should
-             issue a warning.  */
-         switch (flags & SEC_LINK_DUPLICATES)
-           {
-           default:
-             abort ();
-
-           case SEC_LINK_DUPLICATES_DISCARD:
-             break;
-
-           case SEC_LINK_DUPLICATES_ONE_ONLY:
-             if (sec->comdat == NULL)
-               einfo (_("%P: %B: warning: ignoring duplicate section `%s'\n"),
-                      abfd, name);
-             else
-               einfo (_("%P: %B: warning: ignoring duplicate `%s' section symbol `%s'\n"),
-                      abfd, name, sec->comdat->name);
-             break;
-
-           case SEC_LINK_DUPLICATES_SAME_CONTENTS:
-             /* FIXME: We should really dig out the contents of both
-                 sections and memcmp them.  The COFF/PE spec says that
-                 the Microsoft linker does not implement this
-                 correctly, so I'm not going to bother doing it
-                 either.  */
-             /* Fall through.  */
-           case SEC_LINK_DUPLICATES_SAME_SIZE:
-             if (bfd_section_size (abfd, sec)
-                 != bfd_section_size (l->sec->owner, l->sec))
-               einfo (_("%P: %B: warning: duplicate section `%s' has different size\n"),
-                      abfd, name);
-             break;
-           }
-
-         /* Set the output_section field so that lang_add_section
-            does not create a lang_input_section structure for this
-            section.  Since there might be a symbol in the section
-            being discarded, we must retain a pointer to the section
-            which we are really going to use.  */
-         sec->output_section = bfd_abs_section_ptr;
-         sec->kept_section = l->sec;
-
-         if (flags & SEC_GROUP)
-           bfd_discard_group (abfd, sec);
-
-         return;
-       }
-    }
-
-  /* This is the first section with this name.  Record it.  Allocate
-     the memory from the same obstack as the hash table is kept in.  */
-
-  l = bfd_hash_allocate (&already_linked_table, sizeof *l);
-
-  l->sec = sec;
-  l->next = already_linked_list->entry;
-  already_linked_list->entry = l;
-}
-
-/* Support routines for the hash table used by section_already_linked,
-   initialize the table, fill in an entry and remove the table.  */
-
-static struct bfd_hash_entry *
-already_linked_newfunc (struct bfd_hash_entry *entry ATTRIBUTE_UNUSED,
-                       struct bfd_hash_table *table,
-                       const char *string ATTRIBUTE_UNUSED)
-{
-  struct already_linked_hash_entry *ret =
-    bfd_hash_allocate (table, sizeof (struct already_linked_hash_entry));
-
-  ret->entry = NULL;
-
-  return &ret->root;
-}
-
-static void
-already_linked_table_init (void)
-{
-  if (! bfd_hash_table_init_n (&already_linked_table,
-                              already_linked_newfunc,
-                              42))
-    einfo (_("%P%F: Failed to create hash table\n"));
-}
-
-static void
-already_linked_table_free (void)
-{
-  bfd_hash_table_free (&already_linked_table);
+  bfd_section_already_linked (abfd, sec);
 }
 \f
 /* The wild routines.
@@ -1010,19 +937,11 @@ lang_add_section (lang_statement_list_type *ptr,
                  lang_output_section_statement_type *output,
                  lang_input_statement_type *file)
 {
-  flagword flags;
+  flagword flags = section->flags;
   bfd_boolean discard;
 
-  flags = bfd_get_section_flags (section->owner, section);
-
-  discard = FALSE;
-
-  /* Discard sections marked with SEC_EXCLUDE if we are doing a final
-     link.  Discard debugging sections marked with SEC_EXCLUDE on a
-     relocatable link too.  */
-  if ((flags & SEC_EXCLUDE) != 0
-      && ((flags & SEC_DEBUGGING) != 0 || !link_info.relocatable))
-    discard = TRUE;
+  /* Discard sections marked with SEC_EXCLUDE.  */
+  discard = (flags & SEC_EXCLUDE) != 0;
 
   /* Discard input sections which are assigned to a section named
      DISCARD_SECTION_NAME.  */
@@ -1101,10 +1020,6 @@ lang_add_section (lang_statement_list_type *ptr,
          flags &= ~ (SEC_MERGE | SEC_STRINGS);
        }
 
-      /* For now make .tbss normal section.  */
-      if ((flags & SEC_THREAD_LOCAL) && ! link_info.relocatable)
-       flags |= SEC_LOAD;
-
       section->output_section->flags |= flags;
 
       if (flags & SEC_MERGE)
@@ -1265,14 +1180,9 @@ output_section_callback (lang_wild_statement_type *ptr,
   lang_statement_union_type *before;
 
   /* Exclude sections that match UNIQUE_SECTION_LIST.  */
-  if (unique_section_p (bfd_get_section_name (file->the_bfd, section)))
+  if (unique_section_p (section))
     return;
 
-  /* If the wild pattern was marked KEEP, the member sections
-     should be as well.  */
-  if (ptr->keep_sections)
-    section->flags |= SEC_KEEP;
-
   before = wild_sort (ptr, sec, file, section);
 
   /* Here BEFORE points to the lang_input_section which
@@ -1311,6 +1221,24 @@ output_section_callback (lang_wild_statement_type *ptr,
     }
 }
 
+/* Check if all sections in a wild statement for a particular FILE
+   are readonly.  */
+
+static void
+check_section_callback (lang_wild_statement_type *ptr ATTRIBUTE_UNUSED,
+                       struct wildcard_list *sec ATTRIBUTE_UNUSED,
+                       asection *section,
+                       lang_input_statement_type *file ATTRIBUTE_UNUSED,
+                       void *data)
+{
+  /* Exclude sections that match UNIQUE_SECTION_LIST.  */
+  if (unique_section_p (section))
+    return;
+
+  if (section->output_section == NULL && (section->flags & SEC_READONLY) == 0)
+    ((lang_output_section_statement_type *) data)->all_input_readonly = FALSE;
+}
+
 /* This is passed a file name which must have been seen already and
    added to the statement tree.  We will see if it has been opened
    already and had its symbols read.  If not then we'll read it.  */
@@ -1338,8 +1266,8 @@ lookup_name (const char *name)
     }
 
   if (search == NULL)
-    search = new_afile (name, lang_input_file_is_search_file_enum, default_target,
-                       FALSE);
+    search = new_afile (name, lang_input_file_is_search_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
@@ -1733,7 +1661,8 @@ open_output (const char *name)
                  /* Oh dear - we could not find any targets that
                     satisfy our requirements.  */
                  if (winner == NULL)
-                   einfo (_("%P: warning: could not find any targets that match endianness requirement\n"));
+                   einfo (_("%P: warning: could not find any targets"
+                            " that match endianness requirement\n"));
                  else
                    output_target = winner->name;
                }
@@ -1846,7 +1775,7 @@ open_input_bfds (lang_statement_union_type *s, bfd_boolean force)
          /* Maybe we should load the file's symbols.  */
          if (s->wild_statement.filename
              && ! wildcardp (s->wild_statement.filename))
-           (void) lookup_name (s->wild_statement.filename);
+           lookup_name (s->wild_statement.filename);
          open_input_bfds (s->wild_statement.children.head, force);
          break;
        case lang_group_statement_enum:
@@ -2064,6 +1993,41 @@ lang_place_undefineds (void)
     insert_undefined (ptr->name);
 }
 
+/* Check for all readonly or some readwrite sections.  */
+
+static void
+check_input_sections
+  (lang_statement_union_type *s,
+   lang_output_section_statement_type *output_section_statement)
+{
+  for (; s != (lang_statement_union_type *) NULL; s = s->header.next)
+    {
+      switch (s->header.type)
+      {
+      case lang_wild_statement_enum:
+       walk_wild (&s->wild_statement, check_section_callback,
+                  output_section_statement);
+       if (! output_section_statement->all_input_readonly)
+         return;
+       break;
+      case lang_constructors_statement_enum:
+       check_input_sections (constructor_list.head,
+                             output_section_statement);
+       if (! output_section_statement->all_input_readonly)
+         return;
+       break;
+      case lang_group_statement_enum:
+       check_input_sections (s->group_statement.children.head,
+                             output_section_statement);
+       if (! output_section_statement->all_input_readonly)
+         return;
+       break;
+      default:
+       break;
+      }
+    }
+}
+
 /* Open input files and attach to output sections.  */
 
 static void
@@ -2084,6 +2048,23 @@ map_input_to_output_sections
                                        output_section_statement);
          break;
        case lang_output_section_statement_enum:
+         if (s->output_section_statement.constraint)
+           {
+             if (s->output_section_statement.constraint == -1)
+               break;
+             s->output_section_statement.all_input_readonly = TRUE;
+             check_input_sections (s->output_section_statement.children.head,
+                                   &s->output_section_statement);
+             if ((s->output_section_statement.all_input_readonly
+                  && s->output_section_statement.constraint == ONLY_IF_RW)
+                 || (!s->output_section_statement.all_input_readonly
+                     && s->output_section_statement.constraint == ONLY_IF_RO))
+               {
+                 s->output_section_statement.constraint = -1;
+                 break;
+               }
+           }
+
          map_input_to_output_sections (s->output_section_statement.children.head,
                                        target,
                                        &s->output_section_statement);
@@ -2158,6 +2139,8 @@ strip_excluded_output_sections (void)
       asection *s;
 
       os = &u->output_section_statement;
+      if (os->constraint == -1)
+       continue;
       s = os->bfd_section;
       if (s != NULL && (s->flags & SEC_EXCLUDE) != 0)
        {
@@ -2203,7 +2186,7 @@ print_output_section_statement
              ++len;
            }
 
-         minfo ("0x%V %W", section->vma, section->_raw_size);
+         minfo ("0x%V %W", section->vma, section->size);
 
          if (output_section_statement->load_base != NULL)
            {
@@ -2271,7 +2254,7 @@ print_input_statement (lang_input_statement_type *statm)
 }
 
 /* Print all symbols defined in a particular section.  This is called
-   via bfd_link_hash_traverse.  */
+   via bfd_link_hash_traverse, or by print_all_symbols.  */
 
 static bfd_boolean
 print_one_symbol (struct bfd_link_hash_entry *hash_entry, void *ptr)
@@ -2297,62 +2280,82 @@ print_one_symbol (struct bfd_link_hash_entry *hash_entry, void *ptr)
   return TRUE;
 }
 
+static void
+print_all_symbols (sec)
+     asection *sec;
+{
+  struct fat_user_section_struct *ud = get_userdata (sec);
+  struct map_symbol_def *def;
+
+  *ud->map_symbol_def_tail = 0;
+  for (def = ud->map_symbol_def_head; def; def = def->next)
+    print_one_symbol (def->entry, sec);
+}
+
 /* Print information about an input section to the map file.  */
 
 static void
 print_input_section (lang_input_section_type *in)
 {
   asection *i = in->section;
-  bfd_size_type size = i->_cooked_size != 0 ? i->_cooked_size : i->_raw_size;
+  bfd_size_type size = i->size;
 
   init_opb ();
   if (size != 0)
     {
-      print_space ();
+      int len;
+      bfd_vma addr;
 
+      print_space ();
       minfo ("%s", i->name);
 
-      if (i->output_section != NULL)
+      len = 1 + strlen (i->name);
+      if (len >= SECTION_NAME_MAP_LENGTH - 1)
        {
-         int len;
+         print_nl ();
+         len = 0;
+       }
+      while (len < SECTION_NAME_MAP_LENGTH)
+       {
+         print_space ();
+         ++len;
+       }
 
-         len = 1 + strlen (i->name);
-         if (len >= SECTION_NAME_MAP_LENGTH - 1)
-           {
-             print_nl ();
-             len = 0;
-           }
-         while (len < SECTION_NAME_MAP_LENGTH)
-           {
-             print_space ();
-             ++len;
-           }
+      if (i->output_section != NULL && (i->flags & SEC_EXCLUDE) == 0)
+       addr = i->output_section->vma + i->output_offset;
+      else
+       {
+         addr = print_dot;
+         size = 0;
+       }
 
-         minfo ("0x%V %W %B\n",
-                i->output_section->vma + i->output_offset, TO_ADDR (size),
-                i->owner);
+      minfo ("0x%V %W %B\n", addr, TO_ADDR (size), i->owner);
 
-         if (i->_cooked_size != 0 && i->_cooked_size != i->_raw_size)
-           {
-             len = SECTION_NAME_MAP_LENGTH + 3;
+      if (size != i->rawsize && i->rawsize != 0)
+       {
+         len = SECTION_NAME_MAP_LENGTH + 3;
 #ifdef BFD64
-             len += 16;
+         len += 16;
 #else
-             len += 8;
+         len += 8;
 #endif
-             while (len > 0)
-               {
-                 print_space ();
-                 --len;
-               }
-
-             minfo (_("%W (size before relaxing)\n"), i->_raw_size);
+         while (len > 0)
+           {
+             print_space ();
+             --len;
            }
 
-         bfd_link_hash_traverse (link_info.hash, print_one_symbol, i);
+         minfo (_("%W (size before relaxing)\n"), i->rawsize);
+       }
+
+      if (i->output_section != NULL && (i->flags & SEC_EXCLUDE) == 0)
+       {
+         if (command_line.reduce_memory_overheads)
+           bfd_link_hash_traverse (link_info.hash, print_one_symbol, i);
+         else
+           print_all_symbols (i);
 
-         print_dot = (i->output_section->vma + i->output_offset
-                      + TO_ADDR (size));
+         print_dot = addr + TO_ADDR (size);
        }
     }
 }
@@ -2486,7 +2489,7 @@ print_padding_statement (lang_padding_statement_type *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, (bfd_vma) s->size);
 
   if (s->fill->size != 0)
     {
@@ -2711,21 +2714,22 @@ insert_pad (lang_statement_union_type **ptr,
     }
   pad->padding_statement.output_offset = dot - output_section->vma;
   pad->padding_statement.size = alignment_needed;
-  output_section->_raw_size += alignment_needed;
+  output_section->size += alignment_needed;
 }
 
 /* Work out how much this section will move the dot point.  */
 
 static bfd_vma
-size_input_section (lang_statement_union_type **this_ptr,
-                   lang_output_section_statement_type *output_section_statement,
-                   fill_type *fill,
-                   bfd_vma dot)
+size_input_section
+  (lang_statement_union_type **this_ptr,
+   lang_output_section_statement_type *output_section_statement,
+   fill_type *fill,
+   bfd_vma dot)
 {
   lang_input_section_type *is = &((*this_ptr)->input_section);
   asection *i = is->section;
 
-  if (!is->ifile->just_syms_flag)
+  if (!is->ifile->just_syms_flag && (i->flags & SEC_EXCLUDE) == 0)
     {
       unsigned int alignment_needed;
       asection *o;
@@ -2755,11 +2759,8 @@ size_input_section (lang_statement_union_type **this_ptr,
       i->output_offset = dot - o->vma;
 
       /* Mark how big the output section must be to contain this now.  */
-      if (i->_cooked_size != 0)
-       dot += TO_ADDR (i->_cooked_size);
-      else
-       dot += TO_ADDR (i->_raw_size);
-      o->_raw_size = TO_SIZE (dot - o->vma);
+      dot += TO_ADDR (i->size);
+      o->size = TO_SIZE (dot - o->vma);
     }
   else
     {
@@ -2769,10 +2770,11 @@ size_input_section (lang_statement_union_type **this_ptr,
   return dot;
 }
 
-#define IGNORE_SECTION(bfd, s) \
-  (((bfd_get_section_flags (bfd, s) & (SEC_ALLOC | SEC_NEVER_LOAD))    \
-    != SEC_ALLOC)                                                      \
-   || bfd_section_size (bfd, s) == 0)
+#define IGNORE_SECTION(s) \
+  (((s->flags & SEC_THREAD_LOCAL) != 0                         \
+    ? (s->flags & (SEC_LOAD | SEC_NEVER_LOAD)) != SEC_LOAD     \
+    : (s->flags & (SEC_ALLOC | SEC_NEVER_LOAD)) != SEC_ALLOC)  \
+   || s->size == 0)
 
 /* Check to see if any allocated sections overlap with other allocated
    sections.  This can happen when the linker script specifically specifies
@@ -2789,7 +2791,7 @@ lang_check_section_addresses (void)
       asection *os;
 
       /* Ignore sections which are not loaded or which have no contents.  */
-      if (IGNORE_SECTION (output_bfd, s))
+      if (IGNORE_SECTION (s))
        continue;
 
       /* Once we reach section 's' stop our seach.  This prevents two
@@ -2803,7 +2805,7 @@ lang_check_section_addresses (void)
          bfd_vma os_end;
 
          /* Only consider loadable sections with real contents.  */
-         if (IGNORE_SECTION (output_bfd, os))
+         if (IGNORE_SECTION (os))
            continue;
 
          /* We must check the sections' LMA addresses not their
@@ -2811,8 +2813,8 @@ lang_check_section_addresses (void)
             overlapping VMAs but they must have distinct LMAs.  */
          s_start = bfd_section_lma (output_bfd, s);
          os_start = bfd_section_lma (output_bfd, os);
-         s_end = s_start + TO_ADDR (bfd_section_size (output_bfd, s)) - 1;
-         os_end = os_start + TO_ADDR (bfd_section_size (output_bfd, os)) - 1;
+         s_end = s_start + TO_ADDR (s->size) - 1;
+         os_end = os_start + TO_ADDR (os->size) - 1;
 
          /* Look for an overlap.  */
          if ((s_end < os_start) || (s_start > os_end))
@@ -2847,7 +2849,8 @@ os_region_check (lang_output_section_statement_type *os,
     {
       if (tree != NULL)
        {
-         einfo (_("%X%P: address 0x%v of %B section %s is not within region %s\n"),
+         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,
@@ -2902,15 +2905,16 @@ lang_size_sections_1
 
                if (os->children.head == NULL
                    || os->children.head->header.next != NULL
-                   || os->children.head->header.type != lang_input_section_enum)
-                 einfo (_("%P%X: Internal error on COFF shared library section %s\n"),
-                        os->name);
+                   || (os->children.head->header.type
+                       != lang_input_section_enum))
+                 einfo (_("%P%X: Internal error on COFF shared library"
+                          " section %s\n"), 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;
+               os->bfd_section->size = input->size;
                break;
              }
 
@@ -2926,10 +2930,10 @@ lang_size_sections_1
                    /* No address specified for this section, get one
                       from the region specification.  */
                    if (os->region == NULL
-                       || (((bfd_get_section_flags (output_bfd, os->bfd_section)
-                             & (SEC_ALLOC | SEC_LOAD)) != 0)
+                       || ((os->bfd_section->flags & (SEC_ALLOC | SEC_LOAD))
                            && os->region->name[0] == '*'
-                           && strcmp (os->region->name, DEFAULT_MEMORY_REGION) == 0))
+                           && strcmp (os->region->name,
+                                      DEFAULT_MEMORY_REGION) == 0))
                      {
                        os->region = lang_memory_default (os->bfd_section);
                      }
@@ -2937,10 +2941,11 @@ lang_size_sections_1
                    /* If a loadable section is using the default memory
                       region, and some non default memory regions were
                       defined, issue an error message.  */
-                   if (!IGNORE_SECTION (output_bfd, os->bfd_section)
+                   if (!IGNORE_SECTION (os->bfd_section)
                        && ! link_info.relocatable
                        && check_regions
-                       && strcmp (os->region->name, DEFAULT_MEMORY_REGION) == 0
+                       && strcmp (os->region->name,
+                                  DEFAULT_MEMORY_REGION) == 0
                        && lang_memory_region_list != NULL
                        && (strcmp (lang_memory_region_list->name,
                                    DEFAULT_MEMORY_REGION) != 0
@@ -2951,16 +2956,18 @@ lang_size_sections_1
                           default memory region we can end up creating an
                           excessively large binary, or even seg faulting when
                           attempting to perform a negative seek.  See
-                            http://sources.redhat.com/ml/binutils/2003-04/msg00423.html
+                          sources.redhat.com/ml/binutils/2003-04/msg00423.html
                           for an example of this.  This behaviour can be
                           overridden by the using the --no-check-sections
                           switch.  */
                        if (command_line.check_section_addresses)
-                         einfo (_("%P%F: error: no memory region specified for loadable section `%s'\n"),
+                         einfo (_("%P%F: error: no memory region specified"
+                                  " for loadable section `%s'\n"),
                                 bfd_get_section_name (output_bfd,
                                                       os->bfd_section));
                        else
-                         einfo (_("%P: warning: no memory region specified for loadable section `%s'\n"),
+                         einfo (_("%P: warning: no memory region specified"
+                                  " for loadable section `%s'\n"),
                                 bfd_get_section_name (output_bfd,
                                                       os->bfd_section));
                      }
@@ -2976,7 +2983,8 @@ lang_size_sections_1
                                           os->bfd_section->alignment_power);
 
                        if (dot != olddot && config.warn_section_align)
-                         einfo (_("%P: warning: changing start of section %s by %u bytes\n"),
+                         einfo (_("%P: warning: changing start of section"
+                                  " %s by %u bytes\n"),
                                 os->name, (unsigned int) (dot - olddot));
                      }
                  }
@@ -2992,7 +3000,8 @@ lang_size_sections_1
                    os->processed = 0;
                    
                    if (!r.valid_p)
-                     einfo (_("%F%S: non constant or forward reference address expression for section %s\n"),
+                     einfo (_("%F%S: non constant or forward reference"
+                              " address expression for section %s\n"),
                             os->name);
 
                    dot = r.value + r.section->bfd_section->vma;
@@ -3015,21 +3024,23 @@ lang_size_sections_1
            /* Put the section within the requested block size, or
               align at the block boundary.  */
            after = ((os->bfd_section->vma
-                     + TO_ADDR (os->bfd_section->_raw_size)
+                     + TO_ADDR (os->bfd_section->size)
                      + os->block_value - 1)
                     & - (bfd_vma) os->block_value);
 
            if (bfd_is_abs_section (os->bfd_section))
              ASSERT (after == os->bfd_section->vma);
-           else if ((os->bfd_section->flags & SEC_HAS_CONTENTS) == 0
-                    && (os->bfd_section->flags & SEC_THREAD_LOCAL)
-                    && ! link_info.relocatable)
-             os->bfd_section->_raw_size = 0;
            else
-             os->bfd_section->_raw_size
+             os->bfd_section->size
                = TO_SIZE (after - os->bfd_section->vma);
 
-           dot = os->bfd_section->vma + TO_ADDR (os->bfd_section->_raw_size);
+           dot = os->bfd_section->vma;
+           /* .tbss sections effectively have zero size.  */
+           if ((os->bfd_section->flags & SEC_HAS_CONTENTS) != 0
+               || (os->bfd_section->flags & SEC_THREAD_LOCAL) == 0
+               || link_info.relocatable)
+             dot += TO_ADDR (os->bfd_section->size);
+
            os->processed = 1;
 
            if (os->update_dot_tree != 0)
@@ -3045,10 +3056,8 @@ lang_size_sections_1
               addresses of sections after it. We have to update
               dot.  */
            if (os->region != NULL
-               && ((bfd_get_section_flags (output_bfd, os->bfd_section)
-                    & SEC_NEVER_LOAD) == 0
-                   || (bfd_get_section_flags (output_bfd, os->bfd_section)
-                       & (SEC_ALLOC | SEC_LOAD))))
+               && ((os->bfd_section->flags & SEC_NEVER_LOAD) == 0
+                   || (os->bfd_section->flags & (SEC_ALLOC | SEC_LOAD))))
              {
                os->region->current = dot;
 
@@ -3067,7 +3076,7 @@ lang_size_sections_1
                    /* Set load_base, which will be handled later.  */
                    os->load_base = exp_intop (os->lma_region->current);
                    os->lma_region->current +=
-                     TO_ADDR (os->bfd_section->_raw_size);
+                     TO_ADDR (os->bfd_section->size);
                    if (check_regions)
                      os_region_check (os, os->lma_region, NULL,
                                       os->bfd_section->lma);
@@ -3118,7 +3127,7 @@ lang_size_sections_1
            if (size < TO_SIZE ((unsigned) 1))
              size = TO_SIZE ((unsigned) 1);
            dot += TO_ADDR (size);
-           output_section_statement->bfd_section->_raw_size += size;
+           output_section_statement->bfd_section->size += size;
            /* The output section gets contents, and then we inspect for
               any flags set in the input script which override any ALLOC.  */
            output_section_statement->bfd_section->flags |= SEC_HAS_CONTENTS;
@@ -3140,7 +3149,7 @@ lang_size_sections_1
              output_section_statement->bfd_section;
            size = bfd_get_reloc_size (s->reloc_statement.howto);
            dot += TO_ADDR (size);
-           output_section_statement->bfd_section->_raw_size += size;
+           output_section_statement->bfd_section->size += size;
          }
          break;
 
@@ -3165,12 +3174,7 @@ lang_size_sections_1
            asection *i;
 
            i = (*prev)->input_section.section;
-           if (! relax)
-             {
-               if (i->_cooked_size == 0)
-                 i->_cooked_size = i->_raw_size;
-             }
-           else
+           if (relax)
              {
                bfd_boolean again;
 
@@ -3207,7 +3211,8 @@ lang_size_sections_1
                  {
                    /* If we don't have an output section, then just adjust
                       the default memory address.  */
-                   lang_memory_region_lookup (DEFAULT_MEMORY_REGION, FALSE)->current = newdot;
+                   lang_memory_region_lookup (DEFAULT_MEMORY_REGION,
+                                              FALSE)->current = newdot;
                  }
                else
                  {
@@ -3224,7 +3229,8 @@ lang_size_sections_1
                /* If dot is advanced, this implies that the section should
                   have space allocated to it, unless the user has explicitly
                   stated that the section should never be loaded.  */
-               if (!(output_section_statement->flags & (SEC_NEVER_LOAD | SEC_ALLOC)))
+               if (!(output_section_statement->flags
+                     & (SEC_NEVER_LOAD | SEC_ALLOC)))
                  output_section_statement->bfd_section->flags |= SEC_ALLOC;
 
                dot = newdot;
@@ -3280,7 +3286,6 @@ lang_size_sections
    bfd_boolean check_regions)
 {
   bfd_vma result;
-  asection *o;
 
   /* Callers of exp_fold_tree need to increment this.  */
   lang_statement_iteration++;
@@ -3288,7 +3293,19 @@ lang_size_sections
   exp_data_seg.phase = exp_dataseg_none;
   result = lang_size_sections_1 (s, output_section_statement, prev, fill,
                                 dot, relax, check_regions);
-  if (exp_data_seg.phase == exp_dataseg_end_seen)
+  if (exp_data_seg.phase == exp_dataseg_end_seen
+      && link_info.relro && exp_data_seg.relro_end)
+    {
+      /* If DATA_SEGMENT_ALIGN DATA_SEGMENT_RELRO_END pair was seen, try
+        to put exp_data_seg.relro on a (common) page boundary.  */
+
+      exp_data_seg.phase = exp_dataseg_relro_adjust;
+      result = lang_size_sections_1 (s, output_section_statement, prev, fill,
+                                    dot, relax, check_regions);
+      link_info.relro_start = exp_data_seg.base;
+      link_info.relro_end = exp_data_seg.relro_end;
+    }
+  else 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.  */
@@ -3308,14 +3325,6 @@ lang_size_sections
        }
     }
 
-  /* Some backend relaxers want to refer to the output section size.  Give
-     them a section size that does not change on the next call while they
-     relax.  We can't set this at top because lang_reset_memory_regions
-     which is called before we get here, sets _raw_size to 0 on relaxing
-     rounds.  */
-  for (o = output_bfd->sections; o != NULL; o = o->next)
-    o->_cooked_size = o->_raw_size;
-
   return result;
 }
 
@@ -3347,11 +3356,12 @@ lang_do_assignments_1
            if (os->bfd_section != NULL)
              {
                dot = os->bfd_section->vma;
-               (void) lang_do_assignments_1 (os->children.head, os,
-                                             os->fill, dot);
-               dot = (os->bfd_section->vma
-                      + TO_ADDR (os->bfd_section->_raw_size));
-
+               lang_do_assignments_1 (os->children.head, os, os->fill, dot);
+               /* .tbss sections effectively have zero size.  */
+               if ((os->bfd_section->flags & SEC_HAS_CONTENTS) != 0
+                   || (os->bfd_section->flags & SEC_THREAD_LOCAL) == 0
+                   || link_info.relocatable)
+                 dot += TO_ADDR (os->bfd_section->size);
              }
            if (os->load_base)
              {
@@ -3437,10 +3447,8 @@ lang_do_assignments_1
          {
            asection *in = s->input_section.section;
 
-           if (in->_cooked_size != 0)
-             dot += TO_ADDR (in->_cooked_size);
-           else
-             dot += TO_ADDR (in->_raw_size);
+           if ((in->flags & SEC_EXCLUDE) == 0)
+             dot += TO_ADDR (in->size);
          }
          break;
 
@@ -3482,10 +3490,11 @@ lang_do_assignments_1
 }
 
 void
-lang_do_assignments (lang_statement_union_type *s,
-                    lang_output_section_statement_type *output_section_statement,
-                    fill_type *fill,
-                    bfd_vma dot)
+lang_do_assignments
+  (lang_statement_union_type *s,
+   lang_output_section_statement_type *output_section_statement,
+   fill_type *fill,
+   bfd_vma dot)
 {
   /* Callers of exp_fold_tree need to increment this.  */
   lang_statement_iteration++;
@@ -3530,10 +3539,7 @@ lang_set_startof (void)
       if (h != NULL && h->type == bfd_link_hash_undefined)
        {
          h->type = bfd_link_hash_defined;
-         if (s->_cooked_size != 0)
-           h->u.def.value = TO_ADDR (s->_cooked_size);
-         else
-           h->u.def.value = TO_ADDR (s->_raw_size);
+         h->u.def.value = TO_ADDR (s->size);
          h->u.def.section = bfd_abs_section_ptr;
        }
 
@@ -3599,7 +3605,8 @@ lang_finish (void)
          if (ts != NULL)
            {
              if (warn)
-               einfo (_("%P: warning: cannot find entry symbol %s; defaulting to %V\n"),
+               einfo (_("%P: warning: cannot find entry symbol %s;"
+                        " defaulting to %V\n"),
                       entry_symbol.name,
                       bfd_get_section_vma (output_bfd, ts));
              if (! bfd_set_start_address (output_bfd,
@@ -3610,13 +3617,15 @@ lang_finish (void)
          else
            {
              if (warn)
-               einfo (_("%P: warning: cannot find entry symbol %s; not setting start address\n"),
+               einfo (_("%P: warning: cannot find entry symbol %s;"
+                        " not setting start address\n"),
                       entry_symbol.name);
            }
        }
     }
 
-  bfd_hash_table_free (&lang_definedness_table);
+  /* Don't bfd_hash_table_free (&lang_definedness_table);
+     map file output may result in a call of lang_track_definedness.  */
 }
 
 /* This is a small function used when we want to ignore errors from
@@ -3642,8 +3651,9 @@ lang_check (void)
   for (file = file_chain.head; file != NULL; file = file->input_statement.next)
     {
       input_bfd = file->input_statement.the_bfd;
-      compatible = bfd_arch_get_compatible (input_bfd, output_bfd,
-                                           command_line.accept_unknown_input_arch);
+      compatible
+       = bfd_arch_get_compatible (input_bfd, output_bfd,
+                                  command_line.accept_unknown_input_arch);
 
       /* In general it is not possible to perform a relocatable
         link between differing object formats when the input
@@ -3656,7 +3666,8 @@ lang_check (void)
              || 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"),
+         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.  */
@@ -3665,7 +3676,8 @@ lang_check (void)
       if (compatible == NULL)
        {
          if (command_line.warn_mismatch)
-           einfo (_("%P: warning: %s architecture of input file `%B' is incompatible with %s output\n"),
+           einfo (_("%P: warning: %s architecture of input file `%B'"
+                    " is incompatible with %s output\n"),
                   bfd_printable_name (input_bfd), input_bfd,
                   bfd_printable_name (output_bfd));
        }
@@ -3686,8 +3698,8 @@ lang_check (void)
          if (! bfd_merge_private_bfd_data (input_bfd, output_bfd))
            {
              if (command_line.warn_mismatch)
-               einfo (_("%E%X: failed to merge target specific data of file %B\n"),
-                      input_bfd);
+               einfo (_("%P%X: failed to merge target specific data"
+                        " of file %B\n"), input_bfd);
            }
          if (! command_line.warn_mismatch)
            bfd_set_error_handler (pfn);
@@ -3741,8 +3753,8 @@ lang_one_common (struct bfd_link_hash_entry *h, void *info)
   section = h->u.c.p->section;
 
   /* Increase the size of the section to align the common sym.  */
-  section->_cooked_size += ((bfd_vma) 1 << (power_of_two + opb_shift)) - 1;
-  section->_cooked_size &= (- (bfd_vma) 1 << (power_of_two + opb_shift));
+  section->size += ((bfd_vma) 1 << (power_of_two + opb_shift)) - 1;
+  section->size &= (- (bfd_vma) 1 << (power_of_two + opb_shift));
 
   /* Adjust the alignment if necessary.  */
   if (power_of_two > section->alignment_power)
@@ -3751,10 +3763,10 @@ lang_one_common (struct bfd_link_hash_entry *h, void *info)
   /* Change the symbol from common to defined.  */
   h->type = bfd_link_hash_defined;
   h->u.def.section = section;
-  h->u.def.value = section->_cooked_size;
+  h->u.def.value = section->size;
 
   /* Increase the size of the section.  */
-  section->_cooked_size += size;
+  section->size += size;
 
   /* Make sure the section is allocated in memory, and make sure that
      it is no longer a common section.  */
@@ -3830,9 +3842,10 @@ lang_place_orphans (void)
                 around for a sensible place for it to go.  */
 
              if (file->just_syms_flag)
-               {
-                 abort ();
-               }
+               abort ();
+
+             if ((s->flags & SEC_EXCLUDE) != 0)
+               s->output_section = bfd_abs_section_ptr;
              else if (strcmp (s->name, "COMMON") == 0)
                {
                  /* This is a lonely common section which must have
@@ -3847,7 +3860,8 @@ lang_place_orphans (void)
                          /* This message happens when using the
                              svr3.ifile linker script, so I have
                              disabled it.  */
-                         info_msg (_("%P: no [COMMON] command, defaulting to .bss\n"));
+                         info_msg (_("%P: no [COMMON] command,"
+                                     " defaulting to .bss\n"));
 #endif
                          default_common_section =
                            lang_output_section_statement_lookup (".bss");
@@ -3937,24 +3951,6 @@ lang_for_each_file (void (*func) (lang_input_statement_type *))
     }
 }
 
-#if 0
-
-/* Not used.  */
-
-void
-lang_for_each_input_section (void (*func) (bfd *ab, asection *as))
-{
-  LANG_FOR_EACH_INPUT_STATEMENT (f)
-    {
-      asection *s;
-
-      for (s = f->the_bfd->sections; s != NULL; s = s->next)
-       func (f->the_bfd, s);
-    }
-}
-
-#endif
-
 void
 ldlang_add_file (lang_input_statement_type *entry)
 {
@@ -4025,13 +4021,15 @@ lang_enter_output_section_statement (const char *output_section_statement_name,
                                     enum section_type sectype,
                                     etree_type *align,
                                     etree_type *subalign,
-                                    etree_type *ebase)
+                                    etree_type *ebase,
+                                    int constraint)
 {
   lang_output_section_statement_type *os;
 
   current_section =
    os =
-    lang_output_section_statement_lookup (output_section_statement_name);
+    lang_output_section_statement_lookup_1 (output_section_statement_name,
+                                           constraint);
 
   /* Add this statement to tree.  */
 #if 0
@@ -4085,11 +4083,14 @@ lang_reset_memory_regions (void)
     }
 
   for (o = output_bfd->sections; o != NULL; o = o->next)
-    o->_raw_size = 0;
+    {
+      /* Save the last size for possible use by bfd_relax_section.  */
+      o->rawsize = o->size;
+      o->size = 0;
+    }
 }
 
-/* If the wild pattern was marked KEEP, the member sections
-   should be as well.  */
+/* Worker for lang_gc_sections_1.  */
 
 static void
 gc_section_callback (lang_wild_statement_type *ptr,
@@ -4098,18 +4099,12 @@ gc_section_callback (lang_wild_statement_type *ptr,
                     lang_input_statement_type *file ATTRIBUTE_UNUSED,
                     void *data ATTRIBUTE_UNUSED)
 {
+  /* If the wild pattern was marked KEEP, the member sections
+     should be as well.  */
   if (ptr->keep_sections)
     section->flags |= SEC_KEEP;
 }
 
-/* Handle a wild statement, marking it against GC.  */
-
-static void
-lang_gc_wild (lang_wild_statement_type *s)
-{
-  walk_wild (s, gc_section_callback, NULL);
-}
-
 /* Iterate over sections marking them against GC.  */
 
 static void
@@ -4120,7 +4115,7 @@ lang_gc_sections_1 (lang_statement_union_type *s)
       switch (s->header.type)
        {
        case lang_wild_statement_enum:
-         lang_gc_wild (&s->wild_statement);
+         walk_wild (&s->wild_statement, gc_section_callback, NULL);
          break;
        case lang_constructors_statement_enum:
          lang_gc_sections_1 (constructor_list.head);
@@ -4164,7 +4159,22 @@ lang_gc_sections (void)
        }
     }
 
-  bfd_gc_sections (output_bfd, &link_info);
+  /* SEC_EXCLUDE is ignored when doing a relocatable link, except in
+     the special case of debug info.  (See bfd/stabs.c)
+     Twiddle the flag here, to simplify later linker code.  */
+  if (link_info.relocatable)
+    {
+      LANG_FOR_EACH_INPUT_STATEMENT (f)
+       {
+         asection *sec;
+         for (sec = f->the_bfd->sections; sec != NULL; sec = sec->next)
+           if ((sec->flags & SEC_DEBUGGING) == 0)
+             sec->flags &= ~SEC_EXCLUDE;
+       }
+    }
+
+  if (command_line.gc_sections)
+    bfd_gc_sections (output_bfd, &link_info);
 }
 
 void
@@ -4182,7 +4192,8 @@ lang_process (void)
   /* Add to the hash table all undefineds on the command line.  */
   lang_place_undefineds ();
 
-  already_linked_table_init ();
+  if (!bfd_section_already_linked_table_init ())
+    einfo (_("%P%F: Failed to create hash table\n"));
 
   /* Create a bfd for each input file.  */
   current_target = default_target;
@@ -4194,7 +4205,7 @@ lang_process (void)
 
   ldemul_after_open ();
 
-  already_linked_table_free ();
+  bfd_section_already_linked_table_free ();
 
   /* Make sure that we're not mixing architectures.  We call this
      after all the input files have been opened, but before we do any
@@ -4212,14 +4223,7 @@ lang_process (void)
   ldctor_build_sets ();
 
   /* Remove unreferenced sections if asked to.  */
-  if (command_line.gc_sections)
-    lang_gc_sections ();
-
-  /* If there were any SEC_MERGE sections, finish their merging, so that
-     section sizes can be computed.  This has to be done after GC of sections,
-     so that GCed sections are not merged, but before assigning output
-     sections, since removing whole input sections is hard then.  */
-  bfd_merge_sections (output_bfd, &link_info);
+  lang_gc_sections ();
 
   /* Size up the common data.  */
   lang_common ();
@@ -4233,8 +4237,16 @@ lang_process (void)
 
   if (! link_info.relocatable)
     {
+      asection *found;
+
+      /* Merge SEC_MERGE sections.  This has to be done after GC of
+        sections, so that GCed sections are not merged, but before
+        assigning dynamic symbols, since removing whole input sections
+        is hard then.  */
+      bfd_merge_sections (output_bfd, &link_info);
+
       /* Look for a text section and set the readonly attribute in it.  */
-      asection *found = bfd_get_section_by_name (output_bfd, ".text");
+      found = bfd_get_section_by_name (output_bfd, ".text");
 
       if (found != NULL)
        {
@@ -4281,7 +4293,7 @@ lang_process (void)
                               NULL, 0);
 
          /* We must do this after lang_do_assignments, because it uses
-            _raw_size.  */
+            size.  */
          lang_reset_memory_regions ();
 
          /* Perform another relax pass - this time we know where the
@@ -4530,8 +4542,9 @@ lang_get_regions (lang_memory_region_type **region,
 {
   *lma_region = lang_memory_region_lookup (lma_memspec, FALSE);
 
-  /* If no runtime region or VMA has been specified, but the load region has
-     been specified, then use the load region for the runtime region as well.  */
+  /* If no runtime region or VMA has been specified, but the load region
+     has been specified, then use the load region for the runtime region
+     as well.  */
   if (lma_memspec != NULL
       && ! have_vma
       && strcmp (memspec, DEFAULT_MEMORY_REGION) == 0)
@@ -4615,7 +4628,7 @@ lang_abs_symbol_at_end_of (const char *secname, const char *name)
        h->u.def.value = 0;
       else
        h->u.def.value = (bfd_get_section_vma (output_bfd, sec)
-                         + TO_ADDR (bfd_section_size (output_bfd, sec)));
+                         + TO_ADDR (sec->size));
 
       h->u.def.section = bfd_abs_section_ptr;
     }
@@ -4733,6 +4746,8 @@ lang_record_phdrs (void)
          lang_output_section_phdr_list *pl;
 
          os = &u->output_section_statement;
+         if (os->constraint == -1)
+           continue;
 
          pl = os->phdrs;
          if (pl != NULL)
@@ -4792,7 +4807,8 @@ lang_record_phdrs (void)
     {
       lang_output_section_phdr_list *pl;
 
-      if (u->output_section_statement.bfd_section == NULL)
+      if (u->output_section_statement.constraint == -1
+         || u->output_section_statement.bfd_section == NULL)
        continue;
 
       for (pl = u->output_section_statement.phdrs;
@@ -4864,7 +4880,7 @@ lang_enter_overlay_section (const char *name)
   etree_type *size;
 
   lang_enter_output_section_statement (name, overlay_vma, normal_section,
-                                      0, overlay_subalign, 0);
+                                      0, overlay_subalign, 0, 0);
 
   /* If this is the first section, then base the VMA of future
      sections on this one.  This will work correctly even if `.' is
@@ -5327,7 +5343,8 @@ lang_register_vers_node (const char *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"));
+      einfo (_("%X%P: anonymous version tag cannot be combined"
+              " with other version tags\n"));
       free (version);
       return;
     }
@@ -5355,16 +5372,17 @@ lang_register_vers_node (const char *name,
              while (e2 && strcmp (e1->symbol, e2->symbol) == 0)
                {
                  if (e1->mask == e2->mask)
-                   einfo (_("%X%P: duplicate expression `%s' in version information\n"),
-                          e1->symbol);
+                   einfo (_("%X%P: duplicate expression `%s'"
+                            " in version information\n"), e1->symbol);
                  e2 = e2->next;
                }
            }
          else if (!e1->symbol)
            for (e2 = t->locals.remaining; e2 != NULL; e2 = e2->next)
-             if (strcmp (e1->pattern, e2->pattern) == 0 && e1->mask == e2->mask)
-               einfo (_("%X%P: duplicate expression `%s' in version information\n"),
-                      e1->pattern);
+             if (strcmp (e1->pattern, e2->pattern) == 0
+                 && e1->mask == e2->mask)
+               einfo (_("%X%P: duplicate expression `%s'"
+                        " in version information\n"), e1->pattern);
        }
     }
 
@@ -5380,16 +5398,18 @@ lang_register_vers_node (const char *name,
              while (e2 && strcmp (e1->symbol, e2->symbol) == 0)
                {
                  if (e1->mask == e2->mask)
-                   einfo (_("%X%P: duplicate expression `%s' in version information\n"),
+                   einfo (_("%X%P: duplicate expression `%s'"
+                            " in version information\n"),
                           e1->symbol);
                  e2 = e2->next;
                }
            }
          else if (!e1->symbol)
            for (e2 = t->globals.remaining; e2 != NULL; e2 = e2->next)
-             if (strcmp (e1->pattern, e2->pattern) == 0 && e1->mask == e2->mask)
-               einfo (_("%X%P: duplicate expression `%s' in version information\n"),
-                      e1->pattern);
+             if (strcmp (e1->pattern, e2->pattern) == 0
+                 && e1->mask == e2->mask)
+               einfo (_("%X%P: duplicate expression `%s'"
+                        " in version information\n"), e1->pattern);
        }
     }
 
@@ -5447,7 +5467,7 @@ lang_do_version_exports_section (void)
       if (sec == NULL)
        continue;
 
-      len = bfd_section_size (is->the_bfd, sec);
+      len = sec->size;
       contents = xmalloc (len);
       if (!bfd_get_section_contents (is->the_bfd, sec, contents, 0, len))
        einfo (_("%X%P: unable to read .exports section contents\n"), sec);
@@ -5462,8 +5482,7 @@ lang_do_version_exports_section (void)
       /* Do not free the contents, as we used them creating the regex.  */
 
       /* Do not include this section in the link.  */
-      bfd_set_section_flags (is->the_bfd, sec,
-       bfd_get_section_flags (is->the_bfd, sec) | SEC_EXCLUDE);
+      sec->flags |= SEC_EXCLUDE;
     }
 
   lreg = lang_new_vers_pattern (NULL, "*", NULL);