bfd/
[external/binutils.git] / ld / ldlang.c
index b343c27..6cc05a6 100644 (file)
@@ -1,6 +1,6 @@
 /* Linker command language support.
    Copyright 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
-   2001, 2002, 2003
+   2001, 2002, 2003, 2004
    Free Software Foundation, Inc.
 
    This file is part of GLD, the Gnu Linker.
@@ -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);
@@ -622,7 +643,8 @@ lang_output_section_statement_lookup (const char *const name)
 
       lookup->next = NULL;
       lookup->bfd_section = NULL;
-      lookup->processed = FALSE;
+      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)
@@ -775,6 +857,10 @@ exp_init_os (etree_type *exp)
       exp_init_os (exp->trinary.rhs);
       break;
 
+    case etree_assert:
+      exp_init_os (exp->assert_s.child);
+      break;
+      
     case etree_unary:
       exp_init_os (exp->unary.child);
       break;
@@ -800,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.  */
@@ -847,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.
@@ -1006,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.  */
@@ -1097,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)
@@ -1261,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
@@ -1307,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.  */
@@ -1320,17 +1252,22 @@ lookup_name (const char *name)
        search != NULL;
        search = (lang_input_statement_type *) search->next_real_file)
     {
-      if (search->filename == NULL && name == NULL)
+      /* Use the local_sym_name as the name of the file that has
+        already been loaded as filename might have been transformed
+        via the search directory lookup mechanism.  */
+      const char * filename = search->local_sym_name;
+
+      if (filename == NULL && name == NULL)
        return search;
-      if (search->filename != NULL
+      if (filename != NULL
          && name != NULL
-         && strcmp (search->filename, name) == 0)
+         && strcmp (filename, name) == 0)
        break;
     }
 
   if (search == NULL)
-    search = new_afile (name, lang_input_file_is_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
@@ -1724,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;
                }
@@ -1794,6 +1732,30 @@ ldlang_open_output (lang_statement_union_type *statement)
     }
 }
 
+/* Convert between addresses in bytes and sizes in octets.
+   For currently supported targets, octets_per_byte is always a power
+   of two, so we can use shifts.  */
+#define TO_ADDR(X) ((X) >> opb_shift)
+#define TO_SIZE(X) ((X) << opb_shift)
+
+/* Support the above.  */
+static unsigned int opb_shift = 0;
+
+static void
+init_opb (void)
+{
+  unsigned x = bfd_arch_mach_octets_per_byte (ldfile_output_architecture,
+                                             ldfile_output_machine);
+  opb_shift = 0;
+  if (x > 1)
+    while ((x & 1) == 0)
+      {
+       x >>= 1;
+       ++opb_shift;
+      }
+  ASSERT (x == 1);
+}
+
 /* Open all the input files.  */
 
 static void
@@ -1813,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:
@@ -2031,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
@@ -2051,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);
@@ -2065,10 +2079,14 @@ map_input_to_output_sections
                                        target,
                                        output_section_statement);
          break;
+       case lang_data_statement_enum:
+         /* Make sure that any sections mentioned in the expression
+            are initialized.  */
+         exp_init_os (s->data_statement.exp);
+         /* FALLTHROUGH */
        case lang_fill_statement_enum:
        case lang_input_section_enum:
        case lang_object_symbols_statement_enum:
-       case lang_data_statement_enum:
        case lang_reloc_statement_enum:
        case lang_padding_statement_enum:
        case lang_input_statement_enum:
@@ -2121,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)
        {
@@ -2166,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)
            {
@@ -2234,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)
@@ -2260,61 +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;
-  unsigned opb = bfd_arch_mach_octets_per_byte (ldfile_output_architecture,
-                                               ldfile_output_machine);
+  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)
+       {
+         print_nl ();
+         len = 0;
+       }
+      while (len < SECTION_NAME_MAP_LENGTH)
        {
-         int len;
+         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, size / opb,
-                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 + size / opb;
+         print_dot = addr + TO_ADDR (size);
        }
     }
 }
@@ -2337,9 +2378,8 @@ print_data_statement (lang_data_statement_type *data)
   bfd_vma addr;
   bfd_size_type size;
   const char *name;
-  unsigned opb = bfd_arch_mach_octets_per_byte (ldfile_output_architecture,
-                                               ldfile_output_machine);
 
