From 3c2fafa5311f159f222047699968e091a8f260d6 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Sat, 27 Oct 2007 00:29:34 +0000 Subject: [PATCH] From Craig Silverstein and Ian Lance Taylor: Process --script option. --- gold/main.cc | 7 ++- gold/options.cc | 111 +++++++++++++++++++++++++++++++++------------ gold/options.h | 24 ++++++---- gold/parameters.cc | 39 ++++++++++++---- gold/parameters.h | 89 ++++++++++++++++++++++++++---------- gold/script.cc | 45 ++++++++++++++++++ gold/script.h | 9 ++++ 7 files changed, 255 insertions(+), 69 deletions(-) diff --git a/gold/main.cc b/gold/main.cc index eda586bc673..a4dcc5a42a5 100644 --- a/gold/main.cc +++ b/gold/main.cc @@ -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()); diff --git a/gold/options.cc b/gold/options.cc index 9e5e270845a..08cbf2ae9cc 100644 --- a/gold/options.cc +++ b/gold/options.cc @@ -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; } diff --git a/gold/options.h b/gold/options.h index e3d5c266156..208c62a238e 100644 --- a/gold/options.h +++ b/gold/options.h @@ -37,11 +37,14 @@ #include #include +#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 diff --git a/gold/parameters.cc b/gold/parameters.cc index f8d6039fad8..52deac016ca 100644 --- a/gold/parameters.cc +++ b/gold/parameters.cc @@ -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. diff --git a/gold/parameters.h b/gold/parameters.h index 132aadab078..79545ac0ea9 100644 --- a/gold/parameters.h +++ b/gold/parameters.h @@ -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); diff --git a/gold/script.cc b/gold/script.cc index 08be65f0b98..7122ea43cee 100644 --- a/gold/script.cc +++ b/gold/script.cc @@ -28,6 +28,7 @@ #include #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. diff --git a/gold/script.h b/gold/script.h index 8198c970e28..16483a03c9d 100644 --- a/gold/script.h +++ b/gold/script.h @@ -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) -- 2.30.2