* gold.cc (gold_exit): Call plugin cleanup handlers on exit.
[binutils-gdb.git] / gold / script.cc
index eef034ecd8e2853c43ffad761e376a03f892f2f6..9deb72685438ba84c3a1759e030ee16b74aa4ab2 100644 (file)
 
 #include "gold.h"
 
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
 #include <fnmatch.h>
 #include <string>
 #include <vector>
-#include <cstdio>
-#include <cstdlib>
 #include "filenames.h"
 
 #include "elfcpp.h"
@@ -183,7 +184,9 @@ class Lex
     // Reading an expression in a linker script.
     EXPRESSION,
     // Reading a version script.
-    VERSION_SCRIPT
+    VERSION_SCRIPT,
+    // Reading a --dynamic-list file.
+    DYNAMIC_LIST
   };
 
   Lex(const char* input_string, size_t input_length, int parsing_token)
@@ -392,8 +395,9 @@ Lex::can_start_name(char c, char c2)
     case '~':
       return this->mode_ == LINKER_SCRIPT && can_continue_name(&c2);
 
-    case '*': case '[': 
+    case '*': case '[':
       return (this->mode_ == VERSION_SCRIPT
+              || this->mode_ == DYNAMIC_LIST
              || (this->mode_ == LINKER_SCRIPT
                  && can_continue_name(&c2)));
 
@@ -428,27 +432,31 @@ Lex::can_continue_name(const char* c)
     case '5': case '6': case '7': case '8': case '9':
       return c + 1;
 
+    // TODO(csilvers): why not allow ~ in names for version-scripts?
     case '/': case '\\': case '~':
     case '=': case '+':
-    case ',': case '?': 
+    case ',':
       if (this->mode_ == LINKER_SCRIPT)
         return c + 1;
       return NULL;
 
-    case '[': case ']': case '*': case '-':
-      if (this->mode_ == LINKER_SCRIPT || this->mode_ == VERSION_SCRIPT)
+    case '[': case ']': case '*': case '?': case '-':
+      if (this->mode_ == LINKER_SCRIPT || this->mode_ == VERSION_SCRIPT
+          || this->mode_ == DYNAMIC_LIST)
         return c + 1;
       return NULL;
 
+    // TODO(csilvers): why allow this?  ^ is meaningless in version scripts.
     case '^':
-      if (this->mode_ == VERSION_SCRIPT)
+      if (this->mode_ == VERSION_SCRIPT || this->mode_ == DYNAMIC_LIST)
         return c + 1;
       return NULL;
 
     case ':':
       if (this->mode_ == LINKER_SCRIPT)
         return c + 1;
-      else if (this->mode_ == VERSION_SCRIPT && (c[1] == ':'))
+      else if ((this->mode_ == VERSION_SCRIPT || this->mode_ == DYNAMIC_LIST)
+               && (c[1] == ':'))
         {
           // A name can have '::' in it, as that's a c++ namespace
           // separator. But a single colon is not part of a name.
@@ -1108,6 +1116,12 @@ Script_options::add_symbols_to_table(Symbol_table* symtab)
 void
 Script_options::finalize_symbols(Symbol_table* symtab, const Layout* layout)
 {
+  // We finalize the symbols defined in SECTIONS first, because they
+  // are the ones which may have changed.  This way if symbol outside
+  // SECTIONS are defined in terms of symbols inside SECTIONS, they
+  // will get the right value.
+  this->script_sections_.finalize_symbols(symtab, layout);
+
   for (Symbol_assignments::iterator p = this->symbol_assignments_.begin();
        p != this->symbol_assignments_.end();
        ++p)
@@ -1117,8 +1131,6 @@ Script_options::finalize_symbols(Symbol_table* symtab, const Layout* layout)
        p != this->assertions_.end();
        ++p)
     (*p)->check(symtab, layout);
-
-  this->script_sections_.finalize_symbols(symtab, layout);
 }
 
 // Set section addresses.  We set all the symbols which have absolute
@@ -1156,7 +1168,7 @@ class Parser_closure
       command_line_(command_line), script_options_(script_options),
       version_script_info_(script_options->version_script_info()),
       lex_(lex), lineno_(0), charpos_(0), lex_mode_stack_(), inputs_(NULL)
