Explicit locations: introduce explicit locations
[deliverable/binutils-gdb.git] / ld / ldlang.c
index 9e355273fdef38037d852dc14979dfb12551f0b6..0d6419d91ddaadc7d5449bd7ddcb77f8fc35d7d3 100644 (file)
@@ -1,5 +1,5 @@
 /* Linker command language support.
-   Copyright 1991-2013 Free Software Foundation, Inc.
+   Copyright (C) 1991-2015 Free Software Foundation, Inc.
 
    This file is part of the GNU Binutils.
 
@@ -40,6 +40,7 @@
 #include "demangle.h"
 #include "hashtab.h"
 #include "libbfd.h"
+#include "elf-bfd.h"
 #ifdef ENABLE_PLUGINS
 #include "plugin.h"
 #endif /* ENABLE_PLUGINS */
@@ -56,23 +57,21 @@ static struct obstack map_obstack;
 #define obstack_chunk_free free
 static const char *entry_symbol_default = "start";
 static bfd_boolean placed_commons = FALSE;
-static bfd_boolean stripped_excluded_sections = FALSE;
+static bfd_boolean map_head_is_link_order = FALSE;
 static lang_output_section_statement_type *default_common_section;
 static bfd_boolean map_option_f;
 static bfd_vma print_dot;
 static lang_input_statement_type *first_file;
 static const char *current_target;
 static lang_statement_list_type statement_list;
-static struct bfd_hash_table lang_definedness_table;
 static lang_statement_list_type *stat_save[10];
 static lang_statement_list_type **stat_save_ptr = &stat_save[0];
 static struct unique_sections *unique_section_list;
+static struct asneeded_minfo *asneeded_list_head;
 
 /* Forward declarations.  */
 static void exp_init_os (etree_type *);
 static lang_input_statement_type *lookup_name (const char *);
-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 bfd_boolean sort_def_symbol (struct bfd_link_hash_entry *, void *);
 static void print_statement (lang_statement_union_type *,
@@ -86,6 +85,7 @@ 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 *);
+static void lang_do_memory_regions (void);
 
 /* Exported variables.  */
 const char *output_target;
@@ -105,13 +105,12 @@ 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;
+struct asneeded_minfo **asneeded_list_tail;
 
  /* Functions that traverse the linker script and might evaluate
     DEFINED() need to increment this at the start of the traversal.  */
 int lang_statement_iteration = 0;
 
-etree_type *base; /* Relocation base - or null */
-
 /* Return TRUE if the PATTERN argument is a wildcard pattern.
    Although backslashes are treated specially if a pattern contains
    wildcards, we do not consider the mere presence of a backslash to
@@ -1061,13 +1060,6 @@ new_afile (const char *name,
   p->flags.whole_archive = input_flags.whole_archive;
   p->flags.sysrooted = input_flags.sysrooted;
 
-  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:
@@ -1081,7 +1073,13 @@ new_afile (const char *name,
       p->local_sym_name = name;
       break;
     case lang_input_file_is_l_enum:
-      p->filename = name;
+      if (name[0] == ':' && name[1] != '\0')
+        {
+          p->filename = name + 1;
+          p->flags.full_name_provided = TRUE;
+        }
+      else
+        p->filename = name;
       p->local_sym_name = concat ("-l", name, (const char *) NULL);
       p->flags.maybe_archive = TRUE;
       p->flags.real = TRUE;
@@ -1118,6 +1116,26 @@ lang_add_input_file (const char *name,
                     lang_input_file_enum_type file_type,
                     const char *target)
 {
+  if (name != NULL && *name == '=')
+    {
+      lang_input_statement_type *ret;
+      char *sysrooted_name
+       = concat (ld_sysroot, name + 1, (const char *) NULL);
+
+      /* We've now forcibly prepended the sysroot, making the input
+        file independent of the context.  Therefore, temporarily
+        force a non-sysrooted context for this statement, so it won't
+        get the sysroot prepended again when opened.  (N.B. if it's a
+        script, any child nodes with input files starting with "/"
+        will be handled as "sysrooted" as they'll be found to be
+        within the sysroot subdirectory.)  */
+      unsigned int outer_sysrooted = input_flags.sysrooted;
+      input_flags.sysrooted = 0;
+      ret = new_afile (sysrooted_name, file_type, target, TRUE);
+      input_flags.sysrooted = outer_sysrooted;
+      return ret;
+    }
+
   return new_afile (name, file_type, target, TRUE);
 }
 
@@ -1221,20 +1239,13 @@ lang_init (void)
 
   abs_output_section->bfd_section = bfd_abs_section_ptr;
 
-  /* The value "13" is ad-hoc, somewhat related to the expected number of
-     assignments in a linker script.  */
-  if (!bfd_hash_table_init_n (&lang_definedness_table,
-                             lang_definedness_newfunc,
-                             sizeof (struct lang_definedness_hash_entry),
-                             13))
-    einfo (_("%P%F: can not create hash table: %E\n"));
+  asneeded_list_head = NULL;
+  asneeded_list_tail = &asneeded_list_head;
 }
 
 void
 lang_finish (void)
 {
-  bfd_link_hash_table_free (link_info.output_bfd, link_info.hash);
-  bfd_hash_table_free (&lang_definedness_table);
   output_section_statement_table_free ();
 }
 
@@ -1295,7 +1306,9 @@ lang_memory_region_lookup (const char *const name, bfd_boolean create)
   new_region->name_list.name = xstrdup (name);
   new_region->name_list.next = NULL;
   new_region->next = NULL;
