From Craig Silverstein and Ian Lance Taylor: Process --script option.
authorIan Lance Taylor <iant@google.com>
Sat, 27 Oct 2007 00:29:34 +0000 (00:29 +0000)
committerIan Lance Taylor <iant@google.com>
Sat, 27 Oct 2007 00:29:34 +0000 (00:29 +0000)
gold/main.cc
gold/options.cc
gold/options.h
gold/parameters.cc
gold/parameters.h
gold/script.cc
gold/script.h

index eda586bc673c9c4d6c2d74375badc66810213f2b..a4dcc5a42a5302ff0dc23ad363edd13f7d1510f4 100644 (file)
@@ -54,6 +54,10 @@ main(int argc, char** argv)
 
   Errors errors(program_name);
 
+  // Initialize the global parameters, to let random code get to the
+  // errors object.
+  initialize_parameters(&errors);
+
   // Handle the command line options.
   Command_line command_line;
   command_line.process(argc - 1, argv + 1);
@@ -62,7 +66,8 @@ main(int argc, char** argv)
   if (command_line.options().print_stats())
     start_time = get_run_time();
 
-  initialize_parameters(&command_line.options(), &errors);
+  // Store some options in the globally accessible parameters.
+  set_parameters_from_options(&command_line.options());
 
   // The work queue.
   Workqueue workqueue(command_line.options());
index 9e5e270845a5182b6ef7418050e0ca31426df7a6..08cbf2ae9cc3d062065c3becfa5f0d3c7dbacd95 100644 (file)
@@ -69,7 +69,8 @@ struct options::One_option
   // be 0 if this function changes *argv.  ARG points to the location
   // in *ARGV where the option starts, which may be helpful for a
   // short option.
-  int (*special)(int argc, char** argv, char *arg, Command_line*);
+  int (*special)(int argc, char** argv, char *arg, bool long_option,
+                Command_line*);
 
   // If this is a position independent option which does not take an
   // argument, this is the member function to call to record it.
@@ -121,15 +122,32 @@ namespace
 // Handle the special -l option, which adds an input file.
 
 int
-library(int argc, char** argv, char* arg, gold::Command_line* cmdline)
+library(int argc, char** argv, char* arg, bool long_option,
+       gold::Command_line* cmdline)
 {
-  return cmdline->process_l_option(argc, argv, arg);
+  return cmdline->process_l_option(argc, argv, arg, long_option);
+}
+
+// Handle the special -T/--script option, which reads a linker script.
+
+int
+invoke_script(int argc, char** argv, char* arg, bool long_option,
+             gold::Command_line* cmdline)
+{
+  int ret;
+  const char* script_name = cmdline->get_special_argument("script", argc, argv,
+                                                         arg, long_option,
+                                                         &ret);
+  if (!read_commandline_script(script_name, cmdline))
+    gold::gold_error(_("%s: unable to parse script file %s\n"),
+                    gold::program_name, arg);
+  return ret;
 }
 
 // Handle the special --start-group option.
 
 int
