* ld-scripts/crossref.exp: Compile test source with -mtiny=0 in order to
[deliverable/binutils-gdb.git] / ld / ldlang.c
index a9af491b78802382c1271d57fa510a08e290cb74..b06cabd40b63f7965e2da2e88259fa4997362ca0 100644 (file)
@@ -1,27 +1,27 @@
 /* Linker command language support.
    Copyright 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
-   2001, 2002, 2003, 2004, 2005, 2006
+   2001, 2002, 2003, 2004, 2005, 2006, 2007
    Free Software Foundation, Inc.
 
-   This file is part of GLD, the Gnu Linker.
+   This file is part of the GNU Binutils.
 
-   GLD is free software; you can redistribute it and/or modify
+   This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2, or (at your option)
-   any later version.
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
 
-   GLD is distributed in the hope that it will be useful,
+   This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.
 
    You should have received a copy of the GNU General Public License
-   along with GLD; see the file COPYING.  If not, write to the Free
-   Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
-   02110-1301, USA.  */
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+   MA 02110-1301, USA.  */
 
-#include "bfd.h"
 #include "sysdep.h"
+#include "bfd.h"
 #include "libiberty.h"
 #include "safe-ctype.h"
 #include "obstack.h"
@@ -52,7 +52,6 @@ static struct obstack map_obstack;
 #define obstack_chunk_alloc xmalloc
 #define obstack_chunk_free free
 static const char *startup_file;
-static lang_statement_list_type input_file_chain;
 static bfd_boolean placed_commons = FALSE;
 static bfd_boolean stripped_excluded_sections = FALSE;
 static lang_output_section_statement_type *default_common_section;
@@ -62,15 +61,12 @@ static lang_input_statement_type *first_file;
 static const char *current_target;
 static const char *output_target;
 static lang_statement_list_type statement_list;
-static struct lang_phdr *lang_phdr_list;
 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 lang_input_statement_type *lookup_name (const char *);
-static bfd_boolean load_symbols (lang_input_statement_type *,
-                                lang_statement_list_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 *);
@@ -84,12 +80,15 @@ static void print_input_section (asection *);
 static bfd_boolean lang_one_common (struct bfd_link_hash_entry *, void *);
 static void lang_record_phdrs (void);
 static void lang_do_version_exports_section (void);
+static void lang_finalize_version_expr_head
+  (struct bfd_elf_version_expr_head *);
 
 /* Exported variables.  */
 lang_output_section_statement_type *abs_output_section;
 lang_statement_list_type lang_output_section_statement;
 lang_statement_list_type *stat_ptr = &statement_list;
 lang_statement_list_type file_chain = { NULL, NULL };
+lang_statement_list_type input_file_chain;
 struct bfd_sym_chain entry_symbol = { NULL, NULL };
 static const char *entry_symbol_default = "start";
 const char *entry_section = ".text";
@@ -98,6 +97,7 @@ bfd_boolean lang_has_input_file = FALSE;
 bfd_boolean had_output_filename = FALSE;
 bfd_boolean lang_float_flag = FALSE;
 bfd_boolean delete_output_file_on_failure = FALSE;
+struct lang_phdr *lang_phdr_list;
 struct lang_nocrossrefs *nocrossref_list;
 static struct unique_sections *unique_section_list;
 static bfd_boolean ldlang_sysrooted_script = FALSE;