-  { 
+  {
     // We start out processing C symbols in the default lex mode.
     language_stack_.push_back("");
     lex_mode_stack_.push_back(lex->mode());
@@ -1312,7 +1324,7 @@ bool
 read_input_script(Workqueue* workqueue, const General_options& options,
                  Symbol_table* symtab, Layout* layout,
                  Dirsearch* dirsearch, Input_objects* input_objects,
-                 Input_group* input_group,
+                 Mapfile* mapfile, Input_group* input_group,
                  const Input_argument* input_argument,
                  Input_file* input_file, Task_token* next_blocker,
                  bool* used_next_blocker)
@@ -1352,7 +1364,7 @@ read_input_script(Workqueue* workqueue, const General_options& options,
          nb->add_blocker();
        }
       workqueue->queue_soon(new Read_symbols(options, input_objects, symtab,
-                                            layout, dirsearch, &*p,
+                                            layout, dirsearch, mapfile, &*p,
                                             input_group, this_blocker, nb));
       this_blocker = nb;
     }
@@ -1368,6 +1380,7 @@ read_input_script(Workqueue* workqueue, const General_options& options,
 
 static bool
 read_script_file(const char* filename, Command_line* cmdline,
+                 Script_options* script_options,
                  int first_token, Lex::Mode lex_mode)
 {
   // TODO: if filename is a relative filename, search for it manually
@@ -1381,8 +1394,8 @@ read_script_file(const char* filename, Command_line* cmdline,
 
   // We don't want this file to be opened in binary mode.
   Position_dependent_options posdep = cmdline->position_dependent_options();
-  if (posdep.format() == General_options::OBJECT_FORMAT_BINARY)
-    posdep.set_format("elf");
+  if (posdep.format_enum() == General_options::OBJECT_FORMAT_BINARY)
+    posdep.set_format_enum(General_options::OBJECT_FORMAT_ELF);
   Input_file_argument input_argument(filename, false, "", false, posdep);
   Input_file input_file(&input_argument);
   if (!input_file.open(cmdline->options(), dirsearch, task))
@@ -1399,7 +1412,7 @@ read_script_file(const char* filename, Command_line* cmdline,
                         false,
                         input_file.is_in_sysroot(),
                          cmdline,
-                        &cmdline->script_options(),
+                        script_options,
                         &lex);
   if (yyparse(&closure) != 0)
     {
@@ -1420,21 +1433,32 @@ read_script_file(const char* filename, Command_line* cmdline,
 bool
 read_commandline_script(const char* filename, Command_line* cmdline)
 {
-  return read_script_file(filename, cmdline,
+  return read_script_file(filename, cmdline, &cmdline->script_options(),
                           PARSING_LINKER_SCRIPT, Lex::LINKER_SCRIPT);
 }
 
-// FILE was found as an argument to --version-script.  Read it as a
-// version script, and store its contents in
+// FILENAME was found as an argument to --version-script.  Read it as
+// version script, and store its contents in
 // cmdline->script_options()->version_script_info().
 
 bool
 read_version_script(const char* filename, Command_line* cmdline)
 {
-  return read_script_file(filename, cmdline,
+  return read_script_file(filename, cmdline, &cmdline->script_options(),
                           PARSING_VERSION_SCRIPT, Lex::VERSION_SCRIPT);
 }
 
+// FILENAME was found as an argument to --dynamic-list.  Read it as a
+// list of symbols, and store its contents in DYNAMIC_LIST.
+
+bool
+read_dynamic_list(const char* filename, Command_line* cmdline,
+                  Script_options* dynamic_list)
+{
+  return read_script_file(filename, cmdline, dynamic_list,
+                          PARSING_DYNAMIC_LIST, Lex::DYNAMIC_LIST);
+}
+
 // Implement the --defsym option on the command line.  Return true if
 // all is well.
 
@@ -1617,6 +1641,19 @@ version_script_keywords(&version_script_keyword_parsecodes[0],
                         (sizeof(version_script_keyword_parsecodes)
                          / sizeof(version_script_keyword_parsecodes[0])));
 
+static const Keyword_to_parsecode::Keyword_parsecode
+dynamic_list_keyword_parsecodes[] =
+{
+  { "extern", EXTERN },
+};
+
+static const Keyword_to_parsecode
+dynamic_list_keywords(&dynamic_list_keyword_parsecodes[0],
+                      (sizeof(dynamic_list_keyword_parsecodes)
+                       / sizeof(dynamic_list_keyword_parsecodes[0])));
+
+
+
 // Comparison function passed to bsearch.
 
 extern "C"
@@ -1731,7 +1768,8 @@ Version_script_info::get_versions() const
 {
   std::vector<std::string> ret;
   for (size_t j = 0; j < version_trees_.size(); ++j)
-    ret.push_back(version_trees_[j]->tag);
+    if (!this->version_trees_[j]->tag.empty())
+      ret.push_back(this->version_trees_[j]->tag);
   return ret;
 }
 
@@ -1752,9 +1790,16 @@ Version_script_info::get_dependencies(const char* version) const
   return ret;
 }
 
-const std::string&
+// Look up SYMBOL_NAME in the list of versions.  If CHECK_GLOBAL is
+// true look at the globally visible symbols, otherwise look at the
+// symbols listed as "local:".  Return true if the symbol is found,
+// false otherwise.  If the symbol is found, then if PVERSION is not
+// NULL, set *PVERSION to the version.
+
+bool
 Version_script_info::get_symbol_version_helper(const char* symbol_name,
-                                               bool check_global) const
+                                               bool check_global,
+                                              std::string* pversion) const
 {
   for (size_t j = 0; j < version_trees_.size(); ++j)
     {
@@ -1795,11 +1840,14 @@ Version_script_info::get_symbol_version_helper(const char* symbol_name,
             if (demangled_name != NULL)
               free(demangled_name);
             if (matched)
-              return version_trees_[j]->tag;
+             {
+               if (pversion != NULL)
+                 *pversion = this->version_trees_[j]->tag;
+               return true;
+             }
           }
     }
-  static const std::string empty = "";
-  return empty;
+  return false;
 }
 
 struct Version_dependency_list*
@@ -1947,6 +1995,9 @@ yylex(YYSTYPE* lvalp, void* closurev)
           case Lex::VERSION_SCRIPT:
             parsecode = version_script_keywords.keyword_to_parsecode(str, len);
             break;
+          case Lex::DYNAMIC_LIST:
+            parsecode = dynamic_list_keywords.keyword_to_parsecode(str, len);
+            break;
           default:
             break;
           }
@@ -2131,7 +2182,7 @@ script_parse_option(void* closurev, const char* option, size_t length)
   else
     {
       bool past_a_double_dash_option = false;
-      char* mutable_option = strndup(option, length);
+      const char* mutable_option = strndup(option, length);
       gold_assert(mutable_option != NULL);
       closure->command_line()->process_one_option(1, &mutable_option, 0,
                                                   &past_a_double_dash_option);
@@ -2206,9 +2257,9 @@ script_register_vers_node(void*,
                          struct Version_dependency_list *deps)
 {
   gold_assert(tree != NULL);
-  gold_assert(tag != NULL);
   tree->dependencies = deps;
-  tree->tag = std::string(tag, taglen);
+  if (tag != NULL)
+    tree->tag = std::string(tag, taglen);
 }
 
 // Add a dependencies to the list of existing dependencies, if any,
@@ -2323,7 +2374,7 @@ script_start_output_section(void* closurev, const char* name, size_t namelen,
 // Finish processing entries for an output section.
 
 extern "C" void
-script_finish_output_section(void* closurev, 
+script_finish_output_section(void* closurev,
                             const struct Parser_output_section_trailer* trail)
 {
   Parser_closure* closure = static_cast<Parser_closure*>(closurev);
@@ -2384,6 +2435,34 @@ script_add_input_section(void* closurev,
   closure->script_options()->script_sections()->add_input_section(spec, keep);
 }
 
+// When we see DATA_SEGMENT_ALIGN we record that following output
+// sections may be relro.
+
+extern "C" void
+script_data_segment_align(void* closurev)
+{
+  Parser_closure* closure = static_cast<Parser_closure*>(closurev);
+  if (!closure->script_options()->saw_sections_clause())
+    gold_error(_("%s:%d:%d: DATA_SEGMENT_ALIGN not in SECTIONS clause"),
+              closure->filename(), closure->lineno(), closure->charpos());
+  else
+    closure->script_options()->script_sections()->data_segment_align();
+}
+
+// When we see DATA_SEGMENT_RELRO_END we know that all output sections
+// since DATA_SEGMENT_ALIGN should be relro.
+
+extern "C" void
+script_data_segment_relro_end(void* closurev)
+{
+  Parser_closure* closure = static_cast<Parser_closure*>(closurev);
+  if (!closure->script_options()->saw_sections_clause())
+    gold_error(_("%s:%d:%d: DATA_SEGMENT_ALIGN not in SECTIONS clause"),
+              closure->filename(), closure->lineno(), closure->charpos());
+  else
+    closure->script_options()->script_sections()->data_segment_relro_end();
+}
+
 // Create a new list of string/sort pairs.
 
 extern "C" String_sort_list_ptr