mirror of
https://sourceware.org/git/binutils-gdb.git
synced 2024-11-27 03:54:41 +08:00
From Craig Silverstein and Ian Lance Taylor: Process --script option.
This commit is contained in:
parent
4af13c269b
commit
3c2fafa531
@ -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());
|
||||
|
111
gold/options.cc
111
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;
|
||||
}
|
||||
|
||||
|
@ -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 {
|
||||
|
||||
@ -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
|
||||
|
@ -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(options, errors);
|
||||
parameters = static_parameters = new Parameters(errors);
|
||||
}
|
||||
|
||||
// Set values from the options.
|
||||
|
||||
void
|
||||
set_parameters_from_options(const General_options* options)
|
||||
{
|
||||
static_parameters->set_from_options(options);
|
||||
}
|
||||
|
||||
// Set whether we are doing a static link.
|
||||
|
@ -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);
|
||||
|
@ -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.
|
||||
|
||||
|
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user