+  init_opb ();
   for (i = 0; i < SECTION_NAME_MAP_LENGTH; i++)
     print_space ();
 
@@ -2383,8 +2423,7 @@ print_data_statement (lang_data_statement_type *data)
 
   print_nl ();
 
-  print_dot = addr + size / opb;
-
+  print_dot = addr + TO_ADDR (size);
 }
 
 /* Print an address statement.  These are generated by options like
@@ -2406,9 +2445,8 @@ print_reloc_statement (lang_reloc_statement_type *reloc)
   int i;
   bfd_vma addr;
   bfd_size_type size;
-  unsigned opb = bfd_arch_mach_octets_per_byte (ldfile_output_architecture,
-                                               ldfile_output_machine);
 
+  init_opb ();
   for (i = 0; i < SECTION_NAME_MAP_LENGTH; i++)
     print_space ();
 
@@ -2429,7 +2467,7 @@ print_reloc_statement (lang_reloc_statement_type *reloc)
 
   print_nl ();
 
-  print_dot = addr + size / opb;
+  print_dot = addr + TO_ADDR (size);
 }
 
 static void
@@ -2437,9 +2475,8 @@ print_padding_statement (lang_padding_statement_type *s)
 {
   int len;
   bfd_vma addr;
-  unsigned opb = bfd_arch_mach_octets_per_byte (ldfile_output_architecture,
-                                               ldfile_output_machine);
 
+  init_opb ();
   minfo (" *fill*");
 
   len = sizeof " *fill*" - 1;
@@ -2452,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)
     {
@@ -2464,7 +2501,7 @@ print_padding_statement (lang_padding_statement_type *s)
 
   print_nl ();
 
-  print_dot = addr + s->size / opb;
+  print_dot = addr + TO_ADDR (s->size);
 }
 
 static void
@@ -2677,24 +2714,23 @@ 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 opb = bfd_arch_mach_octets_per_byte (ldfile_output_architecture,
-                                                   ldfile_output_machine);
       unsigned int alignment_needed;
       asection *o;
 
@@ -2714,7 +2750,7 @@ size_input_section (lang_statement_union_type **this_ptr,
 
       if (alignment_needed != 0)
        {
-         insert_pad (this_ptr, fill, alignment_needed * opb, o, dot);
+         insert_pad (this_ptr, fill, TO_SIZE (alignment_needed), o, dot);
          dot += alignment_needed;
        }
 
@@ -2723,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 += i->_cooked_size / opb;
-      else
-       dot += i->_raw_size / opb;
-      o->_raw_size = (dot - o->vma) * opb;
+      dot += TO_ADDR (i->size);
+      o->size = TO_SIZE (dot - o->vma);
     }
   else
     {
@@ -2737,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_LOAD))  \
-    != (SEC_ALLOC | SEC_LOAD))                                 \
-   || 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
@@ -2750,7 +2784,6 @@ static void
 lang_check_section_addresses (void)
 {
   asection *s;
-  unsigned opb = bfd_octets_per_byte (output_bfd);
 
   /* Scan all sections in the output list.  */
   for (s = output_bfd->sections; s != NULL; s = s->next)
@@ -2758,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
@@ -2772,16 +2805,16 @@ 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
             VMA addresses because overlay sections can have
             overlapping VMAs but they must have distinct LMAs.  */
-         s_start  = bfd_section_lma (output_bfd, s);
+         s_start = bfd_section_lma (output_bfd, s);
          os_start = bfd_section_lma (output_bfd, os);
-         s_end    = s_start  + bfd_section_size (output_bfd, s) / opb - 1;
-         os_end   = os_start + bfd_section_size (output_bfd, os) / opb - 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))
@@ -2805,7 +2838,7 @@ _("%X%P: section %s [%V -> %V] overlaps section %s [%V -> %V]\n"),
 
 static void
 os_region_check (lang_output_section_statement_type *os,
-                struct memory_region_struct *region,
+                lang_memory_region_type *region,
                 etree_type *tree,
                 bfd_vma base)
 {
@@ -2816,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,
@@ -2846,9 +2880,6 @@ lang_size_sections_1
    bfd_boolean *relax,
    bfd_boolean check_regions)
 {
-  unsigned opb = bfd_arch_mach_octets_per_byte (ldfile_output_architecture,
-                                               ldfile_output_machine);
-
   /* Size up the sections from their constituent parts.  */
   for (; s != NULL; s = s->header.next)
     {
@@ -2874,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;
              }
 
@@ -2898,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);
                      }