+  new_region->origin_exp = NULL;
   new_region->origin = 0;
+  new_region->length_exp = NULL;
   new_region->length = ~(bfd_size_type) 0;
   new_region->current = 0;
   new_region->last_os = NULL;
@@ -1490,7 +1503,7 @@ lang_output_section_find_by_flags (const asection *sec,
                                   lang_match_sec_type_func match_type)
 {
   lang_output_section_statement_type *first, *look, *found;
-  flagword flags;
+  flagword look_flags, sec_flags, differ;
 
   /* We know the first statement on this list is *ABS*.  May as well
      skip it.  */
@@ -1498,21 +1511,22 @@ lang_output_section_find_by_flags (const asection *sec,
   first = first->next;
 
   /* First try for an exact match.  */
+  sec_flags = sec->flags;
   found = NULL;
   for (look = first; look; look = look->next)
     {
-      flags = look->flags;
+      look_flags = look->flags;
       if (look->bfd_section != NULL)
        {
-         flags = look->bfd_section->flags;
+         look_flags = look->bfd_section->flags;
          if (match_type && !match_type (link_info.output_bfd,
                                         look->bfd_section,
                                         sec->owner, sec))
            continue;
        }
-      flags ^= sec->flags;
-      if (!(flags & (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_READONLY
-                    | SEC_CODE | SEC_SMALL_DATA | SEC_THREAD_LOCAL)))
+      differ = look_flags ^ sec_flags;
+      if (!(differ & (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_READONLY
+                     | SEC_CODE | SEC_SMALL_DATA | SEC_THREAD_LOCAL)))
        found = look;
     }
   if (found != NULL)
@@ -1522,115 +1536,144 @@ lang_output_section_find_by_flags (const asection *sec,
       return found;
     }
 
-  if ((sec->flags & SEC_CODE) != 0
-      && (sec->flags & SEC_ALLOC) != 0)
+  if ((sec_flags & SEC_CODE) != 0
+      && (sec_flags & SEC_ALLOC) != 0)
     {
       /* Try for a rw code section.  */
       for (look = first; look; look = look->next)
        {
-         flags = look->flags;
+         look_flags = look->flags;
          if (look->bfd_section != NULL)
            {
-             flags = look->bfd_section->flags;
+             look_flags = look->bfd_section->flags;
              if (match_type && !match_type (link_info.output_bfd,
                                             look->bfd_section,
                                             sec->owner, sec))
                continue;
            }
-         flags ^= sec->flags;
-         if (!(flags & (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD
-                        | SEC_CODE | SEC_SMALL_DATA | SEC_THREAD_LOCAL)))
+         differ = look_flags ^ sec_flags;
+         if (!(differ & (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD
+                         | SEC_CODE | SEC_SMALL_DATA | SEC_THREAD_LOCAL)))
            found = look;
        }
     }
-  else if ((sec->flags & (SEC_READONLY | SEC_THREAD_LOCAL)) != 0
-          && (sec->flags & SEC_ALLOC) != 0)
+  else if ((sec_flags & SEC_READONLY) != 0
+          && (sec_flags & SEC_ALLOC) != 0)
     {
       /* .rodata can go after .text, .sdata2 after .rodata.  */
       for (look = first; look; look = look->next)
        {
-         flags = look->flags;
+         look_flags = look->flags;
          if (look->bfd_section != NULL)
            {
-             flags = look->bfd_section->flags;
+             look_flags = look->bfd_section->flags;
              if (match_type && !match_type (link_info.output_bfd,
                                             look->bfd_section,
                                             sec->owner, sec))
                continue;
            }
-         flags ^= sec->flags;
-         if (!(flags & (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD
-                        | SEC_READONLY | SEC_SMALL_DATA))
-             || (!(flags & (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD
-                            | SEC_READONLY))
-                 && !(look->flags & SEC_SMALL_DATA))
-             || (!(flags & (SEC_THREAD_LOCAL | SEC_ALLOC))
-                 && (look->flags & SEC_THREAD_LOCAL)
-                 && (!(flags & SEC_LOAD)
-                     || (look->flags & SEC_LOAD))))
+         differ = look_flags ^ sec_flags;
+         if (!(differ & (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD
+                         | SEC_READONLY | SEC_SMALL_DATA))
+             || (!(differ & (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD
+                             | SEC_READONLY))
+                 && !(look_flags & SEC_SMALL_DATA)))
+           found = look;
+       }
+    }
+  else if ((sec_flags & SEC_THREAD_LOCAL) != 0
+          && (sec_flags & SEC_ALLOC) != 0)
+    {
+      /* .tdata can go after .data, .tbss after .tdata.  Treat .tbss
+        as if it were a loaded section, and don't use match_type.  */
+      bfd_boolean seen_thread_local = FALSE;
+
+      match_type = NULL;
+      for (look = first; look; look = look->next)
+       {
+         look_flags = look->flags;
+         if (look->bfd_section != NULL)
+           look_flags = look->bfd_section->flags;
+
+         differ = look_flags ^ (sec_flags | SEC_LOAD | SEC_HAS_CONTENTS);
+         if (!(differ & (SEC_THREAD_LOCAL | SEC_ALLOC)))
+           {
+             /* .tdata and .tbss must be adjacent and in that order.  */
+             if (!(look_flags & SEC_LOAD)
+                 && (sec_flags & SEC_LOAD))
+               /* ..so if we're at a .tbss section and we're placing
+                  a .tdata section stop looking and return the
+                  previous section.  */
+               break;
+             found = look;
+             seen_thread_local = TRUE;
+           }
+         else if (seen_thread_local)
+           break;
+         else if (!(differ & (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD)))
            found = look;
        }
     }
-  else if ((sec->flags & SEC_SMALL_DATA) != 0
-          && (sec->flags & SEC_ALLOC) != 0)
+  else if ((sec_flags & SEC_SMALL_DATA) != 0
+          && (sec_flags & SEC_ALLOC) != 0)
     {
       /* .sdata goes after .data, .sbss after .sdata.  */
       for (look = first; look; look = look->next)
        {
-         flags = look->flags;
+         look_flags = look->flags;
          if (look->bfd_section != NULL)
            {
-             flags = look->bfd_section->flags;
+             look_flags = look->bfd_section->flags;
              if (match_type && !match_type (link_info.output_bfd,
                                             look->bfd_section,
                                             sec->owner, sec))
                continue;
            }
-         flags ^= sec->flags;
-         if (!(flags & (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD
-                        | SEC_THREAD_LOCAL))
-             || ((look->flags & SEC_SMALL_DATA)
-                 && !(sec->flags & SEC_HAS_CONTENTS)))
+         differ = look_flags ^ sec_flags;
+         if (!(differ & (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD
+                         | SEC_THREAD_LOCAL))
+             || ((look_flags & SEC_SMALL_DATA)
+                 && !(sec_flags & SEC_HAS_CONTENTS)))
            found = look;
        }
     }
-  else if ((sec->flags & SEC_HAS_CONTENTS) != 0
-          && (sec->flags & SEC_ALLOC) != 0)
+  else if ((sec_flags & SEC_HAS_CONTENTS) != 0
+          && (sec_flags & SEC_ALLOC) != 0)
     {
       /* .data goes after .rodata.  */
       for (look = first; look; look = look->next)
        {
-         flags = look->flags;
+         look_flags = look->flags;
          if (look->bfd_section != NULL)
            {
-             flags = look->bfd_section->flags;
+             look_flags = look->bfd_section->flags;
              if (match_type && !match_type (link_info.output_bfd,
                                             look->bfd_section,
                                             sec->owner, sec))
                continue;
            }
-         flags ^= sec->flags;
-         if (!(flags & (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD
-                        | SEC_SMALL_DATA | SEC_THREAD_LOCAL)))
+         differ = look_flags ^ sec_flags;
+         if (!(differ & (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD
+                         | SEC_SMALL_DATA | SEC_THREAD_LOCAL)))
            found = look;
        }
     }
-  else if ((sec->flags & SEC_ALLOC) != 0)
+  else if ((sec_flags & SEC_ALLOC) != 0)
     {
       /* .bss goes after any other alloc section.  */
       for (look = first; look; look = look->next)
        {
-         flags = look->flags;
+         look_flags = look->flags;
          if (look->bfd_section != NULL)
            {
-             flags = look->bfd_section->flags;
+             look_flags = look->bfd_section->flags;
              if (match_type && !match_type (link_info.output_bfd,
                                             look->bfd_section,
                                             sec->owner, sec))
                continue;
            }
-         flags ^= sec->flags;
-         if (!(flags & SEC_ALLOC))
+         differ = look_flags ^ sec_flags;
+         if (!(differ & SEC_ALLOC))
            found = look;
        }
     }
@@ -1639,11 +1682,11 @@ lang_output_section_find_by_flags (const asection *sec,
       /* non-alloc go last.  */
       for (look = first; look; look = look->next)
        {
-         flags = look->flags;
+         look_flags = look->flags;
          if (look->bfd_section != NULL)
-           flags = look->bfd_section->flags;
-         flags ^= sec->flags;
-         if (!(flags & SEC_DEBUGGING))
+           look_flags = look->bfd_section->flags;
+         differ = look_flags ^ sec_flags;
+         if (!(differ & SEC_DEBUGGING))
            found = look;
        }
       return found;
@@ -1953,6 +1996,43 @@ lang_insert_orphan (asection *s,
   return os;
 }
 
+static void
+lang_print_asneeded (void)
+{
+  struct asneeded_minfo *m;
+  char buf[100];
+
+  if (asneeded_list_head == NULL)
+    return;
+
+  sprintf (buf, _("\nAs-needed library included "
+                 "to satisfy reference by file (symbol)\n\n"));
+  minfo ("%s", buf);
+
+  for (m = asneeded_list_head; m != NULL; m = m->next)
+    {
+      size_t len;
+
+      minfo ("%s", m->soname);
+      len = strlen (m->soname);
+
+      if (len >= 29)
+       {
+         print_nl ();
+         len = 0;
+       }
+      while (len < 30)
+       {
+         print_space ();
+         ++len;
+       }
+
+      if (m->ref != NULL)
+       minfo ("%B ", m->ref);
+      minfo ("(%T)\n", m->name);
+    }
+}
+
 static void
 lang_map_flags (flagword flag)
 {
@@ -2052,6 +2132,8 @@ lang_map (void)
     }
   lang_statement_iteration++;
   print_statements ();
+
+  ldemul_extra_map_file_text (link_info.output_bfd, &link_info, config.map_file);
 }
 
 static bfd_boolean
@@ -2340,8 +2422,7 @@ lang_add_section (lang_statement_list_type *ptr,
 
   section->output_section = output->bfd_section;
 
-  if (!link_info.relocatable
-      && !stripped_excluded_sections)
+  if (!map_head_is_link_order)
     {
       asection *s = output->bfd_section->map_tail.s;
       output->bfd_section->map_tail.s = section;
@@ -2720,9 +2801,7 @@ load_symbols (lang_input_statement_type *entry,
       break;
 
     case bfd_object:
-#ifdef ENABLE_PLUGINS
       if (!entry->flags.reload)
-#endif
        ldlang_add_file (entry);
       if (trace_files || verbose)
        info_msg ("%I\n", entry);
@@ -3198,38 +3277,33 @@ open_input_bfds (lang_statement_union_type *s, enum open_bfd_mode mode)
            {
              lang_statement_union_type **os_tail;
              lang_statement_list_type add;
+             bfd *abfd;
 
              s->input_statement.target = current_target;
 
              /* If we are being called from within a group, and this
                 is an archive which has already been searched, then
                 force it to be researched unless the whole archive
-                has been loaded already.  Do the same for a rescan.  */
+                has been loaded already.  Do the same for a rescan.
+                Likewise reload --as-needed shared libs.  */
              if (mode != OPEN_BFD_NORMAL
 #ifdef ENABLE_PLUGINS
                  && ((mode & OPEN_BFD_RESCAN) == 0
                      || plugin_insert == NULL)
 #endif
-                 && !s->input_statement.flags.whole_archive
                  && s->input_statement.flags.loaded
-                 && s->input_statement.the_bfd != NULL
-                 && bfd_check_format (s->input_statement.the_bfd,
-                                      bfd_archive))
-               s->input_statement.flags.loaded = FALSE;
-#ifdef ENABLE_PLUGINS
-             /* When rescanning, reload --as-needed shared libs.  */
-             else if ((mode & OPEN_BFD_RESCAN) != 0
-                      && plugin_insert == NULL
-                      && s->input_statement.flags.loaded
-                      && s->input_statement.flags.add_DT_NEEDED_for_regular
-                      && s->input_statement.the_bfd != NULL
-                      && ((s->input_statement.the_bfd->flags) & DYNAMIC) != 0
-                      && plugin_should_reload (s->input_statement.the_bfd))
+                 && (abfd = s->input_statement.the_bfd) != NULL
+                 && ((bfd_get_format (abfd) == bfd_archive
+                      && !s->input_statement.flags.whole_archive)
+                     || (bfd_get_format (abfd) == bfd_object
+                         && ((abfd->flags) & DYNAMIC) != 0
+                         && s->input_statement.flags.add_DT_NEEDED_for_regular
+                         && bfd_get_flavour (abfd) == bfd_target_elf_flavour
+                         && (elf_dyn_lib_class (abfd) & DYN_AS_NEEDED) != 0)))
                {
                  s->input_statement.flags.loaded = FALSE;
                  s->input_statement.flags.reload = TRUE;
                }
-#endif
 
              os_tail = lang_output_section_statement.tail;
              lang_list_init (&add);
@@ -3282,65 +3356,6 @@ open_input_bfds (lang_statement_union_type *s, enum open_bfd_mode mode)
     einfo ("%F");
 }
 
-/* New-function for the definedness hash table.  */
-
-static struct bfd_hash_entry *
-lang_definedness_newfunc (struct bfd_hash_entry *entry,
-                         struct bfd_hash_table *table ATTRIBUTE_UNUSED,
-                         const char *name ATTRIBUTE_UNUSED)
-{
-  struct lang_definedness_hash_entry *ret
-    = (struct lang_definedness_hash_entry *) entry;
-
-  if (ret == NULL)
-    ret = (struct lang_definedness_hash_entry *)
-      bfd_hash_allocate (table, sizeof (struct lang_definedness_hash_entry));
-
-  if (ret == NULL)
-    einfo (_("%P%F: bfd_hash_allocate failed creating symbol %s\n"), name);
-
-  ret->by_object = 0;
-  ret->by_script = 0;
-  ret->iteration = 0;
-  return &ret->root;
-}
-
-/* Called during processing of linker script script expressions.
-   For symbols assigned in a linker script, return a struct describing
-   where the symbol is defined relative to the current expression,
-   otherwise return NULL.  */
-
-struct lang_definedness_hash_entry *
-lang_symbol_defined (const char *name)
-{
-  return ((struct lang_definedness_hash_entry *)
-         bfd_hash_lookup (&lang_definedness_table, name, FALSE, FALSE));
-}
-
-/* Update the definedness state of NAME.  */
-
-void
-lang_update_definedness (const char *name, struct bfd_link_hash_entry *h)
-{
-  struct lang_definedness_hash_entry *defentry
-    = (struct lang_definedness_hash_entry *)
-    bfd_hash_lookup (&lang_definedness_table, name, TRUE, FALSE);
-
-  if (defentry == NULL)
-    einfo (_("%P%F: bfd_hash_lookup failed creating symbol %s\n"), name);
-
-  /* If the symbol was already defined, and not by a script, then it
-     must be defined by an object file.  */
-  if (!defentry->by_script
-      && h->type != bfd_link_hash_undefined
-      && h->type != bfd_link_hash_common
-      && h->type != bfd_link_hash_new)
-    defentry->by_object = 1;
-
-  defentry->by_script = 1;
-  defentry->iteration = lang_statement_iteration;
-}
-
 /* Add the supplied name to the symbol table as an undefined reference.
    This is a two step process as the symbol table doesn't even exist at
    the time the ld command line is processed.  First we put the name
@@ -3398,6 +3413,55 @@ lang_place_undefineds (void)
     insert_undefined (ptr->name);
 }
 
+/* Structure used to build the list of symbols that the user has required
+   be defined.  */
+
+struct require_defined_symbol
+{
+  const char *name;
+  struct require_defined_symbol *next;
+};
+
+/* The list of symbols that the user has required be defined.  */
+
+static struct require_defined_symbol *require_defined_symbol_list;
+
+/* Add a new symbol NAME to the list of symbols that are required to be
+   defined.  */
+
+void
+ldlang_add_require_defined (const char * const name)
+{
+  struct require_defined_symbol *ptr;
+
+  ldlang_add_undef (name, TRUE);
+  ptr = (struct require_defined_symbol *) stat_alloc (sizeof (*ptr));
+  ptr->next = require_defined_symbol_list;
+  ptr->name = strdup (name);
+  require_defined_symbol_list = ptr;
+}
+
+/* Check that all symbols the user required to be defined, are defined,
+   raise an error if we find a symbol that is not defined.  */
+
+static void
+ldlang_check_require_defined_symbols (void)
+{
+  struct require_defined_symbol *ptr;
+
+  for (ptr = require_defined_symbol_list; ptr != NULL; ptr = ptr->next)
+    {
+      struct bfd_link_hash_entry *h;
+
+      h = bfd_link_hash_lookup (link_info.hash, ptr->name,
+                                FALSE, FALSE, TRUE);
+      if (h == NULL
+          || (h->type != bfd_link_hash_defined
+              && h->type != bfd_link_hash_defweak))
+        einfo(_("%P%X: required symbol `%s' not defined\n"), ptr->name);
+    }
+}
+
 /* Check for all readonly or some readwrite sections.  */
 
 static void
@@ -3848,10 +3912,6 @@ strip_excluded_output_sections (void)
              }
        }
 
-      /* TODO: Don't just junk map_head.s, turn them into link_orders.  */
-      output_section->map_head.link_order = NULL;
-      output_section->map_tail.link_order = NULL;
-
       if (exclude)
        {
          /* We don't set bfd_section to NULL since bfd_section of the
@@ -3863,10 +3923,42 @@ strip_excluded_output_sections (void)
          link_info.output_bfd->section_count--;
        }
     }
+}
+
+/* Called from ldwrite to clear out asection.map_head and
+   asection.map_tail for use as link_orders in ldwrite.
+   FIXME: Except for sh64elf.em which starts creating link_orders in
+   its after_allocation routine so needs to call it early.  */
+
+void
+lang_clear_os_map (void)
+{
+  lang_output_section_statement_type *os;
+
+  if (map_head_is_link_order)
+    return;
+
+  for (os = &lang_output_section_statement.head->output_section_statement;
+       os != NULL;
+       os = os->next)
+    {
+      asection *output_section;
+
+      if (os->constraint < 0)
+       continue;
+
+      output_section = os->bfd_section;
+      if (output_section == NULL)
+       continue;
+
+      /* TODO: Don't just junk map_head.s, turn them into link_orders.  */
+      output_section->map_head.link_order = NULL;
+      output_section->map_tail.link_order = NULL;
+    }
 
   /* Stop future calls to lang_add_section from messing with map_head
      and map_tail link_order fields.  */
-  stripped_excluded_sections = TRUE;
+  map_head_is_link_order = TRUE;
 }
 
 static void
@@ -3935,14 +4027,20 @@ print_assignment (lang_assignment_statement_type *assignment,
       const char *dst = assignment->exp->assign.dst;
 
       is_dot = (dst[0] == '.' && dst[1] == 0);
-      expld.assign_name = dst;
+      if (!is_dot)
+       expld.assign_name = dst;
       tree = assignment->exp->assign.src;
     }
 
   osec = output_section->bfd_section;
   if (osec == NULL)
     osec = bfd_abs_section_ptr;
-  exp_fold_tree (tree, osec, &print_dot);
+
+  if (assignment->exp->type.node_class != etree_provide)
+    exp_fold_tree (tree, osec, &print_dot);
+  else
+    expld.result.valid_p = FALSE;
+
   if (expld.result.valid_p)
     {
       bfd_vma value;
@@ -3980,7 +4078,10 @@ print_assignment (lang_assignment_statement_type *assignment,
     }
   else
     {
-      minfo ("*undef*   ");
+      if (assignment->exp->type.node_class == etree_provide)
+        minfo ("[!provide]");
+      else
+        minfo ("*undef*   ");
 #ifdef BFD64
       minfo ("        ");
 #endif
@@ -4522,12 +4623,15 @@ size_input_section
 {
   lang_input_section_type *is = &((*this_ptr)->input_section);
   asection *i = is->section;
+  asection *o = output_section_statement->bfd_section;
 
-  if (i->sec_info_type != SEC_INFO_TYPE_JUST_SYMS
-      && (i->flags & SEC_EXCLUDE) == 0)
+  if (i->sec_info_type == SEC_INFO_TYPE_JUST_SYMS)
+    i->output_offset = i->vma - o->vma;
+  else if ((i->flags & SEC_EXCLUDE) != 0)
+    i->output_offset = dot - o->vma;
+  else
     {
       bfd_size_type alignment_needed;
-      asection *o;
 
       /* Align this section first to the input sections requirement,
         then to the output section's requirement.  If this alignment
@@ -4537,7 +4641,6 @@ size_input_section
       if (output_section_statement->subsection_alignment != -1)
        i->alignment_power = output_section_statement->subsection_alignment;
 
-      o = output_section_statement->bfd_section;
       if (o->alignment_power < i->alignment_power)
        o->alignment_power = i->alignment_power;
 
@@ -4550,17 +4653,12 @@ size_input_section
        }
 
       /* Remember where in the output section this input section goes.  */
-
       i->output_offset = dot - o->vma;
 
       /* Mark how big the output section must be to contain this now.  */
       dot += TO_ADDR (i->size);
       o->size = TO_SIZE (dot - o->vma);
     }
-  else
-    {
-      i->output_offset = i->vma - output_section_statement->bfd_section->vma;
-    }
 
   return dot;
 }
@@ -4735,7 +4833,7 @@ lang_size_sections_1
        {
        case lang_output_section_statement_enum:
          {
-           bfd_vma newdot, after;
+           bfd_vma newdot, after, dotdelta;
            lang_output_section_statement_type *os;
            lang_memory_region_type *r;
            int section_alignment = 0;
@@ -4801,6 +4899,7 @@ lang_size_sections_1
              }
 
            newdot = dot;
+           dotdelta = 0;
            if (bfd_is_abs_section (os->bfd_section))
              {
                /* No matter what happens, an abs section starts at zero.  */
@@ -4869,13 +4968,14 @@ lang_size_sections_1
                    bfd_vma savedot = newdot;
                    newdot = align_power (newdot, section_alignment);
 
-                   if (newdot != savedot
+                   dotdelta = newdot - savedot;
+                   if (dotdelta != 0
                        && (config.warn_section_align
                            || os->addr_tree != NULL)
                        && expld.phase != lang_mark_phase_enum)
                      einfo (_("%P: warning: changing start of section"
                               " %s by %lu bytes\n"),
-                            os->name, (unsigned long) (newdot - savedot));
+                            os->name, (unsigned long) dotdelta);
                  }
 
                bfd_set_section_vma (0, os->bfd_section, newdot);
@@ -4923,15 +5023,20 @@ lang_size_sections_1
              {
                bfd_vma lma = os->lma_region->current;
 
-               /* When LMA_REGION is the same as REGION, align the LMA
-                  as we did for the VMA, possibly including alignment
-                  from the bfd section.  If a different region, then
-                  only align according to the value in the output
-                  statement unless specified otherwise.  */
-               if (os->lma_region != os->region && !os->align_lma_with_input)
-                 section_alignment = os->section_alignment;
-               if (section_alignment > 0)
-                 lma = align_power (lma, section_alignment);
+               if (os->align_lma_with_input)
+                 lma += dotdelta;
+               else
+                 {
+                   /* When LMA_REGION is the same as REGION, align the LMA
+                      as we did for the VMA, possibly including alignment
+                      from the bfd section.  If a different region, then
+                      only align according to the value in the output
+                      statement.  */
+                   if (os->lma_region != os->region)
+                     section_alignment = os->section_alignment;
+                   if (section_alignment > 0)
+                     lma = align_power (lma, section_alignment);
+                 }
                os->bfd_section->lma = lma;
              }
            else if (r->last_os != NULL
@@ -5007,7 +5112,10 @@ lang_size_sections_1
            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);
+             dotdelta = TO_ADDR (os->bfd_section->size);
+           else
+             dotdelta = 0;
+           dot += dotdelta;
 
            if (os->update_dot_tree != 0)
              exp_fold_tree (os->update_dot_tree, bfd_abs_section_ptr, &dot);
@@ -5027,10 +5135,10 @@ lang_size_sections_1
                                   os->bfd_section->vma);
 
                if (os->lma_region != NULL && os->lma_region != os->region
-                   && (os->bfd_section->flags & SEC_LOAD))
+                   && ((os->bfd_section->flags & SEC_LOAD)
+                       || os->align_lma_with_input))
                  {
-                   os->lma_region->current
-                     = os->bfd_section->lma + TO_ADDR (os->bfd_section->size);
+                   os->lma_region->current = os->bfd_section->lma + dotdelta;
 
                    if (check_regions)
                      os_region_check (os, os->lma_region, NULL,
@@ -5131,7 +5239,7 @@ lang_size_sections_1
                  *relax = TRUE;
              }
            dot = size_input_section (prev, output_section_statement,
-                                     output_section_statement->fill, dot);
+                                     fill, dot);
          }
          break;
 
@@ -5323,55 +5431,51 @@ lang_size_sections (bfd_boolean *relax, bfd_boolean check_regions)
   if (expld.dataseg.phase == exp_dataseg_end_seen
       && link_info.relro && expld.dataseg.relro_end)
     {
-      /* If DATA_SEGMENT_ALIGN DATA_SEGMENT_RELRO_END pair was seen, try
-        to put expld.dataseg.relro_end on a (common) page boundary.  */
-      bfd_vma min_base, relro_end, maxpage;
+      bfd_vma initial_base, relro_end, desired_end;
+      asection *sec;
 
-      expld.dataseg.phase = exp_dataseg_relro_adjust;
-      maxpage = expld.dataseg.maxpagesize;
-      /* MIN_BASE is the absolute minimum address we are allowed to start the
-        read-write segment (byte before will be mapped read-only).  */
-      min_base = (expld.dataseg.min_base + maxpage - 1) & ~(maxpage - 1);
-      expld.dataseg.base += (-expld.dataseg.relro_end
-                            & (expld.dataseg.pagesize - 1));
       /* Compute the expected PT_GNU_RELRO segment end.  */
       relro_end = ((expld.dataseg.relro_end + expld.dataseg.pagesize - 1)
                   & ~(expld.dataseg.pagesize - 1));
-      if (min_base + maxpage < expld.dataseg.base)
-       {
-         expld.dataseg.base -= maxpage;
-         relro_end -= maxpage;
-       }
+
+      /* Adjust by the offset arg of DATA_SEGMENT_RELRO_END.  */
+      desired_end = relro_end - expld.dataseg.relro_offset;
+
+      /* For sections in the relro segment..  */
+      for (sec = link_info.output_bfd->section_last; sec; sec = sec->prev)
+       if (!IGNORE_SECTION (sec)
+           && sec->vma >= expld.dataseg.base
+           && sec->vma < expld.dataseg.relro_end - expld.dataseg.relro_offset)
+         {
+           /* Where do we want to put this section so that it ends as
+              desired?  */
+           bfd_vma start = sec->vma;
+           bfd_vma end = start + sec->size;
+           bfd_vma bump = desired_end - end;
+           /* We'd like to increase START by BUMP, but we must heed
+              alignment so the increase might be less than optimum.  */
+           start += bump & ~(((bfd_vma) 1 << sec->alignment_power) - 1);
+           /* This is now the desired end for the previous section.  */
+           desired_end = start;
+         }
+
+      expld.dataseg.phase = exp_dataseg_relro_adjust;
+      ASSERT (desired_end >= expld.dataseg.base);
+      initial_base = expld.dataseg.base;
+      expld.dataseg.base = desired_end;
       lang_reset_memory_regions ();
       one_lang_size_sections_pass (relax, check_regions);
+
       if (expld.dataseg.relro_end > relro_end)
        {
-         /* The alignment of sections between DATA_SEGMENT_ALIGN
-            and DATA_SEGMENT_RELRO_END can cause excessive padding to
-            be inserted at DATA_SEGMENT_RELRO_END.  Try to start a
-            bit lower so that the section alignments will fit in.  */
-         asection *sec;
-         unsigned int max_alignment_power = 0;
-
-         /* Find maximum alignment power of sections between
-            DATA_SEGMENT_ALIGN and DATA_SEGMENT_RELRO_END.  */
-         for (sec = link_info.output_bfd->sections; sec; sec = sec->next)
-           if (sec->vma >= expld.dataseg.base
-               && sec->vma < expld.dataseg.relro_end
-               && sec->alignment_power > max_alignment_power)
-             max_alignment_power = sec->alignment_power;
-
-         if (((bfd_vma) 1 << max_alignment_power) < expld.dataseg.pagesize)
-           {
-             /* Aligning the adjusted base guarantees the padding
-                between sections won't change.  This is better than
-                simply subtracting 1 << max_alignment_power which is
-                what we used to do here.  */
-             expld.dataseg.base &= ~((1 << max_alignment_power) - 1);
-             lang_reset_memory_regions ();
-             one_lang_size_sections_pass (relax, check_regions);
-           }
+         /* Assignments to dot, or to output section address in a
+            user script have increased padding over the original.
+            Revert.  */
+         expld.dataseg.base = initial_base;
+         lang_reset_memory_regions ();
+         one_lang_size_sections_pass (relax, check_regions);
        }
+
       link_info.relro_start = expld.dataseg.base;
       link_info.relro_end = expld.dataseg.relro_end;
     }
@@ -5903,7 +6007,7 @@ lang_common (void)
          for (power = 0; power <= 4; power++)
            bfd_link_hash_traverse (link_info.hash, lang_one_common, &power);
 
-         power = UINT_MAX;
+         power = (unsigned int) -1;
          bfd_link_hash_traverse (link_info.hash, lang_one_common, &power);
        }
     }
@@ -6066,10 +6170,18 @@ lang_set_flags (lang_memory_region_type *ptr, const char *flags, int invert)
   flagword *ptr_flags;
 
   ptr_flags = invert ? &ptr->not_flags : &ptr->flags;
+
   while (*flags)
     {
       switch (*flags)
        {
+         /* PR 17900: An exclamation mark in the attributes reverses
+            the sense of any of the attributes that follow.  */
+       case '!':
+         invert = ! invert;
+         ptr_flags = invert ? &ptr->not_flags : &ptr->flags;
+         break;
+
        case 'A': case 'a':
          *ptr_flags |= SEC_ALLOC;
          break;
@@ -6092,7 +6204,7 @@ lang_set_flags (lang_memory_region_type *ptr, const char *flags, int invert)
          break;
 
        default:
-         einfo (_("%P%F: invalid syntax in flags\n"));
+         einfo (_("%P%F: invalid character %c (%d) in flags\n"), * flags, * flags);
          break;
        }
       flags++;
@@ -6135,11 +6247,11 @@ ldlang_add_file (lang_input_statement_type *entry)
 
   /* The BFD linker needs to have a list of all input BFDs involved in
      a link.  */
-  ASSERT (entry->the_bfd->link_next == NULL);
+  ASSERT (entry->the_bfd->link.next == NULL);
   ASSERT (entry->the_bfd != link_info.output_bfd);
 
   *link_info.input_bfds_tail = entry->the_bfd;
-  link_info.input_bfds_tail = &entry->the_bfd->link_next;
+  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);
 
@@ -6236,7 +6348,6 @@ lang_final (void)
 
   new_stmt = new_stat (lang_output_statement, stat_ptr);
   new_stmt->name = output_filename;
-
 }
 
 /* Reset the current counters in the regions.  */