@@ -279,7 +279,7 @@ find_section (lang_input_statement_type *file,
 {
   section_iterator_callback_data cb_data = { NULL, FALSE };
 
-  bfd_get_section_by_name_if (file->the_bfd, sec->spec.name, 
+  bfd_get_section_by_name_if (file->the_bfd, sec->spec.name,
                              section_iterator_callback, &cb_data);
   *multiple_sections_found = cb_data.multiple_sections_found;
   return cb_data.found_section;
@@ -316,6 +316,124 @@ match_simple_wild (const char *pattern, const char *name)
   return TRUE;
 }
 
+/* Compare sections ASEC and BSEC according to SORT.  */
+
+static int
+compare_section (sort_type sort, asection *asec, asection *bsec)
+{
+  int ret;
+
+  switch (sort)
+    {
+    default:
+      abort ();
+
+    case by_alignment_name:
+      ret = (bfd_section_alignment (bsec->owner, bsec)
+            - bfd_section_alignment (asec->owner, asec));
+      if (ret)
+       break;
+      /* Fall through.  */
+
+    case by_name:
+      ret = strcmp (bfd_get_section_name (asec->owner, asec),
+                   bfd_get_section_name (bsec->owner, bsec));
+      break;
+
+    case by_name_alignment:
+      ret = strcmp (bfd_get_section_name (asec->owner, asec),
+                   bfd_get_section_name (bsec->owner, bsec));
+      if (ret)
+       break;
+      /* Fall through.  */
+
+    case by_alignment:
+      ret = (bfd_section_alignment (bsec->owner, bsec)
+            - bfd_section_alignment (asec->owner, asec));
+      break;
+    }
+
+  return ret;
+}
+
+/* Build a Binary Search Tree to sort sections, unlike insertion sort
+   used in wild_sort(). BST is considerably faster if the number of
+   of sections are large.  */
+
+static lang_section_bst_type **
+wild_sort_fast (lang_wild_statement_type *wild,
+               struct wildcard_list *sec,
+               lang_input_statement_type *file ATTRIBUTE_UNUSED,
+               asection *section)
+{
+  lang_section_bst_type **tree;
+
+  tree = &wild->tree;
+  if (!wild->filenames_sorted
+      && (sec == NULL || sec->spec.sorted == none))
+    {
+      /* Append at the right end of tree.  */
+      while (*tree)
+       tree = &((*tree)->right);
+      return tree;
+    }
+
+  while (*tree)
+    {
+      /* Find the correct node to append this section.  */
+      if (compare_section (sec->spec.sorted, section, (*tree)->section) < 0)
+       tree = &((*tree)->left);
+      else
+       tree = &((*tree)->right);
+    }
+
+  return tree;
+}
+
+/* Use wild_sort_fast to build a BST to sort sections.  */
+
+static void
+output_section_callback_fast (lang_wild_statement_type *ptr,
+                             struct wildcard_list *sec,
+                             asection *section,
+                             lang_input_statement_type *file,
+                             void *output ATTRIBUTE_UNUSED)
+{
+  lang_section_bst_type *node;
+  lang_section_bst_type **tree;
+
+  if (unique_section_p (section))
+    return;
+
+  node = xmalloc (sizeof (lang_section_bst_type));
+  node->left = 0;
+  node->right = 0;
+  node->section = section;
+
+  tree = wild_sort_fast (ptr, sec, file, section);
+  if (tree != NULL)
+    *tree = node;
+}
+
+/* Convert a sorted sections' BST back to list form.  */
+
+static void
+output_section_callback_tree_to_list (lang_wild_statement_type *ptr,
+                                     lang_section_bst_type *tree,
+                                     void *output)
+{
+  if (tree->left)
+    output_section_callback_tree_to_list (ptr, tree->left, output);
+
+  lang_add_section (&ptr->children, tree->section,
+                   (lang_output_section_statement_type *) output);
+
+  if (tree->right)
+    output_section_callback_tree_to_list (ptr, tree->right, output);
+
+  free (tree);
+}
+
 /* Specialized, optimized routines for handling different kinds of
    wildcards */
 
@@ -543,6 +661,11 @@ analyze_walk_wild_section_handler (lang_wild_statement_type *ptr)
   int data_counter;
 
   ptr->walk_wild_section_handler = walk_wild_section_general;
+  ptr->handler_data[0] = NULL;
+  ptr->handler_data[1] = NULL;
+  ptr->handler_data[2] = NULL;
+  ptr->handler_data[3] = NULL;
+  ptr->tree = NULL;
 
   /* Count how many wildcard_specs there are, and how many of those
      actually use wildcards in the name.  Also, bail out if any of the
@@ -668,7 +791,7 @@ walk_wild (lang_wild_statement_type *s, callback_t callback, void *data)
     {
       LANG_FOR_EACH_INPUT_STATEMENT (f)
        {
-         if (fnmatch (file_spec, f->filename, FNM_FILE_NAME) == 0)
+         if (fnmatch (file_spec, f->filename, 0) == 0)
            walk_wild_file (s, f, callback, data);
        }
     }
@@ -790,6 +913,14 @@ new_afile (const char *name,
   lang_has_input_file = TRUE;
   p->target = target;
   p->sysrooted = FALSE;
+
+  if (file_type == lang_input_file_is_l_enum
+      && name[0] == ':' && name[1] != '\0')
+    {
+      file_type = lang_input_file_is_search_file_enum;
+      name = name + 1;
+    }
+
   switch (file_type)
     {
     case lang_input_file_is_symbols_only_enum:
@@ -865,7 +996,6 @@ lang_add_input_file (const char *name,
                     lang_input_file_enum_type file_type,
                     const char *target)
 {
-  lang_has_input_file = TRUE;
   return new_afile (name, file_type, target, TRUE);
 }
 
@@ -883,7 +1013,7 @@ static struct bfd_hash_table output_section_statement_table;
    initialize the table, fill in an entry and remove the table.  */
 
 static struct bfd_hash_entry *
-output_section_statement_newfunc (struct bfd_hash_entry *entry, 
+output_section_statement_newfunc (struct bfd_hash_entry *entry,
                                  struct bfd_hash_table *table,
                                  const char *string)
 {
@@ -1033,16 +1163,17 @@ lang_memory_region_lookup (const char *const name, bfd_boolean create)
 
   new->name = xstrdup (name);
   new->next = NULL;
-
-  *lang_memory_region_list_tail = new;
-  lang_memory_region_list_tail = &new->next;
   new->origin = 0;
-  new->flags = 0;
-  new->not_flags = 0;
   new->length = ~(bfd_size_type) 0;
   new->current = 0;
+  new->last_os = NULL;
+  new->flags = 0;
+  new->not_flags = 0;
   new->had_full_message = FALSE;
 
+  *lang_memory_region_list_tail = new;
+  lang_memory_region_list_tail = &new->next;
+
   return new;
 }
 
@@ -1331,7 +1462,6 @@ lang_insert_orphan (asection *s,
   lang_statement_list_type *old;
   lang_statement_list_type add;
   const char *ps;
-  etree_type *load_base;
   lang_output_section_statement_type *os;
   lang_output_section_statement_type **os_tail;
 
@@ -1367,28 +1497,19 @@ lang_insert_orphan (asection *s,
          e_align = exp_unop (ALIGN_K,
                              exp_intop ((bfd_vma) 1 << s->alignment_power));
          lang_add_assignment (exp_assop ('=', ".", e_align));
-         lang_add_assignment (exp_assop ('=', symname,
-                                         exp_nameop (NAME, ".")));
+         lang_add_assignment (exp_provide (symname,
+                                           exp_nameop (NAME, "."),
+                                           FALSE));
        }
     }
 
   if (link_info.relocatable || (s->flags & (SEC_LOAD | SEC_ALLOC)) == 0)
     address = exp_intop (0);
 
-  load_base = NULL;
-  if (after != NULL && after->load_base != NULL)
-    {
-      etree_type *lma_from_vma;
-      lma_from_vma = exp_binop ('-', after->load_base,
-                               exp_nameop (ADDR, after->name));
-      load_base = exp_binop ('+', lma_from_vma,
-                            exp_nameop (ADDR, secname));
-    }
-
   os_tail = ((lang_output_section_statement_type **)
             lang_output_section_statement.tail);
   os = lang_enter_output_section_statement (secname, address, 0, NULL, NULL,
-                                           load_base, 0);
+                                           NULL, 0);
 
   if (add_child == NULL)
     add_child = &os->children;
@@ -1408,8 +1529,9 @@ lang_insert_orphan (asection *s,
       symname = (char *) xmalloc (ps - secname + sizeof "__stop_" + 1);
       symname[0] = bfd_get_symbol_leading_char (output_bfd);
       sprintf (symname + (symname[0] != 0), "__stop_%s", secname);
-      lang_add_assignment (exp_assop ('=', symname,
-                                     exp_nameop (NAME, ".")));
+      lang_add_assignment (exp_provide (symname,
+                                       exp_nameop (NAME, "."),
+                                       FALSE));
     }
 
   /* Restore the global list pointer.  */
@@ -1445,7 +1567,18 @@ lang_insert_orphan (asection *s,
        place->section = &output_bfd->sections;
 
       as = *place->section;
-      if (as != snew && as->prev != snew)
+
+      if (!as)
+       {
+         /* Put the section at the end of the list.  */
+
+         /* Unlink the section.  */
+         bfd_section_list_remove (output_bfd, snew);
+
+         /* Now tack it back on in the right place.  */
+         bfd_section_list_append (output_bfd, snew);
+       }
+      else if (as != snew && as->prev != snew)
        {
          /* Unlink the section.  */
          bfd_section_list_remove (output_bfd, snew);
@@ -1521,13 +1654,14 @@ lang_insert_orphan (asection *s,
                    case lang_output_section_statement_enum:
                      if (assign != NULL)
                        where = assign;
+                     break;
                    case lang_input_statement_enum:
                    case lang_address_statement_enum:
                    case lang_target_statement_enum:
                    case lang_output_statement_enum:
                    case lang_group_statement_enum:
                    case lang_afile_asection_pair_statement_enum:
-                     break;
+                     continue;
                    }
                  break;
                }
@@ -1612,8 +1746,9 @@ lang_map (void)
        continue;
 
       for (s = file->the_bfd->sections; s != NULL; s = s->next)
-       if (s->output_section == NULL
-           || s->output_section->owner != output_bfd)
+       if ((s->output_section == NULL
+            || s->output_section->owner != output_bfd)
+           && (s->flags & (SEC_LINKER_CREATED | SEC_KEEP)) == 0)
          {
            if (! dis_header_printed)
              {
@@ -1669,13 +1804,14 @@ lang_map (void)
 
   fprintf (config.map_file, _("\nLinker script and memory map\n\n"));
 
-  if (! command_line.reduce_memory_overheads)
+  if (! link_info.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);
     }
+  lang_statement_iteration ++;
   print_statements ();
 }
 
@@ -1727,7 +1863,8 @@ sort_def_symbol (hash_entry, info)
 /* Initialize an output section.  */
 
 static void
-init_os (lang_output_section_statement_type *s, asection *isec)
+init_os (lang_output_section_statement_type *s, asection *isec,
+        flagword flags)
 {
   if (s->bfd_section != NULL)
     return;
@@ -1737,7 +1874,8 @@ init_os (lang_output_section_statement_type *s, asection *isec)
 
   s->bfd_section = bfd_get_section_by_name (output_bfd, s->name);
   if (s->bfd_section == NULL)
-    s->bfd_section = bfd_make_section (output_bfd, s->name);
+    s->bfd_section = bfd_make_section_with_flags (output_bfd, s->name,
+                                                 flags);
   if (s->bfd_section == NULL)
     {
       einfo (_("%P%F: output format %s cannot represent section called %s\n"),
@@ -1746,7 +1884,7 @@ init_os (lang_output_section_statement_type *s, asection *isec)
   s->bfd_section->output_section = s->bfd_section;
   s->bfd_section->output_offset = 0;
 
-  if (!command_line.reduce_memory_overheads)
+  if (!link_info.reduce_memory_overheads)
     {
       fat_section_userdata_type *new
        = stat_alloc (sizeof (fat_section_userdata_type));
@@ -1815,7 +1953,7 @@ exp_init_os (etree_type *exp)
 
            os = lang_output_section_find (exp->name.name);
            if (os != NULL && os->bfd_section == NULL)
-             init_os (os, NULL);
+             init_os (os, NULL, 0);
          }
        }
       break;
@@ -1839,7 +1977,7 @@ section_already_linked (bfd *abfd, asection *sec, void *data)
     }
 
   if (!(abfd->flags & DYNAMIC))
-    bfd_section_already_linked (abfd, sec);
+    bfd_section_already_linked (abfd, sec, &link_info);
 }
 \f
 /* The wild routines.
@@ -1890,8 +2028,33 @@ lang_add_section (lang_statement_list_type *ptr,
       lang_input_section_type *new;
       flagword flags;
 
+      flags = section->flags;
+
+      /* We don't copy the SEC_NEVER_LOAD flag from an input section
+        to an output section, because we want to be able to include a
+        SEC_NEVER_LOAD section in the middle of an otherwise loaded
+        section (I don't know why we want to do this, but we do).
+        build_link_order in ldwrite.c handles this case by turning
+        the embedded SEC_NEVER_LOAD section into a fill.  */
+
+      flags &= ~ SEC_NEVER_LOAD;
+
+      switch (output->sectype)
+       {
+       case normal_section:
+       case overlay_section:
+         break;
+       case noalloc_section:
+         flags &= ~SEC_ALLOC;
+         break;
+       case noload_section:
+         flags &= ~SEC_LOAD;
+         flags |= SEC_NEVER_LOAD;
+         break;
+       }
+
       if (output->bfd_section == NULL)
-       init_os (output, section);
+       init_os (output, section, flags);
 
       first = ! output->bfd_section->linker_has_input;
       output->bfd_section->linker_has_input = 1;
@@ -1915,17 +2078,6 @@ lang_add_section (lang_statement_list_type *ptr,
       new->section = section;
       section->output_section = output->bfd_section;
 
-      flags = section->flags;
-
-      /* We don't copy the SEC_NEVER_LOAD flag from an input section
-        to an output section, because we want to be able to include a
-        SEC_NEVER_LOAD section in the middle of an otherwise loaded
-        section (I don't know why we want to do this, but we do).
-        build_link_order in ldwrite.c handles this case by turning
-        the embedded SEC_NEVER_LOAD section into a fill.  */
-
-      flags &= ~ SEC_NEVER_LOAD;
-
       /* If final link, don't copy the SEC_LINK_ONCE flags, they've
         already been processed.  One reason to do this is that on pe
         format targets, .text$foo sections go into .text and it's odd
@@ -1962,19 +2114,6 @@ lang_add_section (lang_statement_list_type *ptr,
       if ((section->flags & SEC_READONLY) == 0)
        output->bfd_section->flags &= ~SEC_READONLY;
 
-      switch (output->sectype)
-       {
-       case normal_section:
-         break;
-       case noalloc_section:
-         output->bfd_section->flags &= ~SEC_ALLOC;
-         break;
-       case noload_section:
-         output->bfd_section->flags &= ~SEC_LOAD;
-         output->bfd_section->flags |= SEC_NEVER_LOAD;
-         break;
-       }
-
       /* Copy over SEC_SMALL_DATA.  */
       if (section->flags & SEC_SMALL_DATA)
        output->bfd_section->flags |= SEC_SMALL_DATA;
@@ -1992,46 +2131,6 @@ lang_add_section (lang_statement_list_type *ptr,
     }
 }
 
-/* Compare sections ASEC and BSEC according to SORT.  */
-
-static int
-compare_section (sort_type sort, asection *asec, asection *bsec)
-{
-  int ret;
-
-  switch (sort)
-    {
-    default:
-      abort ();
-
-    case by_alignment_name:
-      ret = (bfd_section_alignment (bsec->owner, bsec)
-            - bfd_section_alignment (asec->owner, asec));
-      if (ret)
-       break;
-      /* Fall through.  */
-
-    case by_name:
-      ret = strcmp (bfd_get_section_name (asec->owner, asec),
-                   bfd_get_section_name (bsec->owner, bsec));
-      break;
-
-    case by_name_alignment:
-      ret = strcmp (bfd_get_section_name (asec->owner, asec),
-                   bfd_get_section_name (bsec->owner, bsec));
-      if (ret)
-       break;
-      /* Fall through.  */
-
-    case by_alignment:
-      ret = (bfd_section_alignment (bsec->owner, bsec)
-            - bfd_section_alignment (asec->owner, asec));
-      break;
-    }
-
-  return ret;
-}
-
 /* Handle wildcard sorting.  This returns the lang_input_section which
    should follow the one we are going to create for SECTION and FILE,
    based on the sorting requirements of WILD.  It returns NULL if the
@@ -2263,7 +2362,7 @@ add_excluded_libs (const char *list)
       entry->name[end - p] = '\0';
       excluded_libs = entry;
       if (*end == '\0')
-        break;
+       break;
       p = end + 1;
     }
 }
@@ -2299,7 +2398,7 @@ check_excluded_libs (bfd *abfd)
 
 /* Get the symbols for an input file.  */
 
-static bfd_boolean
+bfd_boolean
 load_symbols (lang_input_statement_type *entry,
              lang_statement_list_type *place)
 {
@@ -2450,7 +2549,23 @@ wild (lang_wild_statement_type *s,
 {
   struct wildcard_list *sec;
 
-  walk_wild (s, output_section_callback, output);
+  if (s->handler_data[0]
+      && s->handler_data[0]->spec.sorted == by_name
+      && !s->filenames_sorted)
+    {
+      lang_section_bst_type *tree;
+
+      walk_wild (s, output_section_callback_fast, output);
+
+      tree = s->tree;
+      if (tree)
+       {
+         output_section_callback_tree_to_list (s, tree, output);
+         s->tree = NULL;
+       }
+    }
+  else
+    walk_wild (s, output_section_callback, output);
 
   if (default_common_section == NULL)
     for (sec = s->section_list; sec != NULL; sec = sec->next)
@@ -3049,7 +3164,8 @@ update_wild_statements (lang_statement_union_type *s)
 
            case lang_wild_statement_enum:
              sec = s->wild_statement.section_list;
-             if (sec != NULL)
+             for (sec = s->wild_statement.section_list; sec != NULL;
+                  sec = sec->next)
                {
                  switch (sec->spec.sorted)
                    {
@@ -3095,6 +3211,8 @@ map_input_to_output_sections
   (lang_statement_union_type *s, const char *target,
    lang_output_section_statement_type *os)
 {
+  flagword flags;
+
   for (; s != NULL; s = s->header.next)
     {
       switch (s->header.type)
@@ -3144,13 +3262,15 @@ map_input_to_output_sections
          /* Make sure that any sections mentioned in the expression
             are initialized.  */
          exp_init_os (s->data_statement.exp);
-         if (os != NULL && os->bfd_section == NULL)
-           init_os (os, NULL);
+         flags = SEC_HAS_CONTENTS;
          /* The output section gets contents, and then we inspect for
             any flags set in the input script which override any ALLOC.  */
-         os->bfd_section->flags |= SEC_HAS_CONTENTS;
          if (!(os->flags & SEC_NEVER_LOAD))
-           os->bfd_section->flags |= SEC_ALLOC | SEC_LOAD;
+           flags |= SEC_ALLOC | SEC_LOAD;
+         if (os->bfd_section == NULL)
+           init_os (os, NULL, flags);
+         else
+           os->bfd_section->flags |= flags;
          break;
        case lang_input_section_enum:
          break;
@@ -3160,11 +3280,11 @@ map_input_to_output_sections
        case lang_padding_statement_enum:
        case lang_input_statement_enum:
          if (os != NULL && os->bfd_section == NULL)
-           init_os (os, NULL);
+           init_os (os, NULL, 0);
          break;
        case lang_assignment_statement_enum:
          if (os != NULL && os->bfd_section == NULL)
-           init_os (os, NULL);
+           init_os (os, NULL, 0);
 
          /* Make sure that any sections mentioned in the assignment
             are initialized.  */
@@ -3174,7 +3294,7 @@ map_input_to_output_sections
          FAIL ();
          break;
        case lang_address_statement_enum:
-         /* Mark the specified section with the supplied address.  
+         /* Mark the specified section with the supplied address.
 
             If this section was actually a segment marker, then the
             directive is ignored if the linker script explicitly
@@ -3184,15 +3304,15 @@ map_input_to_output_sections
             section directive semantics for backwards compatibilty;
             linker scripts that do not specifically check for
             SEGMENT_START automatically get the old semantics.  */
-         if (!s->address_statement.segment 
+         if (!s->address_statement.segment
              || !s->address_statement.segment->used)
            {
              lang_output_section_statement_type *aos
                = (lang_output_section_statement_lookup
                   (s->address_statement.section_name));
-             
+
              if (aos->bfd_section == NULL)
-               init_os (aos, NULL);
+               init_os (aos, NULL, 0);
              aos->addr_tree = s->address_statement.address;
            }
          break;
@@ -3262,7 +3382,9 @@ strip_excluded_output_sections (void)
        {
          /* We don't set bfd_section to NULL since bfd_section of the
             removed output section statement may still be used.  */
-         os->ignored = TRUE;
+         if (!os->section_relative_symbol
+             && !os->update_dot_tree)
+           os->ignored = TRUE;
          output_section->flags |= SEC_EXCLUDE;
          bfd_section_list_remove (output_bfd, output_section);
          output_bfd->section_count--;
@@ -3303,14 +3425,8 @@ print_output_section_statement
 
          minfo ("0x%V %W", section->vma, section->size);
 
-         if (output_section_statement->load_base != NULL)
-           {
-             bfd_vma addr;
-
-             addr = exp_get_abs_int (output_section_statement->load_base, 0,
-                                     "load base");
-             minfo (_(" load address 0x%V"), addr);
-           }
+         if (section->vma != section->lma)
+           minfo (_(" load address 0x%V"), section->lma);
        }
 
       print_nl ();
@@ -3325,7 +3441,7 @@ print_output_section_statement
    correct expression, since the value of DST that is used on
    the right hand side will be its final value, not its value
    just before this expression is evaluated.  */
-   
+
 static bfd_boolean
 scan_for_self_assignment (const char * dst, etree_type * rhs)
 {
@@ -3424,7 +3540,7 @@ print_assignment (lang_assignment_statement_type *assignment,
              value = h->u.def.value;
 
              if (expld.result.section)
-             value += expld.result.section->vma;
+               value += expld.result.section->vma;
 
              minfo ("[0x%V]", value);
            }
@@ -3550,7 +3666,7 @@ print_input_section (asection *i)
 
   if (i->output_section != NULL && i->output_section->owner == output_bfd)
     {
-      if (command_line.reduce_memory_overheads)
+      if (link_info.reduce_memory_overheads)
        bfd_link_hash_traverse (link_info.hash, print_one_symbol, i);
       else
        print_all_symbols (i);
@@ -3988,6 +4104,10 @@ sort_sections_by_lma (const void *arg1, const void *arg2)
   else if (bfd_section_lma (sec1->owner, sec1)
           > bfd_section_lma (sec2->owner, sec2))
     return 1;
+  else if (sec1->id < sec2->id)
+    return -1;
+  else if (sec1->id > sec2->id)
+    return 1;
 
   return 0;
 }
@@ -4031,7 +4151,7 @@ lang_check_section_addresses (void)
       sections[count] = s;
       count++;
     }
-  
+
   if (count <= 1)
     return;
 
@@ -4048,7 +4168,7 @@ lang_check_section_addresses (void)
         addresses because overlay sections can have overlapping VMAs
         but they must have distinct LMAs.  */
       os = s;
-      os_start = s_start; 
+      os_start = s_start;
       os_end = s_end;
       s = *spp++;
       s_start = bfd_section_lma (output_bfd, s);
@@ -4121,20 +4241,20 @@ lang_size_sections_1
          {
            bfd_vma newdot, after;
            lang_output_section_statement_type *os;
+           lang_memory_region_type *r;
 
            os = &s->output_section_statement;
            if (os->addr_tree != NULL)
              {
-               os->processed = FALSE;
+               os->processed_vma = FALSE;
                exp_fold_tree (os->addr_tree, bfd_abs_section_ptr, &dot);
 
-               if (!expld.result.valid_p
-                   && expld.phase != lang_mark_phase_enum)
+               if (expld.result.valid_p)
+                 dot = expld.result.value + expld.result.section->vma;
+               else if (expld.phase != lang_mark_phase_enum)
                  einfo (_("%F%S: non constant or forward reference"
                           " address expression for section %s\n"),
                         os->name);
-
-               dot = expld.result.value + expld.result.section->vma;
              }
 
            if (os->bfd_section == NULL)
@@ -4254,24 +4374,117 @@ lang_size_sections_1
            lang_size_sections_1 (os->children.head, os, &os->children.head,
                                  os->fill, newdot, relax, check_regions);
 
-           os->processed = TRUE;
+           os->processed_vma = TRUE;
 
            if (bfd_is_abs_section (os->bfd_section) || os->ignored)
+             /* Except for some special linker created sections,
+                no output section should change from zero size
+                after strip_excluded_output_sections.  A non-zero
+                size on an ignored section indicates that some
+                input section was not sized early enough.  */
+             ASSERT (os->bfd_section->size == 0);
+           else
              {
-               ASSERT (os->bfd_section->size == 0);
-               break;
+               dot = os->bfd_section->vma;
+
+               /* Put the section within the requested block size, or
+                  align at the block boundary.  */
+               after = ((dot
+                         + TO_ADDR (os->bfd_section->size)
+                         + os->block_value - 1)
+                        & - (bfd_vma) os->block_value);
+
+               os->bfd_section->size = TO_SIZE (after - os->bfd_section->vma);
              }
 
-           dot = os->bfd_section->vma;
+           /* Set section lma.  */
+           r = os->region;
+           if (r == NULL)
+             r = lang_memory_region_lookup (DEFAULT_MEMORY_REGION, FALSE);
+
+           if (os->load_base)
+             {
+               bfd_vma lma = exp_get_abs_int (os->load_base, 0, "load base");
+               os->bfd_section->lma = lma;
+             }
+           else if (os->region != NULL
+                    && os->lma_region != NULL
+                    && os->lma_region != os->region)
+             {
+               bfd_vma lma = os->lma_region->current;
+
+               if (os->section_alignment != -1)
+                 lma = align_power (lma, os->section_alignment);
+               os->bfd_section->lma = lma;
+             }
+           else if (r->last_os != NULL
+                    && (os->bfd_section->flags & SEC_ALLOC) != 0)
+             {
+               bfd_vma lma;
+               asection *last;
+
+               last = r->last_os->output_section_statement.bfd_section;
+
+               /* A backwards move of dot should be accompanied by
+                  an explicit assignment to the section LMA (ie.
+                  os->load_base set) because backwards moves can
+                  create overlapping LMAs.  */
+               if (dot < last->vma
+                   && os->bfd_section->size != 0
+                   && dot + os->bfd_section->size <= last->vma)
+                 {
+                   /* If dot moved backwards then leave lma equal to
+                      vma.  This is the old default lma, which might
+                      just happen to work when the backwards move is
+                      sufficiently large.  Nag if this changes anything,
+                      so people can fix their linker scripts.  */
+
+                   if (last->vma != last->lma)
+                     einfo (_("%P: warning: dot moved backwards before `%s'\n"),
+                            os->name);
+                 }
+               else
+                 {
+                   /* If this is an overlay, set the current lma to that
+                      at the end of the previous section.  */
+                   if (os->sectype == overlay_section)
+                     lma = last->lma + last->size;
+
+                   /* Otherwise, keep the same lma to vma relationship
+                      as the previous section.  */
+                   else
+                     lma = dot + last->lma - last->vma;
+
+                   if (os->section_alignment != -1)
+                     lma = align_power (lma, os->section_alignment);
+                   os->bfd_section->lma = lma;
+                 }
+             }
+           os->processed_lma = TRUE;
 
-           /* Put the section within the requested block size, or
-              align at the block boundary.  */
-           after = ((dot
-                     + TO_ADDR (os->bfd_section->size)
-                     + os->block_value - 1)
-                    & - (bfd_vma) os->block_value);
+           if (bfd_is_abs_section (os->bfd_section) || os->ignored)
+             break;
 
-           os->bfd_section->size = TO_SIZE (after - os->bfd_section->vma);
+           /* Keep track of normal sections using the default
+              lma region.  We use this to set the lma for
+              following sections.  Overlays or other linker
+              script assignment to lma might mean that the
+              default lma == vma is incorrect.
+              To avoid warnings about dot moving backwards when using
+              -Ttext, don't start tracking sections until we find one
+              of non-zero size or with lma set differently to vma.  */
+           if (((os->bfd_section->flags & SEC_HAS_CONTENTS) != 0
+                || (os->bfd_section->flags & SEC_THREAD_LOCAL) == 0)
+               && (os->bfd_section->flags & SEC_ALLOC) != 0
+               && (os->bfd_section->size != 0
+                   || (r->last_os == NULL
+                       && os->bfd_section->vma != os->bfd_section->lma)
+                   || (r->last_os != NULL
+                       && dot >= (r->last_os->output_section_statement
+                                  .bfd_section->vma)))
+               && os->lma_region == NULL
+               && !link_info.relocatable)
+             r->last_os = s;
 
            /* .tbss sections effectively have zero size.  */
            if ((os->bfd_section->flags & SEC_HAS_CONTENTS) != 0
@@ -4301,17 +4514,11 @@ lang_size_sections_1
                  os_region_check (os, os->region, os->addr_tree,
                                   os->bfd_section->vma);
 
-               /* If there's no load address specified, use the run
-                  region as the load region.  */
-               if (os->lma_region == NULL && os->load_base == NULL)
-                 os->lma_region = os->region;
-
                if (os->lma_region != NULL && os->lma_region != os->region)
                  {
-                   /* Set load_base, which will be handled later.  */
-                   os->load_base = exp_intop (os->lma_region->current);
-                   os->lma_region->current +=
-                     TO_ADDR (os->bfd_section->size);
+                   os->lma_region->current
+                     = os->bfd_section->lma + TO_ADDR (os->bfd_section->size);
+
                    if (check_regions)
                      os_region_check (os, os->lma_region, NULL,
                                       os->bfd_section->lma);
@@ -4427,12 +4634,42 @@ lang_size_sections_1
        case lang_assignment_statement_enum:
          {
            bfd_vma newdot = dot;
+           etree_type *tree = s->assignment_statement.exp;
+
+           expld.dataseg.relro = exp_dataseg_relro_none;
 
-           exp_fold_tree (s->assignment_statement.exp,
+           exp_fold_tree (tree,
                           output_section_statement->bfd_section,
                           &newdot);
 
-           if (newdot != dot && !output_section_statement->ignored)
+           if (expld.dataseg.relro == exp_dataseg_relro_start)
+             {
+               if (!expld.dataseg.relro_start_stat)
+                 expld.dataseg.relro_start_stat = s;
+               else
+                 {
+                   ASSERT (expld.dataseg.relro_start_stat == s);
+                 }
+             }
+           else if (expld.dataseg.relro == exp_dataseg_relro_end)
+             {
+               if (!expld.dataseg.relro_end_stat)
+                 expld.dataseg.relro_end_stat = s;
+               else
+                 {
+                   ASSERT (expld.dataseg.relro_end_stat == s);
+                 }
+             }
+           expld.dataseg.relro = exp_dataseg_relro_none;
+
+           /* This symbol is relative to this section.  */
+           if ((tree->type.node_class == etree_provided
+                || tree->type.node_class == etree_assign)
+               && (tree->assign.dst [0] != '.'
+                   || tree->assign.dst [1] != '\0'))
+             output_section_statement->section_relative_symbol = 1;
+
+           if (!output_section_statement->ignored)
              {
                if (output_section_statement == abs_output_section)
                  {
@@ -4441,7 +4678,7 @@ lang_size_sections_1
                    lang_memory_region_lookup (DEFAULT_MEMORY_REGION,
                                               FALSE)->current = newdot;
                  }
-               else
+               else if (newdot != dot)
                  {
                    /* Insert a pad after this statement.  We can't
                       put the pad before when relaxing, in case the
@@ -4502,6 +4739,48 @@ lang_size_sections_1
   return dot;
 }
 
+/* Callback routine that is used in _bfd_elf_map_sections_to_segments.
+   The BFD library has set NEW_SEGMENT to TRUE iff it thinks that
+   CURRENT_SECTION and PREVIOUS_SECTION ought to be placed into different
+   segments.  We are allowed an opportunity to override this decision.  */
+
+bfd_boolean
+ldlang_override_segment_assignment (struct bfd_link_info * info ATTRIBUTE_UNUSED,
+                                   bfd * abfd ATTRIBUTE_UNUSED,
+                                   asection * current_section,
+                                   asection * previous_section,
+                                   bfd_boolean new_segment)
+{
+  lang_output_section_statement_type * cur;
+  lang_output_section_statement_type * prev;
+
+  /* The checks below are only necessary when the BFD library has decided
+     that the two sections ought to be placed into the same segment.  */
+  if (new_segment)
+    return TRUE;
+
+  /* Paranoia checks.  */
+  if (current_section == NULL || previous_section == NULL)
+    return new_segment;
+
+  /* Find the memory regions associated with the two sections.
+     We call lang_output_section_find() here rather than scanning the list
+     of output sections looking for a matching section pointer because if
+     we have a large number of sections then a hash lookup is faster.  */
+  cur  = lang_output_section_find (current_section->name);
+  prev = lang_output_section_find (previous_section->name);
+
+  /* More paranoia.  */
+  if (cur == NULL || prev == NULL)
+    return new_segment;
+
+  /* If the regions are different then force the sections to live in
+     different segments.  See the email thread starting at the following
+     URL for the reasons why this is necessary:
+     http://sourceware.org/ml/binutils/2007-02/msg00216.html  */
+  return cur->region != prev->region;
+}
+
 void
 one_lang_size_sections_pass (bfd_boolean *relax, bfd_boolean check_regions)
 {
@@ -4593,11 +4872,10 @@ lang_size_sections (bfd_boolean *relax, bfd_boolean check_regions)
 /* Worker function for lang_do_assignments.  Recursiveness goes here.  */
 
 static bfd_vma
-lang_do_assignments_1
-  (lang_statement_union_type *s,
-   lang_output_section_statement_type *output_section_statement,
-   fill_type *fill,
-   bfd_vma dot)
+lang_do_assignments_1 (lang_statement_union_type *s,
+                      lang_output_section_statement_type *current_os,
+                      fill_type *fill,
+                      bfd_vma dot)
 {
   for (; s != NULL; s = s->header.next)
     {
@@ -4605,9 +4883,7 @@ lang_do_assignments_1
        {
        case lang_constructors_statement_enum:
          dot = lang_do_assignments_1 (constructor_list.head,
-                                      output_section_statement,
-                                      fill,
-                                      dot);
+                                      current_os, fill, dot);
          break;
 
        case lang_output_section_statement_enum:
@@ -4618,31 +4894,22 @@ lang_do_assignments_1
            if (os->bfd_section != NULL && !os->ignored)
              {
                dot = os->bfd_section->vma;
+
                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)
-             {
-               /* If nothing has been placed into the output section then
-                  it won't have a bfd_section.  */
-               if (os->bfd_section && !os->ignored)
-                 {
-                   os->bfd_section->lma
-                     = exp_get_abs_int (os->load_base, 0, "load base");
-                 }
-             }
          }
          break;
 
        case lang_wild_statement_enum:
 
          dot = lang_do_assignments_1 (s->wild_statement.children.head,
-                                      output_section_statement,
-                                      fill, dot);
+                                      current_os, fill, dot);
          break;
 
        case lang_object_symbols_statement_enum:
@@ -4711,7 +4978,7 @@ lang_do_assignments_1
 
        case lang_assignment_statement_enum:
          exp_fold_tree (s->assignment_statement.exp,
-                        output_section_statement->bfd_section,
+                        current_os->bfd_section,
                         &dot);
          break;
 
@@ -4721,8 +4988,7 @@ lang_do_assignments_1
 
        case lang_group_statement_enum:
          dot = lang_do_assignments_1 (s->group_statement.children.head,
-                                      output_section_statement,
-                                      fill, dot);
+                                      current_os, fill, dot);
          break;
 
        default:
@@ -4918,7 +5184,7 @@ lang_check (void)
       if (compatible == NULL)
        {
          if (command_line.warn_mismatch)
-           einfo (_("%P: warning: %s architecture of input file `%B'"
+           einfo (_("%P%X: %s architecture of input file `%B'"
                     " is incompatible with %s output\n"),
                   bfd_printable_name (input_bfd), input_bfd,
                   bfd_printable_name (output_bfd));
@@ -5029,10 +5295,19 @@ lang_one_common (struct bfd_link_hash_entry *h, void *info)
          header_printed = TRUE;
        }
 
-      name = demangle (h->root.string);
-      minfo ("%s", name);
-      len = strlen (name);
-      free (name);
+      name = bfd_demangle (output_bfd, h->root.string,
+                          DMGL_ANSI | DMGL_PARAMS);
+      if (name == NULL)
+       {
+         minfo ("%s", h->root.string);
+         len = strlen (h->root.string);
+       }
+      else
+       {
+         minfo ("%s", name);
+         len = strlen (name);
+         free (name);
+       }
 
       if (len >= 19)
        {
@@ -5188,8 +5463,6 @@ lang_for_each_file (void (*func) (lang_input_statement_type *))
 void
 ldlang_add_file (lang_input_statement_type *entry)
 {
-  bfd **pp;
-
   lang_statement_append (&file_chain,
                         (lang_statement_union_type *) entry,
                         &entry->next);
@@ -5198,9 +5471,9 @@ ldlang_add_file (lang_input_statement_type *entry)
      a link.  */
   ASSERT (entry->the_bfd->link_next == NULL);
   ASSERT (entry->the_bfd != output_bfd);
-  for (pp = &link_info.input_bfds; *pp != NULL; pp = &(*pp)->link_next)
-    ;
-  *pp = entry->the_bfd;
+
+  *link_info.input_bfds_tail = entry->the_bfd;
+  link_info.input_bfds_tail = &entry->the_bfd->link_next;
   entry->the_bfd->usrdata = entry;
   bfd_set_gp_size (entry->the_bfd, g_switch_value);
 
@@ -5307,14 +5580,17 @@ lang_reset_memory_regions (void)
 
   for (p = lang_memory_region_list; p != NULL; p = p->next)
     {
-      p->old_length = (bfd_size_type) (p->current - p->origin);
       p->current = p->origin;
+      p->last_os = NULL;
     }
 
   for (os = &lang_output_section_statement.head->output_section_statement;
        os != NULL;
        os = os->next)
-    os->processed = FALSE;
+    {
+      os->processed_vma = FALSE;
+      os->processed_lma = FALSE;
+    }
 
   for (o = output_bfd->sections; o != NULL; o = o->next)
     {
@@ -5411,6 +5687,81 @@ lang_gc_sections (void)
     bfd_gc_sections (output_bfd, &link_info);
 }
 
+/* Worker for lang_find_relro_sections_1.  */
+
+static void
+find_relro_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)
+{
+  /* Discarded, excluded and ignored sections effectively have zero
+     size.  */
+  if (section->output_section != NULL
+      && section->output_section->owner == output_bfd
+      && (section->output_section->flags & SEC_EXCLUDE) == 0
+      && !IGNORE_SECTION (section)
+      && section->size != 0)
+    {
+      bfd_boolean *has_relro_section = (bfd_boolean *) data;
+      *has_relro_section = TRUE;
+    }
+}
+
+/* Iterate over sections for relro sections.  */
+
+static void
+lang_find_relro_sections_1 (lang_statement_union_type *s,
+                           bfd_boolean *has_relro_section)
+{
+  if (*has_relro_section)
+    return;
+
+  for (; s != NULL; s = s->header.next)
+    {
+      if (s == expld.dataseg.relro_end_stat)
+       break;
+
+      switch (s->header.type)
+       {
+       case lang_wild_statement_enum:
+         walk_wild (&s->wild_statement,
+                    find_relro_section_callback,
+                    has_relro_section);
+         break;
+       case lang_constructors_statement_enum:
+         lang_find_relro_sections_1 (constructor_list.head,
+                                     has_relro_section);
+         break;
+       case lang_output_section_statement_enum:
+         lang_find_relro_sections_1 (s->output_section_statement.children.head,
+                                     has_relro_section);
+         break;
+       case lang_group_statement_enum:
+         lang_find_relro_sections_1 (s->group_statement.children.head,
+                                     has_relro_section);
+         break;
+       default:
+         break;
+       }
+    }
+}
+
+static void
+lang_find_relro_sections (void)
+{
+  bfd_boolean has_relro_section = FALSE;
+
+  /* Check all sections in the link script.  */
+
+  lang_find_relro_sections_1 (expld.dataseg.relro_start_stat,
+                             &has_relro_section);
+
+  if (!has_relro_section)
+    link_info.relro = FALSE;
+}
+
 /* Relax all sections until bfd_relax_section gives up.  */
 
 static void
@@ -5419,9 +5770,11 @@ relax_sections (void)
   /* Keep relaxing until bfd_relax_section gives up.  */
   bfd_boolean relax_again;
 
+  link_info.relax_trip = -1;
   do
     {
-      relax_again = FALSE; 
+      relax_again = FALSE;
+      link_info.relax_trip++;
 
       /* Note: pe-dll.c does something like this also.  If you find
         you need to change this code, you probably need to change
@@ -5445,6 +5798,10 @@ relax_sections (void)
 void
 lang_process (void)
 {
+  /* Finalize dynamic list.  */
+  if (link_info.dynamic_list)
+    lang_finalize_version_expr_head (&link_info.dynamic_list->head);
+
   current_target = default_target;
 
   /* Open the output file.  */
@@ -5532,6 +5889,10 @@ lang_process (void)
      section positions, since they will affect SIZEOF_HEADERS.  */
   lang_record_phdrs ();
 
+  /* Check relro sections.  */
+  if (link_info.relro && ! link_info.relocatable)
+    lang_find_relro_sections ();
+
   /* Size up the sections.  */
   lang_size_sections (NULL, !command_line.relax);
 
@@ -5568,13 +5929,13 @@ lang_process (void)
 
   lang_do_assignments ();
 
+  ldemul_finish ();
+
   /* Make sure that the section addresses make sense.  */
   if (! link_info.relocatable
       && command_line.check_section_addresses)
     lang_check_section_addresses ();
 
-  /* Final stuffs.  */
-  ldemul_finish ();
   lang_end ();
 }
 
@@ -5977,6 +6338,7 @@ lang_record_phdrs (void)
   alc = 10;
   secs = xmalloc (alc * sizeof (asection *));
   last = NULL;
+
   for (l = lang_phdr_list; l != NULL; l = l->next)
     {
       unsigned int c;
@@ -6002,6 +6364,28 @@ lang_record_phdrs (void)
                  || os->bfd_section == NULL
                  || (os->bfd_section->flags & SEC_ALLOC) == 0)
                continue;
+
+             if (last == NULL)
+               {
+                 lang_output_section_statement_type * tmp_os;
+
+                 /* If we have not run across a section with a program
+                    header assigned to it yet, then scan forwards to find
+                    one.  This prevents inconsistencies in the linker's
+                    behaviour when a script has specified just a single
+                    header and there are sections in that script which are
+                    not assigned to it, and which occur before the first
+                    use of that header. See here for more details:
+                    http://sourceware.org/ml/binutils/2007-02/msg00291.html  */
+                 for (tmp_os = os; tmp_os; tmp_os = tmp_os->next)
+                   if (tmp_os->phdrs)
+                     {
+                       last = tmp_os->phdrs;
+                       break;
+                     }
+                 if (last == NULL)
+                   einfo (_("%F%P: no sections assigned to phdrs\n"));
+               }
              pl = last;
            }
 
@@ -6121,7 +6505,7 @@ lang_enter_overlay_section (const char *name)
   struct overlay_list *n;
   etree_type *size;
 
-  lang_enter_output_section_statement (name, overlay_vma, normal_section,
+  lang_enter_output_section_statement (name, overlay_vma, overlay_section,
                                       0, overlay_subalign, 0, 0);
 
   /* If this is the first section, then base the VMA of future
@@ -6176,15 +6560,17 @@ lang_leave_overlay_section (fill_type *fill,
 
   buf = xmalloc (strlen (clean) + sizeof "__load_start_");
   sprintf (buf, "__load_start_%s", clean);
-  lang_add_assignment (exp_assop ('=', buf,
-                                 exp_nameop (LOADADDR, name)));
+  lang_add_assignment (exp_provide (buf,
+                                   exp_nameop (LOADADDR, name),
+                                   FALSE));
 
   buf = xmalloc (strlen (clean) + sizeof "__load_stop_");
   sprintf (buf, "__load_stop_%s", clean);
-  lang_add_assignment (exp_assop ('=', buf,
-                                 exp_binop ('+',
-                                            exp_nameop (LOADADDR, name),
-                                            exp_nameop (SIZEOF, name))));
+  lang_add_assignment (exp_provide (buf,
+                                   exp_binop ('+',
+                                              exp_nameop (LOADADDR, name),
+                                              exp_nameop (SIZEOF, name)),
+                                   FALSE));
 
   free (clean);
 }
@@ -6233,12 +6619,10 @@ lang_leave_overlay (etree_type *lma_expr,
         The base address is not needed (and should be null) if
         an LMA region was specified.  */
       if (l->next == 0)
-       l->os->load_base = lma_expr;
-      else if (lma_region == 0)
-       l->os->load_base = exp_binop ('+',
-                                     exp_nameop (LOADADDR, l->next->os->name),
-                                     exp_nameop (SIZEOF, l->next->os->name));
-
+       {
+         l->os->load_base = lma_expr;
+         l->os->sectype = normal_section;
+       }
       if (phdrs != NULL && l->os->phdrs == NULL)
        l->os->phdrs = phdrs;
 
@@ -6729,7 +7113,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.  */
-      sec->flags |= SEC_EXCLUDE;
+      sec->flags |= SEC_EXCLUDE | SEC_KEEP;
     }
 
   lreg = lang_new_vers_pattern (NULL, "*", NULL, FALSE);
@@ -6751,3 +7135,69 @@ lang_add_unique (const char *name)
   ent->next = unique_section_list;
   unique_section_list = ent;
 }
+
+/* Append the list of dynamic symbols to the existing one.  */
+
+void
+lang_append_dynamic_list (struct bfd_elf_version_expr *dynamic)
+{
+  if (link_info.dynamic_list)
+    {
+      struct bfd_elf_version_expr *tail;
+      for (tail = dynamic; tail->next != NULL; tail = tail->next)
+       ;
+      tail->next = link_info.dynamic_list->head.list;
+      link_info.dynamic_list->head.list = dynamic;
+    }
+  else
+    {
+      struct bfd_elf_dynamic_list *d;
+
+      d = xcalloc (1, sizeof *d);
+      d->head.list = dynamic;
+      d->match = lang_vers_match;
+      link_info.dynamic_list = d;
+    }
+}
+
+/* Append the list of C++ typeinfo dynamic symbols to the existing
+   one.  */
+
+void
+lang_append_dynamic_list_cpp_typeinfo (void)
+{
+  const char * symbols [] =
+    {
+      "typeinfo name for*",
+      "typeinfo for*"
+    };
+  struct bfd_elf_version_expr *dynamic = NULL;
+  unsigned int i;
+
+  for (i = 0; i < ARRAY_SIZE (symbols); i++)
+    dynamic = lang_new_vers_pattern (dynamic, symbols [i], "C++",
+                                    FALSE);
+
+  lang_append_dynamic_list (dynamic);
+}
+
+/* Append the list of C++ operator new and delete dynamic symbols to the
+   existing one.  */
+
+void
+lang_append_dynamic_list_cpp_new (void)
+{
+  const char * symbols [] =
+    {
+      "operator new*",
+      "operator delete*"
+    };
+  struct bfd_elf_version_expr *dynamic = NULL;
+  unsigned int i;
+
+  for (i = 0; i < ARRAY_SIZE (symbols); i++)
+    dynamic = lang_new_vers_pattern (dynamic, symbols [i], "C++",
+                                    FALSE);
+
+  lang_append_dynamic_list (dynamic);
+}
This page took 0.042448 seconds and 4 git commands to generate.