-start_group(int, char**, char* arg, gold::Command_line* cmdline)
+start_group(int, char**, char* arg, bool, gold::Command_line* cmdline)
 {
   cmdline->start_group(arg);
   return 1;
@@ -138,7 +156,7 @@ start_group(int, char**, char* arg, gold::Command_line* cmdline)
 // Handle the special --end-group option.
 
 int
-end_group(int, char**, char* arg, gold::Command_line* cmdline)
+end_group(int, char**, char* arg, bool, gold::Command_line* cmdline)
 {
   cmdline->end_group(arg);
   return 1;
@@ -147,7 +165,7 @@ end_group(int, char**, char* arg, gold::Command_line* cmdline)
 // Report usage information for ld --help, and exit.
 
 int
-help(int, char**, char*, gold::Command_line*)
+help(int, char**, char*, bool, gold::Command_line*)
 {
   printf(_("Usage: %s [options] file...\nOptions:\n"), gold::program_name);
 
@@ -236,7 +254,7 @@ help(int, char**, char*, gold::Command_line*)
 // Report version information.
 
 int
-version(int, char**, char* opt, gold::Command_line*)
+version(int, char**, char* opt, bool, gold::Command_line*)
 {
   gold::print_version(opt[0] == 'v' && opt[1] == '\0');
   ::exit(0);
@@ -377,9 +395,9 @@ options::Command_line_options::options[] =
                NULL, TWO_DASHES, &General_options::set_stats),
   GENERAL_ARG('\0', "sysroot", N_("Set target system root directory"),
              N_("--sysroot DIR"), TWO_DASHES, &General_options::set_sysroot),
-  GENERAL_ARG('T', "script", N_("Read linker script"),
-              N_("-T FILE, --script FILE"), TWO_DASHES,
-              &General_options::set_script),
+  SPECIAL('T', "script", N_("Read linker script"),
+         N_("-T FILE, --script FILE"), TWO_DASHES,
+         &invoke_script),
   GENERAL_ARG('\0', "Ttext", N_("Set the address of the .text section"),
               N_("-Ttext ADDRESS"), ONE_DASH,
               &General_options::set_text_segment_address),
@@ -664,7 +682,12 @@ Command_line::process(int argc, char** argv)
              && strcmp(opt, options[j].long_option) == 0)
            {
              if (options[j].special)
-               i += options[j].special(argc - 1, argv + i, opt, this);
+               {
+                 // Restore the '=' we clobbered above.
+                 if (arg != NULL && skiparg == 0)
+                   arg[-1] = '=';
+                 i += options[j].special(argc - i, argv + i, opt, true, this);
+               }
              else
                {
                  if (!options[j].takes_argument())
@@ -709,7 +732,8 @@ Command_line::process(int argc, char** argv)
                    {
                      // Undo the argument skip done above.
                      --i;
-                     i += options[j].special(argc - i, argv + i, s, this);
+                     i += options[j].special(argc - i, argv + i, s, false,
+                                             this);
                      done = true;
                    }
                  else
@@ -759,6 +783,49 @@ Command_line::process(int argc, char** argv)
   this->normalize_options();
 }
 
+// Extract an option argument for a special option.  LONGNAME is the
+// long name of the option.  This sets *PRET to the return value for
+// the special function handler to skip to the next option.
+
+const char*
+Command_line::get_special_argument(const char* longname, int argc, char** argv,
+                                  const char* arg, bool long_option,
+                                  int *pret)
+{
+  if (long_option)
+    {
+      size_t longlen = strlen(longname);
+      gold_assert(strncmp(arg, longname, longlen) == 0);
+      arg += longlen;
+      if (*arg == '=')
+       {
+         *pret = 1;
+         return arg + 1;
+       }
+      else if (argc > 1)
+       {
+         gold_assert(*arg == '\0');
+         *pret = 2;
+         return argv[1];
+       }
+    }
+  else
+    {
+      if (arg[1] != '\0')
+       {
+         *pret = 1;
+         return arg + 1;
+       }
+      else if (argc > 1)
+       {
+         *pret = 2;
+         return argv[1];
+       }
+    }
+
+  this->usage(_("missing argument"), arg);
+}
+
 // Ensure options don't contradict each other and are otherwise kosher.
 
 void
@@ -814,25 +881,13 @@ Command_line::add_file(const char* name, bool is_lib)
 // Handle the -l option, which requires special treatment.
 
 int
-Command_line::process_l_option(int argc, char** argv, char* arg)
+Command_line::process_l_option(int argc, char** argv, char* arg,
+                              bool long_option)
 {
   int ret;
-  const char* libname;
-  if (arg[1] != '\0')
-    {
-      ret = 1;
-      libname = arg + 1;
-    }
-  else if (argc > 1)
-    {
-      ret = 2;
-      libname = argv[argc + 1];
-    }
-  else
-    this->usage(_("missing argument"), arg);
-
+  const char* libname = this->get_special_argument("library", argc, argv, arg,
+                                                  long_option, &ret);
   this->add_file(libname, true);
-
   return ret;
 }
 
index e3d5c266156f7ed1a94bcb63e998bdb58667b545..208c62a238ee8bd25d3e7c1865f035b3618ec11a 100644 (file)
 #include <string>
 #include <vector>
 
+#include "script.h"
+
 namespace gold
 {
 
 class Command_line;
 class Input_file_group;
+class Position_dependent_options;
 
 namespace options {
 
@@ -316,14 +319,6 @@ class General_options
   set_static()
   { this->is_static_ = true; }
 
-  void
-  set_script(const char* arg)
-  {
-    fprintf(stderr, _("%s: cannot parse %s: -T/--script not yet supported\n"),
-            program_name, arg);
-    ::exit(1);
-  }
-
   void
   set_stats()
   { this->print_stats_ = true; }
@@ -703,7 +698,7 @@ class Command_line
 
   // Handle a -l option.
   int
-  process_l_option(int, char**, char*);
+  process_l_option(int, char**, char*, bool);
 
   // Handle a --start-group option.
   void
@@ -713,11 +708,22 @@ class Command_line
   void
   end_group(const char* arg);
 
+  // Get an option argument--a helper function for special processing.
+  const char*
+  get_special_argument(const char* longname, int argc, char** argv,
+                      const char* arg, bool long_option,
+                      int *pret);
+
   // Get the general options.
   const General_options&
   options() const
   { return this->options_; }
 
+  // Get the position dependent options.
+  const Position_dependent_options&
+  position_dependent_options() const
+  { return this->position_options_; }
+
   // The number of input files.
   int
   number_of_input_files() const
index f8d6039fad8414b2724e4fc2b9d62a42e24416a6..52deac016caba48b634f830e4f87aaabc84d98c7 100644 (file)
@@ -30,14 +30,27 @@ namespace gold
 
 // Initialize the parameters from the options.
 
-Parameters::Parameters(const General_options* options, Errors* errors)
-  : errors_(errors), output_file_name_(options->output_file_name()),
-    sysroot_(options->sysroot()), symbolic_(options->symbolic()),
+Parameters::Parameters(Errors* errors)
+  : errors_(errors), output_file_name_(NULL),
+    output_file_type_(OUTPUT_INVALID), sysroot_(),
+    strip_(STRIP_INVALID), symbolic_(false),
+    optimization_level_(0), export_dynamic_(false),
     is_doing_static_link_valid_(false), doing_static_link_(false),
-    is_size_and_endian_valid_(false), size_(0), is_big_endian_(false),
-    optimization_level_(options->optimization_level()),
-    export_dynamic_(options->export_dynamic())
+    is_size_and_endian_valid_(false), size_(0), is_big_endian_(false)
 {
+}
+
+// Set fields from the command line options.
+
+void
+Parameters::set_from_options(const General_options* options)
+{
+  this->output_file_name_ = options->output_file_name();
+  this->sysroot_ = options->sysroot();
+  this->symbolic_ = options->symbolic();
+  this->optimization_level_ = options->optimization_level();
+  this->export_dynamic_ = options->export_dynamic();
+
   if (options->is_shared())
     this->output_file_type_ = OUTPUT_SHARED;
   else if (options->is_relocatable())
@@ -51,6 +64,8 @@ Parameters::Parameters(const General_options* options, Errors* errors)
     this->strip_ = STRIP_DEBUG;
   else
     this->strip_ = STRIP_NONE;
+
+  this->options_valid_ = true;
 }
 
 // Set whether we are doing a static link.
@@ -91,9 +106,17 @@ const Parameters* parameters;
 // Initialize the global variable.
 
 void
-initialize_parameters(const General_options* options, Errors* errors)
+initialize_parameters(Errors* errors)
+{
+  parameters = static_parameters = new Parameters(errors);
+}
+
+// Set values from the options.
+
+void
+set_parameters_from_options(const General_options* options)
 {
-  parameters = static_parameters = new Parameters(options, errors);
+  static_parameters->set_from_options(options);
 }
 
 // Set whether we are doing a static link.
index 132aadab0781561a564d7a91fac7decfe2be57a4..79545ac0ea94570f10bd6c3a11ff3e5c661480e3 100644 (file)
@@ -40,7 +40,7 @@ class Errors;
 class Parameters
 {
  public:
-  Parameters(const General_options*, Errors*);
+  Parameters(Errors*);
 
   // Return the error object.
   Errors*
@@ -50,22 +50,34 @@ class Parameters
   // Return the output file name.
   const char*
   output_file_name() const
-  { return this->output_file_name_; }
+  {
+    gold_assert(this->options_valid_);
+    return this->output_file_name_;
+  }
 
   // Whether we are generating a regular executable.
   bool
   output_is_executable() const
-  { return this->output_file_type_ == OUTPUT_EXECUTABLE; }
+  {
+    gold_assert(this->output_file_type_ != OUTPUT_INVALID);
+    return this->output_file_type_ == OUTPUT_EXECUTABLE;
+  }
 
   // Whether we are generating a shared library.
   bool
   output_is_shared() const
-  { return this->output_file_type_ == OUTPUT_SHARED; }
+  {
+    gold_assert(this->output_file_type_ != OUTPUT_INVALID);
+    return this->output_file_type_ == OUTPUT_SHARED;
+  }
 
   // Whether we are generating an object file.
   bool
   output_is_object() const
-  { return this->output_file_type_ == OUTPUT_OBJECT; }
+  {
+    gold_assert(this->output_file_type_ != OUTPUT_INVALID);
+    return this->output_file_type_ == OUTPUT_OBJECT;
+  }
 
   // Whether we are generating position-independent output.
   // This is the case when generating either a shared library
@@ -79,23 +91,51 @@ class Parameters
   // one.
   const std::string&
   sysroot() const
-  { return this->sysroot_; }
+  {
+    gold_assert(this->options_valid_);
+    return this->sysroot_;
+  }
 
   // Whether to strip all symbols.
   bool
   strip_all() const
-  { return this->strip_ == STRIP_ALL; }
+  {
+    gold_assert(this->strip_ != STRIP_INVALID);
+    return this->strip_ == STRIP_ALL;
+  }
 
   // Whether to strip debugging information.
   bool
   strip_debug() const
-  { return this->strip_ == STRIP_ALL || this->strip_ == STRIP_DEBUG; }
+  {
+    gold_assert(this->strip_ != STRIP_INVALID);
+    return this->strip_ == STRIP_ALL || this->strip_ == STRIP_DEBUG;
+  }
 
   // Whether we are doing a symbolic link, in which all defined
   // symbols are bound locally.
   bool
   symbolic() const
-  { return this->symbolic_; }
+  {
+    gold_assert(this->options_valid_);
+    return this->symbolic_;
+  }
+
+  // The general linker optimization level.
+  int
+  optimization_level() const
+  {
+    gold_assert(this->options_valid_);
+    return this->optimization_level_;
+  }
+
+  // Whether the -E/--export-dynamic flag is set.
+  bool
+  export_dynamic() const
+  {
+    gold_assert(this->options_valid_);
+    return this->export_dynamic_;
+  }
 
   // Whether we are doing a static link--a link in which none of the
   // input files are shared libraries.  This is only known after we
@@ -124,15 +164,9 @@ class Parameters
     return this->is_big_endian_;
   }
 
-  // The general linker optimization level.
-  int
-  optimization_level() const
-  { return this->optimization_level_; }
-
-  // Whether the -E/--export-dynamic flag is set.
-  bool
-  export_dynamic() const
-  { return this->export_dynamic_; }
+  // Set values recorded from options.
+  void
+  set_from_options(const General_options*);
 
   // Set whether we are doing a static link.
   void
@@ -146,6 +180,8 @@ class Parameters
   // The types of output files.
   enum Output_file_type
     {
+      // Uninitialized.
+      OUTPUT_INVALID,
       // Generating executable.
       OUTPUT_EXECUTABLE,
       // Generating shared library.
@@ -157,6 +193,8 @@ class Parameters
   // Which symbols to strip.
   enum Strip
   {
+    // Uninitialize.
+    STRIP_INVALID,
     // Don't strip any symbols.
     STRIP_NONE,
     // Strip all symbols.
@@ -168,6 +206,8 @@ class Parameters
   // A pointer to the error handling object.
   Errors* errors_;
 
+  // Whether the fields set from the options are valid.
+  bool options_valid_;
   // The output file name.
   const char* output_file_name_;
   // The type of the output file.
@@ -178,6 +218,10 @@ class Parameters
   Strip strip_;
   // Whether we are doing a symbolic link.
   bool symbolic_;
+  // The optimization level.
+  int optimization_level_;
+  // Whether the -E/--export-dynamic flag is set.
+  bool export_dynamic_;
 
   // Whether the doing_static_link_ field is valid.
   bool is_doing_static_link_valid_;
@@ -189,17 +233,16 @@ class Parameters
   int size_;
   // Whether the output file is big endian.
   bool is_big_endian_;
-  // The optimization level.
-  int optimization_level_;
-  // Whether the -E/--export-dynamic flag is set.
-  bool export_dynamic_;
 };
 
 // This is a global variable.
 extern const Parameters* parameters;
 
 // Initialize the global variable.
-extern void initialize_parameters(const General_options*, Errors*);
+extern void initialize_parameters(Errors*);
+
+// Set the options.
+extern void set_parameters_from_options(const General_options*);
 
 // Set the size and endianness of the global parameters variable.
 extern void set_parameters_size_and_endianness(int size, bool is_big_endian);
index 08be65f0b98d3e0909b031d66e4756f160fa6549..7122ea43cee10a387f6e07ff78d35df45649e8d0 100644 (file)
@@ -28,6 +28,7 @@
 #include <cstdlib>
 #include "filenames.h"
 
+#include "dirsearch.h"
 #include "options.h"
 #include "fileread.h"
 #include "workqueue.h"
@@ -931,6 +932,10 @@ read_input_script(Workqueue* workqueue, const General_options& options,
   if (yyparse(&closure) != 0)
     return false;
 
+  // If this routine was called from the main thread rather than a
+  // work queue -- as it is for the --script option -- then our
+  // work here is done.
+
   // THIS_BLOCKER must be clear before we may add anything to the
   // symbol table.  We are responsible for unblocking NEXT_BLOCKER
   // when we are done.  We are responsible for deleting THIS_BLOCKER
@@ -966,6 +971,46 @@ read_input_script(Workqueue* workqueue, const General_options& options,
   return true;
 }
 
+// FILENAME was found as an argument to --script (-T).
+// Read it as a script, and execute its contents immediately.
+
+bool
+read_commandline_script(const char* filename, Command_line* cmdline)
+{
+  // We don't need to use the real directory search path here:
+  // FILENAME was specified on the command line, and we don't want to
+  // search for it.
+  Dirsearch dirsearch;
+
+  Input_file_argument input_argument(filename, false, "",
+                                    cmdline->position_dependent_options());
+  Input_file input_file(&input_argument);
+  if (!input_file.open(cmdline->options(), dirsearch))
+    return false;
+
+  Lex lex(&input_file);
+  if (lex.tokenize().is_invalid())
+    {
+      // Opening the file locked it, so now we need to unlock it.
+      input_file.file().unlock();
+      return false;
+    }
+
+  Parser_closure closure(filename,
+                        cmdline->position_dependent_options(),
+                        false,
+                        input_file.is_in_sysroot(),
+                        &lex.tokens());
+  if (yyparse(&closure) != 0)
+    {
+      input_file.file().unlock();
+      return false;
+    }
+
+  input_file.file().unlock();
+  return true;
+}
+
 // Manage mapping from keywords to the codes expected by the bison
 // parser.
 
index 8198c970e2899d5cbd0bf99f69b09be34929caea..16483a03c9df4798268a1cdd669377a9c00f4f19 100644 (file)
@@ -34,12 +34,15 @@ namespace gold
 {
 
 class General_options;
+class Command_line;
 class Symbol_table;
 class Layout;
+class Input_argument;
 class Input_objects;
 class Input_group;
 class Input_file;
 class Task_token;
+class Workqueue;
 
 // FILE was found as an argument on the command line, but was not
 // recognized as an ELF file.  Try to read it as a script.  We've
@@ -54,6 +57,12 @@ read_input_script(Workqueue*, const General_options&, Symbol_table*, Layout*,
                  off_t bytes, Task_token* this_blocker,
                  Task_token* next_blocker);
 
+// FILE was found as an argument to --script (-T).
+// Read it as a script, and execute its contents immediately.
+
+bool
+read_commandline_script(const char* filename, Command_line*);
+
 } // End namespace gold.
 
 #endif // !defined(GOLD_SCRIPT_H)