@@ -2909,12 +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)
-                       && (bfd_get_section_flags (output_bfd, os->bfd_section)
-                           & SEC_NEVER_LOAD) == 0
+                   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
@@ -2925,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));
                      }
@@ -2950,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));
                      }
                  }
@@ -2958,12 +2992,16 @@ lang_size_sections_1
                  {
                    etree_value_type r;
 
+                   os->processed = -1;
                    r = exp_fold_tree (os->addr_tree,
                                       abs_output_section,
                                       lang_allocating_phase_enum,
                                       dot, &dot);
+                   os->processed = 0;
+                   
                    if (!r.valid_p)
-                     einfo (_("%F%S: non constant 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;
@@ -2985,22 +3023,25 @@ lang_size_sections_1
 
            /* Put the section within the requested block size, or
               align at the block boundary.  */
-           after = align_n (os->bfd_section->vma
-                            + os->bfd_section->_raw_size / opb,
-                            (bfd_vma) os->block_value);
+           after = ((os->bfd_section->vma
+                     + 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 =
-               (after - os->bfd_section->vma) * opb;
+             os->bfd_section->size
+               = TO_SIZE (after - os->bfd_section->vma);
 
-           dot = os->bfd_section->vma + os->bfd_section->_raw_size / opb;
-           os->processed = TRUE;
+           dot = os->bfd_section->vma;
+           /* .tbss sections effectively have zero size.  */
+           if ((os->bfd_section->flags & SEC_HAS_CONTENTS) != 0
+               || (os->bfd_section->flags & SEC_THREAD_LOCAL) == 0
+               || link_info.relocatable)
+             dot += TO_ADDR (os->bfd_section->size);
+
+           os->processed = 1;
 
            if (os->update_dot_tree != 0)
              exp_fold_tree (os->update_dot_tree, abs_output_section,
@@ -3015,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;
 
@@ -3037,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 +=
-                     os->bfd_section->_raw_size / opb;
+                     TO_ADDR (os->bfd_section->size);
                    if (check_regions)
                      os_region_check (os, os->lma_region, NULL,
                                       os->bfd_section->lma);
@@ -3062,6 +3101,11 @@ lang_size_sections_1
            s->data_statement.output_section =
              output_section_statement->bfd_section;
 
+           /* We might refer to provided symbols in the expression, and
+              need to mark them as needed.  */
+           exp_fold_tree (s->data_statement.exp, abs_output_section,
+                          lang_allocating_phase_enum, dot, &dot);
+
            switch (s->data_statement.type)
              {
              default:
@@ -3080,10 +3124,10 @@ lang_size_sections_1
                size = BYTE_SIZE;
                break;
              }
-           if (size < opb)
-             size = opb;
-           dot += size / opb;
-           output_section_statement->bfd_section->_raw_size += size;
+           if (size < TO_SIZE ((unsigned) 1))
+             size = TO_SIZE ((unsigned) 1);
+           dot += TO_ADDR (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;
@@ -3104,8 +3148,8 @@ lang_size_sections_1
            s->reloc_statement.output_section =
              output_section_statement->bfd_section;
            size = bfd_get_reloc_size (s->reloc_statement.howto);
-           dot += size / opb;
-           output_section_statement->bfd_section->_raw_size += size;
+           dot += TO_ADDR (size);
+           output_section_statement->bfd_section->size += size;
          }
          break;
 
@@ -3130,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;
 
@@ -3172,20 +3211,28 @@ 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
                  {
                    /* Insert a pad after this statement.  We can't
                       put the pad before when relaxing, in case the
                       assignment references dot.  */
-                   insert_pad (&s->header.next, fill, (newdot - dot) * opb,
+                   insert_pad (&s->header.next, fill, TO_SIZE (newdot - dot),
                                output_section_statement->bfd_section, dot);
 
                    /* Don't neuter the pad below when relaxing.  */
                    s = s->header.next;
                  }
 
+               /* If dot is advanced, this implies that the section should
+                  have space allocated to it, unless the user has explicitly
+                  stated that the section should never be loaded.  */
+               if (!(output_section_statement->flags
+                     & (SEC_NEVER_LOAD | SEC_ALLOC)))
+                 output_section_statement->bfd_section->flags |= SEC_ALLOC;
+
                dot = newdot;
              }
          }
@@ -3239,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++;
@@ -3247,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.  */
@@ -3261,19 +3319,12 @@ lang_size_sections
          && first + last <= exp_data_seg.pagesize)
        {
          exp_data_seg.phase = exp_dataseg_adjust;
+         lang_statement_iteration++;
          result = lang_size_sections_1 (s, output_section_statement, prev,
                                         fill, dot, relax, check_regions);
        }
     }
 
-  /* 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;
 }
 
@@ -3286,9 +3337,6 @@ lang_do_assignments_1
    fill_type *fill,
    bfd_vma dot)
 {
-  unsigned opb = bfd_arch_mach_octets_per_byte (ldfile_output_architecture,
-                                               ldfile_output_machine);
-
   for (; s != NULL; s = s->header.next)
     {
       switch (s->header.type)
@@ -3308,10 +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 + os->bfd_section->_raw_size / opb;
-
+               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)
              {
@@ -3348,9 +3398,10 @@ lang_do_assignments_1
            value = exp_fold_tree (s->data_statement.exp,
                                   abs_output_section,
                                   lang_final_phase_enum, dot, &dot);
-           s->data_statement.value = value.value;
            if (!value.valid_p)
              einfo (_("%F%P: invalid data statement\n"));
+           s->data_statement.value
+             = value.value + value.section->bfd_section->vma;
          }
          {
            unsigned int size;
@@ -3372,9 +3423,9 @@ lang_do_assignments_1
                size = BYTE_SIZE;
                break;
              }
-           if (size < opb)
-             size = opb;
-           dot += size / opb;
+           if (size < TO_SIZE ((unsigned) 1))
+             size = TO_SIZE ((unsigned) 1);
+           dot += TO_ADDR (size);
          }
          break;
 
@@ -3389,17 +3440,15 @@ lang_do_assignments_1
            if (!value.valid_p)
              einfo (_("%F%P: invalid reloc statement\n"));
          }
-         dot += bfd_get_reloc_size (s->reloc_statement.howto) / opb;
+         dot += TO_ADDR (bfd_get_reloc_size (s->reloc_statement.howto));
          break;
 
        case lang_input_section_enum:
          {
            asection *in = s->input_section.section;
 
-           if (in->_cooked_size != 0)
-             dot += in->_cooked_size / opb;
-           else
-             dot += in->_raw_size / opb;
+           if ((in->flags & SEC_EXCLUDE) == 0)
+             dot += TO_ADDR (in->size);
          }
          break;
 
@@ -3419,7 +3468,7 @@ lang_do_assignments_1
 
          break;
        case lang_padding_statement_enum:
-         dot += s->padding_statement.size / opb;
+         dot += TO_ADDR (s->padding_statement.size);
          break;
 
        case lang_group_statement_enum:
@@ -3440,12 +3489,12 @@ lang_do_assignments_1
   return dot;
 }
 
-bfd_vma
-lang_do_assignments (lang_statement_union_type *s,
-                    lang_output_section_statement_type
-                    *output_section_statement,
-                    fill_type *fill,
-                    bfd_vma dot)
+void
+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++;
@@ -3489,15 +3538,8 @@ lang_set_startof (void)
       h = bfd_link_hash_lookup (link_info.hash, buf, FALSE, FALSE, TRUE);
       if (h != NULL && h->type == bfd_link_hash_undefined)
        {
-         unsigned opb;
-
-         opb = bfd_arch_mach_octets_per_byte (ldfile_output_architecture,
-                                              ldfile_output_machine);
          h->type = bfd_link_hash_defined;
-         if (s->_cooked_size != 0)
-           h->u.def.value = s->_cooked_size / opb;
-         else
-           h->u.def.value = s->_raw_size / opb;
+         h->u.def.value = TO_ADDR (s->size);
          h->u.def.section = bfd_abs_section_ptr;
        }
 
@@ -3563,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,
@@ -3574,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
@@ -3606,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
@@ -3620,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.  */
@@ -3629,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));
        }