@@ -6566,7 +6677,7 @@ lang_process (void)
   open_input_bfds (statement_list.head, OPEN_BFD_NORMAL);
 
 #ifdef ENABLE_PLUGINS
-  if (plugin_active_plugins_p ())
+  if (link_info.lto_plugin_active)
     {
       lang_statement_list_type added;
       lang_statement_list_type files, inputfiles;
@@ -6585,7 +6696,6 @@ lang_process (void)
        einfo (_("%P%F: %s: plugin reported error after all symbols read\n"),
               plugin_error_plugin ());
       /* Open any newly added files, updating the file chains.  */
-      link_info.loading_lto_outputs = TRUE;
       open_input_bfds (*added.tail, OPEN_BFD_NORMAL);
       /* Restore the global list pointer now they have all been added.  */
       lang_list_remove_tail (stat_ptr, &added);
@@ -6626,8 +6736,26 @@ lang_process (void)
   link_info.gc_sym_list = &entry_symbol;
   if (entry_symbol.name == NULL)
     link_info.gc_sym_list = ldlang_undef_chain_list_head;
+  if (link_info.init_function != NULL)
+    {
+      struct bfd_sym_chain *sym
+       = (struct bfd_sym_chain *) stat_alloc (sizeof (*sym));
+      sym->next = link_info.gc_sym_list;
+      sym->name = link_info.init_function;
+      link_info.gc_sym_list = sym;
+    }
+  if (link_info.fini_function != NULL)
+    {
+      struct bfd_sym_chain *sym
+       = (struct bfd_sym_chain *) stat_alloc (sizeof (*sym));
+      sym->next = link_info.gc_sym_list;
+      sym->name = link_info.fini_function;
+      link_info.gc_sym_list = sym;
+    }
 
   ldemul_after_open ();
+  if (config.map_file != NULL)
+    lang_print_asneeded ();
 
   bfd_section_already_linked_table_free ();
 
@@ -6649,14 +6777,16 @@ lang_process (void)
   /* PR 13683: We must rerun the assignments prior to running garbage
      collection in order to make sure that all symbol aliases are resolved.  */
   lang_do_assignments (lang_mark_phase_enum);
-  expld.phase = lang_first_phase_enum;
 
-  /* Remove unreferenced sections if asked to.  */
-  lang_gc_sections ();
+  lang_do_memory_regions();
+  expld.phase = lang_first_phase_enum;
 
   /* Size up the common data.  */
   lang_common ();
 
+  /* Remove unreferenced sections if asked to.  */
+  lang_gc_sections ();
+
   /* Update wild statements.  */
   update_wild_statements (statement_list.head);
 
@@ -6724,6 +6854,9 @@ lang_process (void)
   if (command_line.check_section_addresses)
     lang_check_section_addresses ();
 
+  /* Check any required symbols are known.  */
+  ldlang_check_require_defined_symbols ();
+
   lang_end ();
 }
 
