aboutsummaryrefslogtreecommitdiff
path: root/gold
diff options
context:
space:
mode:
authorIan Lance Taylor <iant@google.com>2007-10-27 00:29:34 +0000
committerIan Lance Taylor <iant@google.com>2007-10-27 00:29:34 +0000
commit3c2fafa5311f159f222047699968e091a8f260d6 (patch)
tree48a53667ae73288fab5264e1decc5ab27160d445 /gold
parent4af13c269b9cd216b8593a2afbcabde5746c720f (diff)
downloadbinutils-3c2fafa5311f159f222047699968e091a8f260d6.zip
binutils-3c2fafa5311f159f222047699968e091a8f260d6.tar.gz
binutils-3c2fafa5311f159f222047699968e091a8f260d6.tar.bz2
From Craig Silverstein and Ian Lance Taylor: Process --script option.
Diffstat (limited to 'gold')
-rw-r--r--gold/main.cc7
-rw-r--r--gold/options.cc111
-rw-r--r--gold/options.h24
-rw-r--r--gold/parameters.cc39
-rw-r--r--gold/parameters.h89
-rw-r--r--gold/script.cc45
-rw-r--r--gold/script.h9
7 files changed, 255 insertions, 69 deletions
diff --git a/gold/main.cc b/gold/main.cc
index eda586b..a4dcc5a 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 9e5e270..08cbf2a 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 e3d5c26..208c62a 100644
--- a/gold/options.h
+++ b/gold/options.h
@@ -37,11 +37,14 @@
#include <string>
#include <vector>
+#include "script.h"
+
namespace gold
{
class Command_line;
class Input_file_group;
+class Position_dependent_options;
namespace options {
@@ -317,14 +320,6 @@ class General_options
{ 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 f8d6039..52deac0 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 132aada..79545ac 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 08be65f..7122ea4 100644
--- a/gold/script.cc
+++ b/gold/script.cc
@@ -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.
diff --git a/gold/script.h b/gold/script.h
index 8198c97..16483a0 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)