@@ -3650,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);
@@ -3691,8 +3739,6 @@ lang_one_common (struct bfd_link_hash_entry *h, void *info)
   unsigned int power_of_two;
   bfd_vma size;
   asection *section;
-  unsigned opb = bfd_arch_mach_octets_per_byte (ldfile_output_architecture,
-                                               ldfile_output_machine);
 
   if (h->type != bfd_link_hash_common)
     return TRUE;
@@ -3706,9 +3752,9 @@ lang_one_common (struct bfd_link_hash_entry *h, void *info)
 
   section = h->u.c.p->section;
 
-  /* Increase the size of the section.  */
-  section->_cooked_size = align_n ((section->_cooked_size + opb - 1) / opb,
-                                  (bfd_vma) 1 << power_of_two) * opb;
+  /* Increase the size of the section to align the common sym.  */
+  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)
@@ -3717,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.  */
@@ -3796,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
@@ -3813,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");
@@ -3903,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)
 {
@@ -3989,16 +4019,17 @@ lang_output_section_statement_type *
 lang_enter_output_section_statement (const char *output_section_statement_name,
                                     etree_type *address_exp,
                                     enum section_type sectype,
-                                    bfd_vma block_value,
                                     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
@@ -4016,7 +4047,7 @@ lang_enter_output_section_statement (const char *output_section_statement_name,
     os->flags = SEC_NO_FLAGS;
   else
     os->flags = SEC_NEVER_LOAD;
-  os->block_value = block_value ? block_value : 1;
+  os->block_value = 1;
   stat_ptr = &os->children;
 
   os->subsection_alignment =
@@ -4052,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,
@@ -4065,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
@@ -4087,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);
@@ -4131,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
@@ -4142,13 +4185,15 @@ lang_process (void)
 
   /* Open the output file.  */
   lang_for_each_statement (ldlang_open_output);
+  init_opb ();
 
   ldemul_create_output_section_statements ();
 
   /* 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;
@@ -4160,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
@@ -4178,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 ();
@@ -4199,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)
        {
@@ -4235,8 +4281,6 @@ lang_process (void)
 
       do
        {
-         lang_reset_memory_regions ();
-
          relax_again = FALSE;
 
          /* Note: pe-dll.c does something like this also.  If you find
@@ -4248,6 +4292,10 @@ lang_process (void)
          lang_do_assignments (statement_list.head, abs_output_section,
                               NULL, 0);
 
+         /* We must do this after lang_do_assignments, because it uses
+            size.  */
+         lang_reset_memory_regions ();
+
          /* Perform another relax pass - this time we know where the
             globals are, so can make a better guess.  */
          lang_size_sections (statement_list.head, abs_output_section,
@@ -4255,17 +4303,17 @@ lang_process (void)
 
          /* If the normal relax is done and the relax finalize pass
             is not performed yet, we perform another relax pass.  */
-         if (!relax_again && !link_info.relax_finalizing)
+         if (!relax_again && link_info.need_relax_finalize)
            {
-             link_info.relax_finalizing = TRUE;
+             link_info.need_relax_finalize = FALSE;
              relax_again = TRUE;
            }
        }
       while (relax_again);
 
       /* Final extra sizing to report errors.  */
-      lang_reset_memory_regions ();
       lang_do_assignments (statement_list.head, abs_output_section, NULL, 0);
+      lang_reset_memory_regions ();
       lang_size_sections (statement_list.head, abs_output_section,
                          &statement_list.head, 0, 0, NULL, TRUE);
     }
@@ -4485,34 +4533,39 @@ lang_float (bfd_boolean maybe)
    It is an error to specify both a load region and a load address.  */
 
 static void
-lang_get_regions (struct memory_region_struct **region,
-                 struct memory_region_struct **lma_region,
+lang_get_regions (lang_memory_region_type **region,
+                 lang_memory_region_type **lma_region,
                  const char *memspec,
                  const char *lma_memspec,
-                 int have_lma_p)
+                 bfd_boolean have_lma,
+                 bfd_boolean have_vma)
 {
   *lma_region = lang_memory_region_lookup (lma_memspec, FALSE);
 
-  /* If no runtime region has been given, but the load region has
-     been, use the load region.  */
-  if (lma_memspec != 0 && strcmp (memspec, DEFAULT_MEMORY_REGION) == 0)
+  /* 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)
     *region = *lma_region;
   else
     *region = lang_memory_region_lookup (memspec, FALSE);
 
-  if (have_lma_p && lma_memspec != 0)
+  if (have_lma && lma_memspec != 0)
     einfo (_("%X%P:%S: section has both a load address and a load region\n"));
 }
 
 void
-lang_leave_output_section_statement
-  (fill_type *fill, const char *memspec,
-   struct lang_output_section_phdr_list *phdrs, const char *lma_memspec)
+lang_leave_output_section_statement (fill_type *fill, const char *memspec,
+                                    lang_output_section_phdr_list *phdrs,
+                                    const char *lma_memspec)
 {
   lang_get_regions (&current_section->region,
                    &current_section->lma_region,
                    memspec, lma_memspec,
-                   current_section->load_base != 0);
+                   current_section->load_base != NULL,
+                   current_section->addr_tree != NULL);
   current_section->fill = fill;
   current_section->phdrs = phdrs;
   stat_ptr = &statement_list;
@@ -4575,8 +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)
-                         + bfd_section_size (output_bfd, sec) /
-                          bfd_octets_per_byte (output_bfd));
+                         + TO_ADDR (sec->size));
 
       h->u.def.section = bfd_abs_section_ptr;
     }
@@ -4672,7 +4724,7 @@ lang_record_phdrs (void)
 {
   unsigned int alc;
   asection **secs;
-  struct lang_output_section_phdr_list *last;
+  lang_output_section_phdr_list *last;
   struct lang_phdr *l;
   lang_statement_union_type *u;
 
@@ -4691,9 +4743,11 @@ lang_record_phdrs (void)
           u = u->output_section_statement.next)
        {
          lang_output_section_statement_type *os;
-         struct lang_output_section_phdr_list *pl;
+         lang_output_section_phdr_list *pl;
 
          os = &u->output_section_statement;
+         if (os->constraint == -1)
+           continue;
 
          pl = os->phdrs;
          if (pl != NULL)
@@ -4751,9 +4805,10 @@ lang_record_phdrs (void)
        u != NULL;
        u = u->output_section_statement.next)
     {
-      struct lang_output_section_phdr_list *pl;
+      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;
@@ -4768,7 +4823,7 @@ lang_record_phdrs (void)
 /* Record a list of sections which may not be cross referenced.  */
 
 void
-lang_add_nocrossref (struct lang_nocrossref *l)
+lang_add_nocrossref (lang_nocrossref_type *l)
 {
   struct lang_nocrossrefs *n;
 
@@ -4825,7 +4880,7 @@ lang_enter_overlay_section (const char *name)
   etree_type *size;
 
   lang_enter_output_section_statement (name, overlay_vma, normal_section,
-                                      0, 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
@@ -4853,7 +4908,7 @@ lang_enter_overlay_section (const char *name)
 
 void
 lang_leave_overlay_section (fill_type *fill,
-                           struct lang_output_section_phdr_list *phdrs)
+                           lang_output_section_phdr_list *phdrs)
 {
   const char *name;
   char *clean, *s2;
@@ -4900,17 +4955,17 @@ lang_leave_overlay (etree_type *lma_expr,
                    int nocrossrefs,
                    fill_type *fill,
                    const char *memspec,
-                   struct lang_output_section_phdr_list *phdrs,
+                   lang_output_section_phdr_list *phdrs,
                    const char *lma_memspec)
 {
   lang_memory_region_type *region;
   lang_memory_region_type *lma_region;
   struct overlay_list *l;
-  struct lang_nocrossref *nocrossref;
+  lang_nocrossref_type *nocrossref;
 
   lang_get_regions (&region, &lma_region,
                    memspec, lma_memspec,
-                   lma_expr != 0);
+                   lma_expr != NULL, FALSE);
 
   nocrossref = NULL;
 
@@ -4947,7 +5002,7 @@ lang_leave_overlay (etree_type *lma_expr,
 
       if (nocrossrefs)
        {
-         struct lang_nocrossref *nc;
+         lang_nocrossref_type *nc;
 
          nc = xmalloc (sizeof *nc);
          nc->name = l->os->name;
@@ -4989,7 +5044,7 @@ lang_vers_match (struct bfd_elf_version_expr_head *head,
 
   if (head->mask & BFD_ELF_VERSION_CXX_TYPE)
     {
-      cxx_sym = cplus_demangle (sym, /* DMGL_NO_TPARAMS */ 0);
+      cxx_sym = cplus_demangle (sym, DMGL_PARAMS | DMGL_ANSI);
       if (!cxx_sym)
        cxx_sym = sym;
     }
@@ -5288,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;
     }
@@ -5316,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);
        }
     }
 
@@ -5341,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);
        }
     }
 
@@ -5408,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);
@@ -5423,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);