@@ -7912,6 +8045,37 @@ lang_do_version_exports_section (void)
                           lang_new_vers_node (greg, lreg), NULL);
 }
 
+/* Evaluate LENGTH and ORIGIN parts of MEMORY spec */
+
+static void
+lang_do_memory_regions (void)
+{
+  lang_memory_region_type *r = lang_memory_region_list;
+
+  for (; r != NULL; r = r->next)
+    {
+      if (r->origin_exp)
+      {
+        exp_fold_tree_no_dot (r->origin_exp);
+        if (expld.result.valid_p)
+          {
+            r->origin = expld.result.value;
+            r->current = r->origin;
+          }
+        else
+          einfo (_("%F%P: invalid origin for memory region %s\n"), r->name_list.name);
+      }
+      if (r->length_exp)
+      {
+        exp_fold_tree_no_dot (r->length_exp);
+        if (expld.result.valid_p)
+          r->length = expld.result.value;
+        else
+          einfo (_("%F%P: invalid length for memory region %s\n"), r->name_list.name);
+      }
+    }
+}
+
 void
 lang_add_unique (const char *name)
 {
@@ -8021,3 +8185,41 @@ lang_ld_feature (char *str)
       p = q;
     }
 }
+
+/* Pretty print memory amount.  */
+
+static void
+lang_print_memory_size (bfd_vma sz)
+{
+  if ((sz & 0x3fffffff) == 0)
+    printf ("%10" BFD_VMA_FMT "u GB", sz >> 30);
+  else if ((sz & 0xfffff) == 0)
+    printf ("%10" BFD_VMA_FMT "u MB", sz >> 20);
+  else if ((sz & 0x3ff) == 0)
+    printf ("%10" BFD_VMA_FMT "u KB", sz >> 10);
+  else
+    printf (" %10" BFD_VMA_FMT "u B", sz);
+}
+
+/* Implement --print-memory-usage: disply per region memory usage.  */
+
+void
+lang_print_memory_usage (void)
+{
+  lang_memory_region_type *r;
+
+  printf ("Memory region         Used Size  Region Size  %%age Used\n");
+  for (r = lang_memory_region_list; r->next != NULL; r = r->next)
+    {
+      bfd_vma used_length = r->current - r->origin;
+      double percent;
+
+      printf ("%16s: ",r->name_list.name);
+      lang_print_memory_size (used_length);
+      lang_print_memory_size ((bfd_vma) r->length);
+
+      percent = used_length * 100.0 / r->length;
+
+      printf ("    %6.2f%%\n", percent);
+    }
+}
This page took 0.089003 seconds and 4 git commands to generate.