Support assignments and expressions in linker scripts.

This commit is contained in:
Ian Lance Taylor 2008-01-09 19:57:45 +00:00
parent cda30489fc
commit e5756efb6d
21 changed files with 1876 additions and 444 deletions

View File

@ -37,6 +37,7 @@ CCFILES = \
dwarf_reader.cc \
ehframe.cc \
errors.cc \
expression.cc \
fileread.cc \
gold.cc \
gold-threads.cc \

View File

@ -73,13 +73,13 @@ libgold_a_LIBADD =
am__objects_1 = archive.$(OBJEXT) common.$(OBJEXT) \
compressed_output.$(OBJEXT) defstd.$(OBJEXT) \
dirsearch.$(OBJEXT) dynobj.$(OBJEXT) dwarf_reader.$(OBJEXT) \
ehframe.$(OBJEXT) errors.$(OBJEXT) fileread.$(OBJEXT) \
gold.$(OBJEXT) gold-threads.$(OBJEXT) layout.$(OBJEXT) \
merge.$(OBJEXT) object.$(OBJEXT) options.$(OBJEXT) \
output.$(OBJEXT) parameters.$(OBJEXT) readsyms.$(OBJEXT) \
reloc.$(OBJEXT) resolve.$(OBJEXT) script.$(OBJEXT) \
stringpool.$(OBJEXT) symtab.$(OBJEXT) target-select.$(OBJEXT) \
version.$(OBJEXT) workqueue.$(OBJEXT) \
ehframe.$(OBJEXT) errors.$(OBJEXT) expression.$(OBJEXT) \
fileread.$(OBJEXT) gold.$(OBJEXT) gold-threads.$(OBJEXT) \
layout.$(OBJEXT) merge.$(OBJEXT) object.$(OBJEXT) \
options.$(OBJEXT) output.$(OBJEXT) parameters.$(OBJEXT) \
readsyms.$(OBJEXT) reloc.$(OBJEXT) resolve.$(OBJEXT) \
script.$(OBJEXT) stringpool.$(OBJEXT) symtab.$(OBJEXT) \
target-select.$(OBJEXT) version.$(OBJEXT) workqueue.$(OBJEXT) \
workqueue-threads.$(OBJEXT)
am__objects_2 =
am__objects_3 = yyscript.$(OBJEXT)
@ -294,6 +294,7 @@ CCFILES = \
dwarf_reader.cc \
ehframe.cc \
errors.cc \
expression.cc \
fileread.cc \
gold.cc \
gold-threads.cc \
@ -477,6 +478,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dynobj.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ehframe.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/errors.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/expression.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fileread.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gold-threads.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gold.Po@am__quote@

508
gold/expression.cc Normal file
View File

@ -0,0 +1,508 @@
// expression.cc -- expressions in linker scripts for gold
// Copyright 2006, 2007, 2008 Free Software Foundation, Inc.
// Written by Ian Lance Taylor <iant@google.com>.
// This file is part of gold.
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
// MA 02110-1301, USA.
#include "gold.h"
#include <string>
#include "parameters.h"
#include "symtab.h"
#include "layout.h"
#include "script.h"
#include "script-c.h"
namespace gold
{
// This file holds the code which handles linker expressions.
// When evaluating the value of an expression, we pass in a pointer to
// this struct, so that the expression evaluation can find the
// information it needs.
struct Expression::Expression_eval_info
{
const Symbol_table* symtab;
const Layout* layout;
};
// Evaluate an expression.
uint64_t
Expression::eval(const Symbol_table* symtab, const Layout* layout)
{
Expression_eval_info eei;
eei.symtab = symtab;
eei.layout = layout;
return this->value(&eei);
}
// A number.
class Integer_expression : public Expression
{
public:
Integer_expression(uint64_t val)
: val_(val)
{ }
uint64_t
value(const Expression_eval_info*)
{ return this->val_; }
private:
uint64_t val_;
};
extern "C" Expression*
script_exp_integer(uint64_t val)
{
return new Integer_expression(val);
}
// An expression whose value is the value of a symbol.
class Symbol_expression : public Expression
{
public:
Symbol_expression(const char* name, size_t length)
: name_(name, length)
{ }
uint64_t
value(const Expression_eval_info*);
private:
std::string name_;
};
uint64_t
Symbol_expression::value(const Expression_eval_info* eei)
{
Symbol* sym = eei->symtab->lookup(this->name_.c_str());
if (sym == NULL || !sym->is_defined())
{
gold_error(_("undefined symbol '%s' referenced in expression"),
this->name_.c_str());
return 0;
}
if (parameters->get_size() == 32)
return eei->symtab->get_sized_symbol<32>(sym)->value();
else if (parameters->get_size() == 64)
return eei->symtab->get_sized_symbol<64>(sym)->value();
else
gold_unreachable();
}
// An expression whose value is the value of the special symbol ".".
// This is only valid within a SECTIONS clause.
class Dot_expression : public Expression
{
public:
Dot_expression()
{ }
uint64_t
value(const Expression_eval_info*);
};
uint64_t
Dot_expression::value(const Expression_eval_info*)
{
gold_error("dot symbol unimplemented");
return 0;
}
// A string. This is either the name of a symbol, or ".".
extern "C" Expression*
script_exp_string(const char* name, size_t length)
{
if (length == 1 && name[0] == '.')
return new Dot_expression();
else
return new Symbol_expression(name, length);
}
// A unary expression.
class Unary_expression : public Expression
{
public:
Unary_expression(Expression* arg)
: arg_(arg)
{ }
~Unary_expression()
{ delete this->arg_; }
protected:
uint64_t
arg_value(const Expression_eval_info* eei) const
{ return this->arg_->value(eei); }
private:
Expression* arg_;
};
// Handle unary operators. We use a preprocessor macro as a hack to
// capture the C operator.
#define UNARY_EXPRESSION(NAME, OPERATOR) \
class Unary_ ## NAME : public Unary_expression \
{ \
public: \
Unary_ ## NAME(Expression* arg) \
: Unary_expression(arg) \
{ } \
\
uint64_t \
value(const Expression_eval_info* eei) \
{ return OPERATOR this->arg_value(eei); } \
}; \
\
extern "C" Expression* \
script_exp_unary_ ## NAME(Expression* arg) \
{ \
return new Unary_ ## NAME(arg); \
}
UNARY_EXPRESSION(minus, -)
UNARY_EXPRESSION(logical_not, !)
UNARY_EXPRESSION(bitwise_not, ~)
// A binary expression.
class Binary_expression : public Expression
{
public:
Binary_expression(Expression* left, Expression* right)
: left_(left), right_(right)
{ }
~Binary_expression()
{
delete this->left_;
delete this->right_;
}
protected:
uint64_t
left_value(const Expression_eval_info* eei) const
{ return this->left_->value(eei); }
uint64_t
right_value(const Expression_eval_info* eei) const
{ return this->right_->value(eei); }
private:
Expression* left_;
Expression* right_;
};
// Handle binary operators. We use a preprocessor macro as a hack to
// capture the C operator.
#define BINARY_EXPRESSION(NAME, OPERATOR) \
class Binary_ ## NAME : public Binary_expression \
{ \
public: \
Binary_ ## NAME(Expression* left, Expression* right) \
: Binary_expression(left, right) \
{ } \
\
uint64_t \
value(const Expression_eval_info* eei) \
{ \
return (this->left_value(eei) \
OPERATOR this->right_value(eei)); \
} \
}; \
\
extern "C" Expression* \
script_exp_binary_ ## NAME(Expression* left, Expression* right) \
{ \
return new Binary_ ## NAME(left, right); \
}
BINARY_EXPRESSION(mult, *)
BINARY_EXPRESSION(div, /)
BINARY_EXPRESSION(mod, %)
BINARY_EXPRESSION(add, +)
BINARY_EXPRESSION(sub, -)
BINARY_EXPRESSION(lshift, <<)
BINARY_EXPRESSION(rshift, >>)
BINARY_EXPRESSION(eq, ==)
BINARY_EXPRESSION(ne, !=)
BINARY_EXPRESSION(le, <=)
BINARY_EXPRESSION(ge, >=)
BINARY_EXPRESSION(lt, <)
BINARY_EXPRESSION(gt, >)
BINARY_EXPRESSION(bitwise_and, &)
BINARY_EXPRESSION(bitwise_xor, ^)
BINARY_EXPRESSION(bitwise_or, |)
BINARY_EXPRESSION(logical_and, &&)
BINARY_EXPRESSION(logical_or, ||)
// A trinary expression.
class Trinary_expression : public Expression
{
public:
Trinary_expression(Expression* arg1, Expression* arg2, Expression* arg3)
: arg1_(arg1), arg2_(arg2), arg3_(arg3)
{ }
~Trinary_expression()
{
delete this->arg1_;
delete this->arg2_;
delete this->arg3_;
}
protected:
uint64_t
arg1_value(const Expression_eval_info* eei) const
{ return this->arg1_->value(eei); }
uint64_t
arg2_value(const Expression_eval_info* eei) const
{ return this->arg2_->value(eei); }
uint64_t
arg3_value(const Expression_eval_info* eei) const
{ return this->arg3_->value(eei); }
private:
Expression* arg1_;
Expression* arg2_;
Expression* arg3_;
};
// The conditional operator.
class Trinary_cond : public Trinary_expression
{
public:
Trinary_cond(Expression* arg1, Expression* arg2, Expression* arg3)
: Trinary_expression(arg1, arg2, arg3)
{ }
uint64_t
value(const Expression_eval_info* eei)
{
return (this->arg1_value(eei)
? this->arg2_value(eei)
: this->arg3_value(eei));
}
};
extern "C" Expression*
script_exp_trinary_cond(Expression* arg1, Expression* arg2, Expression* arg3)
{
return new Trinary_cond(arg1, arg2, arg3);
}
// Max function.
class Max_expression : public Binary_expression
{
public:
Max_expression(Expression* left, Expression* right)
: Binary_expression(left, right)
{ }
uint64_t
value(const Expression_eval_info* eei)
{ return std::max(this->left_value(eei), this->right_value(eei)); }
};
extern "C" Expression*
script_exp_function_max(Expression* left, Expression* right)
{
return new Max_expression(left, right);
}
// Min function.
class Min_expression : public Binary_expression
{
public:
Min_expression(Expression* left, Expression* right)
: Binary_expression(left, right)
{ }
uint64_t
value(const Expression_eval_info* eei)
{ return std::min(this->left_value(eei), this->right_value(eei)); }
};
extern "C" Expression*
script_exp_function_min(Expression* left, Expression* right)
{
return new Min_expression(left, right);
}
// Align function.
class Align_expression : public Binary_expression
{
public:
Align_expression(Expression* left, Expression* right)
: Binary_expression(left, right)
{ }
uint64_t
value(const Expression_eval_info* eei)
{
uint64_t align = this->right_value(eei);
uint64_t value = this->left_value(eei);
if (align <= 1)
return value;
return ((value + align - 1) / align) * align;
}
};
extern "C" Expression*
script_exp_function_align(Expression* left, Expression* right)
{
return new Align_expression(left, right);
}
// Assert function.
class Assert_expression : public Unary_expression
{
public:
Assert_expression(Expression* arg, const char* message, size_t length)
: Unary_expression(arg), message_(message, length)
{ }
uint64_t
value(const Expression_eval_info* eei)
{
uint64_t value = this->arg_value(eei);
if (!value)
gold_error("%s", this->message_.c_str());
return value;
}
private:
std::string message_;
};
extern "C" Expression*
script_exp_function_assert(Expression* expr, const char* message,
size_t length)
{
return new Assert_expression(expr, message, length);
}
// Functions.
extern "C" Expression*
script_exp_function_defined(const char*, size_t)
{
gold_fatal(_("DEFINED not implemented"));
}
extern "C" Expression*
script_exp_function_sizeof_headers()
{
gold_fatal(_("SIZEOF_HEADERS not implemented"));
}
extern "C" Expression*
script_exp_function_alignof(const char*, size_t)
{
gold_fatal(_("ALIGNOF not implemented"));
}
extern "C" Expression*
script_exp_function_sizeof(const char*, size_t)
{
gold_fatal(_("SIZEOF not implemented"));
}
extern "C" Expression*
script_exp_function_addr(const char*, size_t)
{
gold_fatal(_("ADDR not implemented"));
}
extern "C" Expression*
script_exp_function_loadaddr(const char*, size_t)
{
gold_fatal(_("LOADADDR not implemented"));
}
extern "C" Expression*
script_exp_function_origin(const char*, size_t)
{
gold_fatal(_("ORIGIN not implemented"));
}
extern "C" Expression*
script_exp_function_length(const char*, size_t)
{
gold_fatal(_("LENGTH not implemented"));
}
extern "C" Expression*
script_exp_function_constant(const char*, size_t)
{
gold_fatal(_("CONSTANT not implemented"));
}
extern "C" Expression*
script_exp_function_absolute(Expression*)
{
gold_fatal(_("ABSOLUTE not implemented"));
}
extern "C" Expression*
script_exp_function_data_segment_align(Expression*, Expression*)
{
gold_fatal(_("DATA_SEGMENT_ALIGN not implemented"));
}
extern "C" Expression*
script_exp_function_data_segment_relro_end(Expression*, Expression*)
{
gold_fatal(_("DATA_SEGMENT_RELRO_END not implemented"));
}
extern "C" Expression*
script_exp_function_data_segment_end(Expression*)
{
gold_fatal(_("DATA_SEGMENT_END not implemented"));
}
extern "C" Expression*
script_exp_function_segment_start(const char*, size_t, Expression*)
{
gold_fatal(_("SEGMENT_START not implemented"));
}
} // End namespace gold.

View File

@ -1,6 +1,6 @@
// gold.cc -- main linker functions
// Copyright 2006, 2007 Free Software Foundation, Inc.
// Copyright 2006, 2007, 2008 Free Software Foundation, Inc.
// Written by Ian Lance Taylor <iant@google.com>.
// This file is part of gold.
@ -202,6 +202,9 @@ queue_middle_tasks(const General_options& options,
// appropriate.
layout->define_section_symbols(symtab, input_objects->target());
// Define symbols from any linker scripts.
layout->define_script_symbols(symtab, input_objects->target());
// Read the relocations of the input files. We do this to find
// which symbols are used by relocations which require a GOT and/or
// a PLT entry, or a COPY reloc. When we implement garbage

View File

@ -1,6 +1,6 @@
// layout.cc -- lay out output file sections for gold
// Copyright 2006, 2007 Free Software Foundation, Inc.
// Copyright 2006, 2007, 2008 Free Software Foundation, Inc.
// Written by Ian Lance Taylor <iant@google.com>.
// This file is part of gold.
@ -63,9 +63,9 @@ Layout_task_runner::run(Workqueue* workqueue, const Task* task)
// Layout methods.
Layout::Layout(const General_options& options)
: options_(options), entry_(options.entry()), namepool_(), sympool_(),
dynpool_(), signatures_(),
Layout::Layout(const General_options& options, Script_options* script_options)
: options_(options), script_options_(script_options), namepool_(),
sympool_(), dynpool_(), signatures_(),
section_name_map_(), segment_list_(), section_list_(),
unattached_section_list_(), special_output_list_(),
section_headers_(NULL), tls_segment_(NULL), symtab_section_(NULL),
@ -722,7 +722,7 @@ Layout::finalize(const Input_objects* input_objects, Symbol_table* symtab,
// Lay out the file header.
Output_file_header* file_header;
file_header = new Output_file_header(target, symtab, segment_headers,
this->entry_);
this->script_options_->entry());
load_seg->add_initial_output_data(file_header);
this->special_output_list_.push_back(file_header);
@ -745,6 +745,10 @@ Layout::finalize(const Input_objects* input_objects, Symbol_table* symtab,
if (!parameters->doing_static_link())
this->assign_local_dynsym_offsets(input_objects);
// Process any symbol assignments from a linker script. This must
// be called after the symbol table has been finalized.
this->script_options_->finalize_symbols(symtab, this);
// Create the .shstrtab section.
Output_section* shstrtab_section = this->create_shstrtab();

View File

@ -1,6 +1,6 @@
// layout.h -- lay out output file sections for gold -*- C++ -*-
// Copyright 2006, 2007 Free Software Foundation, Inc.
// Copyright 2006, 2007, 2008 Free Software Foundation, Inc.
// Written by Ian Lance Taylor <iant@google.com>.
// This file is part of gold.
@ -28,6 +28,7 @@
#include <utility>
#include <vector>
#include "script.h"
#include "workqueue.h"
#include "object.h"
#include "dynobj.h"
@ -84,7 +85,7 @@ class Layout_task_runner : public Task_function_runner
class Layout
{
public:
Layout(const General_options& options);
Layout(const General_options& options, Script_options*);
// Given an input section SHNDX, named NAME, with data in SHDR, from
// the object file OBJECT, return the output section where this
@ -142,6 +143,11 @@ class Layout
void
define_section_symbols(Symbol_table*, const Target*);
// Define symbols from any linker script.
void
define_script_symbols(Symbol_table* symtab, const Target* target)
{ this->script_options_->add_symbols_to_table(symtab, target); }
// Return the Stringpool used for symbol names.
const Stringpool*
sympool() const
@ -241,11 +247,14 @@ class Layout
has_static_tls() const
{ return this->has_static_tls_; }
// Set the name of the entry symbol. This is used by linker scripts
// which look like regular objects.
void
set_entry(const char* entry)
{ this->entry_ = entry; }
// Return the options which may be set by a linker script.
Script_options*
script_options()
{ return this->script_options_; }
const Script_options*
script_options() const
{ return this->script_options_; }
// Dump statistical information to stderr.
void
@ -432,9 +441,8 @@ class Layout
// A reference to the options on the command line.
const General_options& options_;
// The name of the entry symbol. This is from the command line, or
// from a linker script, or is NULL.
const char* entry_;
// Information set by scripts or by command line options.
Script_options* script_options_;
// The output section names.
Stringpool namepool_;
// The output symbol names.

View File

@ -1,6 +1,6 @@
// main.cc -- gold main function.
// Copyright 2006, 2007 Free Software Foundation, Inc.
// Copyright 2006, 2007, 2008 Free Software Foundation, Inc.
// Written by Ian Lance Taylor <iant@google.com>.
// This file is part of gold.
@ -27,6 +27,7 @@
#endif
#include "libiberty.h"
#include "script.h"
#include "options.h"
#include "parameters.h"
#include "errors.h"
@ -58,8 +59,12 @@ main(int argc, char** argv)
// errors object.
initialize_parameters(&errors);
// Options which may be set by the command line or by linker
// scripts.
Script_options script_options;
// Handle the command line options.
Command_line command_line;
Command_line command_line(&script_options);
command_line.process(argc - 1, argv + 1);
long start_time = 0;
@ -82,7 +87,7 @@ main(int argc, char** argv)
Symbol_table symtab(command_line.number_of_input_files() * 1024);
// The layout object.
Layout layout(command_line.options());
Layout layout(command_line.options(), &script_options);
// Get the search path from the -L options.
Dirsearch search_path;

View File

@ -1,6 +1,6 @@
// options.c -- handle command line options for gold
// Copyright 2006, 2007 Free Software Foundation, Inc.
// Copyright 2006, 2007, 2008 Free Software Foundation, Inc.
// Written by Ian Lance Taylor <iant@google.com>.
// This file is part of gold.
@ -29,6 +29,7 @@
#include "libiberty.h"
#include "debug.h"
#include "script.h"
#include "options.h"
namespace gold
@ -154,7 +155,7 @@ invoke_script(int argc, char** argv, char* arg, bool long_option,
arg, long_option,
&ret);
if (!read_commandline_script(script_name, cmdline))
gold::gold_error(_("unable to parse script file %s\n"), script_name);
gold::gold_error(_("unable to parse script file %s"), script_name);
return ret;
}
@ -386,6 +387,9 @@ options::Command_line_options::options[] =
N_("--compress-debug-sections=[none" ZLIB_STR "]"),
TWO_DASHES,
&General_options::set_compress_debug_sections),
GENERAL_ARG('\0', "defsym", N_("Define a symbol"),
N_("--defsym SYMBOL=EXPRESSION"), TWO_DASHES,
&General_options::define_symbol),
GENERAL_NOARG('\0', "demangle", N_("Demangle C++ symbols in log messages"),
NULL, TWO_DASHES, &General_options::set_demangle),
GENERAL_NOARG('\0', "no-demangle",
@ -531,9 +535,8 @@ const int options::Command_line_options::debug_options_size =
// The default values for the general options.
General_options::General_options()
: entry_(NULL),
export_dynamic_(false),
General_options::General_options(Script_options* script_options)
: export_dynamic_(false),
soname_(NULL),
dynamic_linker_(NULL),
search_path_(),
@ -558,7 +561,8 @@ General_options::General_options()
thread_count_middle_(0),
thread_count_final_(0),
execstack_(EXECSTACK_FROM_INPUT),
debug_(0)
debug_(0),
script_options_(script_options)
{
// We initialize demangle_ based on the environment variable
// COLLECT_NO_DEMANGLE. The gcc collect2 program will demangle the
@ -568,13 +572,12 @@ General_options::General_options()
this->demangle_ = getenv("COLLECT_NO_DEMANGLE") == NULL;
}
// The default values for the position dependent options.
// Handle the --defsym option.
Position_dependent_options::Position_dependent_options()
: do_static_search_(false),
as_needed_(false),
include_whole_archive_(false)
void
General_options::define_symbol(const char* arg)
{
this->script_options_->define_symbol(arg);
}
// Handle the -z option.
@ -645,6 +648,15 @@ General_options::add_sysroot()
free(canonical_sysroot);
}
// The default values for the position dependent options.
Position_dependent_options::Position_dependent_options()
: do_static_search_(false),
as_needed_(false),
include_whole_archive_(false)
{
}
// Search_directory methods.
// This is called if we have a sysroot. Apply the sysroot if
@ -721,8 +733,8 @@ Input_arguments::end_group()
// Command_line options.
Command_line::Command_line()
: options_(), position_options_(), inputs_()
Command_line::Command_line(Script_options* script_options)
: options_(script_options), position_options_(), inputs_()
{
}

View File

@ -1,6 +1,6 @@
// options.h -- handle command line options for gold -*- C++ -*-
// Copyright 2006, 2007 Free Software Foundation, Inc.
// Copyright 2006, 2007, 2008 Free Software Foundation, Inc.
// Written by Ian Lance Taylor <iant@google.com>.
// This file is part of gold.
@ -106,12 +106,12 @@ class Search_directory
class General_options
{
public:
General_options();
General_options(Script_options*);
// -e: set entry address.
const char*
entry() const
{ return this->entry_; }
{ return this->script_options_->entry(); }
// -E: export dynamic symbols.
bool
@ -277,6 +277,15 @@ class General_options
debug() const
{ return this->debug_; }
// Return the options which may be set from a linker script.
Script_options*
script_options()
{ return this->script_options_; }
const Script_options*
script_options() const
{ return this->script_options_; }
private:
// Don't copy this structure.
General_options(const General_options&);
@ -318,7 +327,7 @@ class General_options
void
set_entry(const char* arg)
{ this->entry_ = arg; }
{ this->script_options_->set_entry(arg, strlen(arg)); }
void
set_export_dynamic()
@ -396,6 +405,9 @@ class General_options
arg);
}
void
define_symbol(const char* arg);
void
set_demangle()
{ this->demangle_ = true; }
@ -518,7 +530,6 @@ class General_options
void
add_sysroot();
const char* entry_;
bool export_dynamic_;
const char* soname_;
const char* dynamic_linker_;
@ -546,6 +557,9 @@ class General_options
int thread_count_final_;
Execstack execstack_;
unsigned int debug_;
// Some options can also be set from linker scripts. Those are
// stored here.
Script_options* script_options_;
};
// The current state of the position dependent options.
@ -810,7 +824,7 @@ class Command_line
public:
typedef Input_arguments::const_iterator const_iterator;
Command_line();
Command_line(Script_options*);
// Process the command line options. This will exit with an
// appropriate error message if an unrecognized option is seen.
@ -834,11 +848,6 @@ class Command_line
void
end_group(const char* arg);
// Set the entry symbol from a linker script.
void
set_entry(const char* entry)
{ this->options_.set_entry(entry); }
// Get an option argument--a helper function for special processing.
const char*
get_special_argument(const char* longname, int argc, char** argv,
@ -855,6 +864,15 @@ class Command_line
position_dependent_options() const
{ return this->position_options_; }
// Get the options which may be set from a linker script.
Script_options*
script_options()
{ return this->options_.script_options(); }
const Script_options*
script_options() const
{ return this->options_.script_options(); }
// The number of input files.
int
number_of_input_files() const

View File

@ -16,6 +16,7 @@ ehframe.cc
ehframe.h
errors.cc
errors.h
expression.cc
fileread.cc
fileread.h
gold.cc

View File

@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2007-12-21 15:26-0800\n"
"POT-Creation-Date: 2008-01-09 11:37-0800\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
@ -16,47 +16,47 @@ msgstr ""
"Content-Type: text/plain; charset=CHARSET\n"
"Content-Transfer-Encoding: 8bit\n"
#: archive.cc:96
#: archive.cc:97
#, c-format
msgid "%s: no archive symbol table (run ranlib)"
msgstr ""
#: archive.cc:147
#: archive.cc:151
#, c-format
msgid "%s: bad archive symbol table names"
msgstr ""
#: archive.cc:177
#: archive.cc:181
#, c-format
msgid "%s: malformed archive header at %zu"
msgstr ""
#: archive.cc:197
#: archive.cc:201
#, c-format
msgid "%s: malformed archive header size at %zu"
msgstr ""
#: archive.cc:208
#: archive.cc:212
#, c-format
msgid "%s: malformed archive header name at %zu"
msgstr ""
#: archive.cc:233
#: archive.cc:237
#, c-format
msgid "%s: bad extended name index at %zu"
msgstr ""
#: archive.cc:243
#: archive.cc:247
#, c-format
msgid "%s: bad extended name entry at header %zu"
msgstr ""
#: archive.cc:336
#: archive.cc:340
#, c-format
msgid "%s: short archive header at %zu"
msgstr ""
#: archive.cc:387 archive.cc:401
#: archive.cc:391 archive.cc:405
#, c-format
msgid "%s: member at %zu is not an ELF object"
msgstr ""
@ -114,7 +114,7 @@ msgstr ""
msgid "dynamic symbol table name section has wrong type: %u"
msgstr ""
#: dynobj.cc:404 object.cc:241 object.cc:579
#: dynobj.cc:404 object.cc:251 object.cc:589
#, c-format
msgid "bad section name offset for section %u: %lu"
msgstr ""
@ -178,82 +178,158 @@ msgstr ""
msgid "size of dynamic symbols is not multiple of symbol size"
msgstr ""
#: dynobj.cc:1312
#: dynobj.cc:1316
#, c-format
msgid "symbol %s has undefined version %s"
msgstr ""
#: errors.cc:88
#: errors.cc:106
#, c-format
msgid "%s: warning: "
msgstr ""
#: errors.cc:127
#: errors.cc:137
#, c-format
msgid "%s: %s: warning: "
msgstr ""
#: errors.cc:154
#: errors.cc:161
#, c-format
msgid "%s: %s: undefined reference to '%s'\n"
msgstr ""
#: errors.cc:164
#: errors.cc:171
#, c-format
msgid "%s: "
msgstr ""
#: fileread.cc:49
#: expression.cc:104
#, c-format
msgid "undefined symbol '%s' referenced in expression"
msgstr ""
#: expression.cc:427
msgid "DEFINED not implemented"
msgstr ""
#: expression.cc:433
msgid "SIZEOF_HEADERS not implemented"
msgstr ""
#: expression.cc:439
msgid "ALIGNOF not implemented"
msgstr ""
#: expression.cc:445
msgid "SIZEOF not implemented"
msgstr ""
#: expression.cc:451
msgid "ADDR not implemented"
msgstr ""
#: expression.cc:457
msgid "LOADADDR not implemented"
msgstr ""
#: expression.cc:463
msgid "ORIGIN not implemented"
msgstr ""
#: expression.cc:469
msgid "LENGTH not implemented"
msgstr ""
#: expression.cc:475
msgid "CONSTANT not implemented"
msgstr ""
#: expression.cc:481
msgid "ABSOLUTE not implemented"
msgstr ""
#: expression.cc:487
msgid "DATA_SEGMENT_ALIGN not implemented"
msgstr ""
#: expression.cc:493
msgid "DATA_SEGMENT_RELRO_END not implemented"
msgstr ""
#: expression.cc:499
msgid "DATA_SEGMENT_END not implemented"
msgstr ""
#: expression.cc:505
msgid "SEGMENT_START not implemented"
msgstr ""
#: fileread.cc:50
#, c-format
msgid "munmap failed: %s"
msgstr ""
#: fileread.cc:90
#: fileread.cc:91
#, c-format
msgid "close of %s failed: %s"
msgstr ""
#: fileread.cc:114
#: fileread.cc:115
#, c-format
msgid "%s: fstat failed: %s"
msgstr ""
#: fileread.cc:229
#: fileread.cc:240
#, c-format
msgid "%s: pread failed: %s"
msgstr ""
#: fileread.cc:235
#: fileread.cc:246
#, c-format
msgid "%s: file too short: read only %lld of %lld bytes at %lld"
msgstr ""
#: fileread.cc:310
#: fileread.cc:325
#, c-format
msgid "%s: mmap offset %lld size %lld failed: %s"
msgstr ""
#: fileread.cc:391
#: fileread.cc:400
#, c-format
msgid "%s: lseek failed: %s"
msgstr ""
#: fileread.cc:406
#, c-format
msgid "%s: readv failed: %s"
msgstr ""
#: fileread.cc:409
#, c-format
msgid "%s: file too short: read only %zd of %zd bytes at %lld"
msgstr ""
#: fileread.cc:556
#, c-format
msgid "%s: total bytes mapped for read: %llu\n"
msgstr ""
#: fileread.cc:393
#: fileread.cc:558
#, c-format
msgid "%s: maximum bytes mapped for read at one time: %llu\n"
msgstr ""
#: fileread.cc:463
#: fileread.cc:628
#, c-format
msgid "cannot find -l%s"
msgstr ""
#: fileread.cc:490
#: fileread.cc:655
#, c-format
msgid "cannot find %s"
msgstr ""
#: fileread.cc:501
#: fileread.cc:666
#, c-format
msgid "cannot open %s: %s"
msgstr ""
@ -398,7 +474,7 @@ msgstr ""
msgid "%s: unsupported ELF machine number %d"
msgstr ""
#: object.cc:71 script.cc:1229
#: object.cc:71
#, c-format
msgid "%s: %s"
msgstr ""
@ -408,124 +484,124 @@ msgstr ""
msgid "section name section has wrong type: %u"
msgstr ""
#: object.cc:315
#: object.cc:325
#, c-format
msgid "invalid symbol table name index: %u"
msgstr ""
#: object.cc:321
#: object.cc:331
#, c-format
msgid "symbol table name section has wrong type: %u"
msgstr ""
#: object.cc:402
#: object.cc:412
#, c-format
msgid "section group %u info %u out of range"
msgstr ""
#: object.cc:420
#: object.cc:430
#, c-format
msgid "symbol %u name offset %u out of range"
msgstr ""
#: object.cc:452
#: object.cc:462
#, c-format
msgid "section %u in section group %u out of range"
msgstr ""
#: object.cc:542 reloc.cc:206 reloc.cc:530
#: object.cc:552 reloc.cc:213 reloc.cc:570
#, c-format
msgid "relocation section %u has bad info %u"
msgstr ""
#: object.cc:713
#: object.cc:723
msgid "size of symbols is not multiple of symbol size"
msgstr ""
#: object.cc:812
#: object.cc:823
#, c-format
msgid "local symbol %u section name out of range: %u >= %u"
msgstr ""
#. FIXME: Handle SHN_XINDEX.
#: object.cc:869
#: object.cc:880
#, c-format
msgid "unknown section index %u for local symbol %u"
msgstr ""
#: object.cc:878
#: object.cc:889
#, c-format
msgid "local symbol %u section index %u out of range"
msgstr ""
#: object.cc:1181
#: object.cc:1192
#, c-format
msgid "%s: incompatible target"
msgstr ""
#: object.cc:1336
#: object.cc:1347
#, c-format
msgid "%s: unsupported ELF file type %d"
msgstr ""
#: object.cc:1355 object.cc:1401 object.cc:1435
#: object.cc:1366 object.cc:1412 object.cc:1446
#, c-format
msgid "%s: ELF file too short"
msgstr ""
#: object.cc:1363
#: object.cc:1374
#, c-format
msgid "%s: invalid ELF version 0"
msgstr ""
#: object.cc:1365
#: object.cc:1376
#, c-format
msgid "%s: unsupported ELF version %d"
msgstr ""
#: object.cc:1372
#: object.cc:1383
#, c-format
msgid "%s: invalid ELF class 0"
msgstr ""
#: object.cc:1378
#: object.cc:1389
#, c-format
msgid "%s: unsupported ELF class %d"
msgstr ""
#: object.cc:1385
#: object.cc:1396
#, c-format
msgid "%s: invalid ELF data encoding"
msgstr ""
#: object.cc:1391
#: object.cc:1402
#, c-format
msgid "%s: unsupported ELF data encoding %d"
msgstr ""
#: object.cc:1411
#: object.cc:1422
#, c-format
msgid "%s: not configured to support 32-bit big-endian object"
msgstr ""
#: object.cc:1424
#: object.cc:1435
#, c-format
msgid "%s: not configured to support 32-bit little-endian object"
msgstr ""
#: object.cc:1445
#: object.cc:1456
#, c-format
msgid "%s: not configured to support 64-bit big-endian object"
msgstr ""
#: object.cc:1458
#: object.cc:1469
#, c-format
msgid "%s: not configured to support 64-bit little-endian object"
msgstr ""
#: options.cc:157
#: options.cc:158
#, c-format
msgid "%s: unable to parse script file %s\n"
msgid "unable to parse script file %s"
msgstr ""
#: options.cc:185
@ -576,337 +652,361 @@ msgid "]"
msgstr ""
#: options.cc:390
msgid "Demangle C++ symbols in log messages"
msgid "Define a symbol"
msgstr ""
#: options.cc:391
msgid "--defsym SYMBOL=EXPRESSION"
msgstr ""
#: options.cc:393
msgid "Do not demangle C++ symbols in log messages"
msgid "Demangle C++ symbols in log messages"
msgstr ""
#: options.cc:396
msgid "Do not demangle C++ symbols in log messages"
msgstr ""
#: options.cc:399
msgid "Try to detect violations of the One Definition Rule"
msgstr ""
#: options.cc:398
msgid "Export all dynamic symbols"
msgstr ""
#: options.cc:400
msgid "Create exception frame header"
#: options.cc:401
msgid "Set program start address"
msgstr ""
#: options.cc:402
msgid "Set dynamic linker path"
msgid "-e ADDRESS, --entry ADDRESS"
msgstr ""
#: options.cc:403
msgid "-I PROGRAM, --dynamic-linker PROGRAM"
msgstr ""
#: options.cc:405
msgid "Search for library LIBNAME"
#: options.cc:404
msgid "Export all dynamic symbols"
msgstr ""
#: options.cc:406
msgid "-lLIBNAME, --library LIBNAME"
msgid "Create exception frame header"
msgstr ""
#: options.cc:408
msgid "Add directory to search path"
msgid "Set shared library name"
msgstr ""
#: options.cc:409
msgid "-L DIR, --library-path DIR"
msgid "-h FILENAME, -soname FILENAME"
msgstr ""
#: options.cc:411
msgid "Ignored for compatibility"
msgid "Set dynamic linker path"
msgstr ""
#: options.cc:413
msgid "Set output file name"
#: options.cc:412
msgid "-I PROGRAM, --dynamic-linker PROGRAM"
msgstr ""
#: options.cc:414
msgid "-o FILE, --output FILE"
msgid "Search for library LIBNAME"
msgstr ""
#: options.cc:416
msgid "Optimize output file size"
#: options.cc:415
msgid "-lLIBNAME, --library LIBNAME"
msgstr ""
#: options.cc:417
msgid "-O level"
msgid "Add directory to search path"
msgstr ""
#: options.cc:419
msgid "Generate relocatable output"
#: options.cc:418
msgid "-L DIR, --library-path DIR"
msgstr ""
#: options.cc:421
msgid "Add DIR to runtime search path"
#: options.cc:420
msgid "Ignored for compatibility"
msgstr ""
#: options.cc:422
msgid "-R DIR, -rpath DIR"
msgid "Set output file name"
msgstr ""
#: options.cc:423
msgid "-o FILE, --output FILE"
msgstr ""
#: options.cc:425
msgid "Add DIR to link time shared library search path"
msgid "Optimize output file size"
msgstr ""
#: options.cc:426
msgid "--rpath-link DIR"
msgid "-O level"
msgstr ""
#: options.cc:428
msgid "Strip all symbols"
msgid "Generate relocatable output"
msgstr ""
#: options.cc:430
msgid "Add DIR to runtime search path"
msgstr ""
#: options.cc:431
msgid "-R DIR, -rpath DIR"
msgstr ""
#: options.cc:434
msgid "Add DIR to link time shared library search path"
msgstr ""
#: options.cc:435
msgid "--rpath-link DIR"
msgstr ""
#: options.cc:437
msgid "Strip all symbols"
msgstr ""
#: options.cc:440
msgid "Strip debug symbols that are unused by gdb (at least versions <= 6.7)"
msgstr ""
#. This must come after -Sdebug since it's a prefix of it.
#: options.cc:435
#: options.cc:444
msgid "Strip debugging information"
msgstr ""
#: options.cc:437
#: options.cc:446
msgid "Generate shared library"
msgstr ""
#: options.cc:439
#: options.cc:448
msgid "Do not link against shared libraries"
msgstr ""
#: options.cc:441
#: options.cc:450
msgid "Print resource usage statistics"
msgstr ""
#: options.cc:443
#: options.cc:452
msgid "Set target system root directory"
msgstr ""
#: options.cc:444
#: options.cc:453
msgid "--sysroot DIR"
msgstr ""
#: options.cc:445
#: options.cc:454
msgid "Set the address of the .text section"
msgstr ""
#: options.cc:446
#: options.cc:455
msgid "-Ttext ADDRESS"
msgstr ""
#. This must come after -Ttext since it's a prefix of it.
#: options.cc:449
#: options.cc:458
msgid "Read linker script"
msgstr ""
#: options.cc:450
#: options.cc:459
msgid "-T FILE, --script FILE"
msgstr ""
#: options.cc:452
#: options.cc:461
msgid "Run the linker multi-threaded"
msgstr ""
#: options.cc:454
#: options.cc:463
msgid "Do not run the linker multi-threaded"
msgstr ""
#: options.cc:456
#: options.cc:465
msgid "Number of threads to use"
msgstr ""
#: options.cc:457
#: options.cc:466
msgid "--thread-count COUNT"
msgstr ""
#: options.cc:460
#: options.cc:469
msgid "Number of threads to use in initial pass"
msgstr ""
#: options.cc:461
#: options.cc:470
msgid "--thread-count-initial COUNT"
msgstr ""
#: options.cc:464
#: options.cc:473
msgid "Number of threads to use in middle pass"
msgstr ""
#: options.cc:465
#: options.cc:474
msgid "--thread-count-middle COUNT"
msgstr ""
#: options.cc:468
#: options.cc:477
msgid "Number of threads to use in final pass"
msgstr ""
#: options.cc:469
#: options.cc:478
msgid "--thread-count-final COUNT"
msgstr ""
#: options.cc:472
#: options.cc:481
msgid "Include all archive contents"
msgstr ""
#: options.cc:476
#: options.cc:485
msgid "Include only needed archive contents"
msgstr ""
#: options.cc:481
#: options.cc:490
msgid ""
"Subcommands as follows:\n"
" -z execstack Mark output as requiring executable stack\n"
" -z noexecstack Mark output as not requiring executable stack"
msgstr ""
#: options.cc:484
#: options.cc:493
msgid "-z SUBCOMMAND"
msgstr ""
#: options.cc:487
#: options.cc:496
msgid "Start a library search group"
msgstr ""
#: options.cc:489
#: options.cc:498
msgid "End a library search group"
msgstr ""
#: options.cc:491
#: options.cc:500
msgid "Report usage information"
msgstr ""
#: options.cc:493
#: options.cc:502
msgid "Report version information"
msgstr ""
#: options.cc:495
#: options.cc:504
msgid "Turn on debugging (all,task)"
msgstr ""
#: options.cc:496
#: options.cc:505
msgid "--debug=TYPE"
msgstr ""
#: options.cc:590
#: options.cc:600
#, c-format
msgid "%s: unrecognized -z subcommand: %s\n"
msgstr ""
#: options.cc:613
#: options.cc:623
#, c-format
msgid "%s: unrecognized --debug subcommand: %s\n"
msgstr ""
#: options.cc:793
#: options.cc:812
msgid "unexpected argument"
msgstr ""
#: options.cc:800 options.cc:852 options.cc:933
#: options.cc:819 options.cc:871 options.cc:952
msgid "missing argument"
msgstr ""
#: options.cc:813 options.cc:861
#: options.cc:832 options.cc:880
msgid "unknown option"
msgstr ""
#: options.cc:879
#: options.cc:898
#, c-format
msgid "%s: missing group end\n"
msgstr ""
#: options.cc:1007
#: options.cc:1026
msgid "may not nest groups"
msgstr ""
#: options.cc:1017
#: options.cc:1036
msgid "group end without group start"
msgstr ""
#: options.cc:1027
#: options.cc:1046
#, c-format
msgid "%s: use the --help option for usage information\n"
msgstr ""
#: options.cc:1036
#: options.cc:1055
#, c-format
msgid "%s: %s: %s\n"
msgstr ""
#: options.cc:1045
#: options.cc:1064
#, c-format
msgid "%s: -%c: %s\n"
msgstr ""
#: options.h:331
#: options.h:358
#, c-format
msgid "invalid optimization level: %s"
msgstr ""
#: options.h:377
#: options.h:404
#, c-format
msgid "unsupported argument to --compress-debug-sections: %s"
msgstr ""
#: options.h:428
#: options.h:458
#, c-format
msgid "invalid argument to -Ttext: %s"
msgstr ""
#: options.h:437
#: options.h:467
#, c-format
msgid "invalid thread count: %s"
msgstr ""
#: options.h:445
#: options.h:475
msgid "--threads not supported"
msgstr ""
#: output.cc:1478
#: output.cc:1511
#, c-format
msgid "invalid alignment %lu for section \"%s\""
msgstr ""
#: output.cc:2383
#: output.cc:2418
#, c-format
msgid "%s: open: %s"
msgstr ""
#: output.cc:2403
#: output.cc:2438
#, c-format
msgid "%s: mremap: %s"
msgstr ""
#: output.cc:2439
#: output.cc:2474
#, c-format
msgid "%s: lseek: %s"
msgstr ""
#: output.cc:2442 output.cc:2479
#: output.cc:2477 output.cc:2514
#, c-format
msgid "%s: write: %s"
msgstr ""
#: output.cc:2450
#: output.cc:2485
#, c-format
msgid "%s: mmap: %s"
msgstr ""
#: output.cc:2460
#: output.cc:2495
#, c-format
msgid "%s: munmap: %s"
msgstr ""
#: output.cc:2477
#: output.cc:2512
#, c-format
msgid "%s: write: unexpected 0 return-value"
msgstr ""
#: output.cc:2489
#: output.cc:2524
#, c-format
msgid "%s: close: %s"
msgstr ""
@ -927,22 +1027,22 @@ msgstr ""
msgid "%s: not an object or archive"
msgstr ""
#: reloc.cc:225 reloc.cc:548
#: reloc.cc:232 reloc.cc:588
#, c-format
msgid "relocation section %u uses unexpected symbol table %u"
msgstr ""
#: reloc.cc:240 reloc.cc:566
#: reloc.cc:247 reloc.cc:606
#, c-format
msgid "unexpected entsize for reloc section %u: %lu != %u"
msgstr ""
#: reloc.cc:249 reloc.cc:575
#: reloc.cc:256 reloc.cc:615
#, c-format
msgid "reloc section %u size %lu uneven"
msgstr ""
#: reloc.cc:839
#: reloc.cc:879
#, c-format
msgid "reloc section size %zu is not a multiple of reloc size %d\n"
msgstr ""
@ -961,40 +1061,45 @@ msgstr ""
#. Two definitions of the same symbol.
#. FIXME: Do a better job of reporting locations.
#: resolve.cc:318
#: resolve.cc:322
#, c-format
msgid "%s: multiple definition of %s"
msgstr ""
#: resolve.cc:319 resolve.cc:324
#: resolve.cc:323 resolve.cc:328
msgid "command line"
msgstr ""
#: resolve.cc:321
#: resolve.cc:325
#, c-format
msgid "%s: previous definition here"
msgstr ""
#. There are some options that we could handle here--e.g.,
#. -lLIBRARY. Should we bother?
#: script.cc:1333
#: script.cc:1413
#, c-format
msgid ""
"%s: Ignoring command OPTION; OPTION is only valid for scripts specified via -"
"T"
msgid "%s:%d:%d: %s"
msgstr ""
#: stringpool.cc:537
#. There are some options that we could handle here--e.g.,
#. -lLIBRARY. Should we bother?
#: script.cc:1539
#, c-format
msgid ""
"%s:%d:%d: ignoring command OPTION; OPTION is only valid for scripts "
"specified via -T/--script"
msgstr ""
#: stringpool.cc:525
#, c-format
msgid "%s: %s entries: %zu; buckets: %zu\n"
msgstr ""
#: stringpool.cc:541
#: stringpool.cc:529
#, c-format
msgid "%s: %s entries: %zu\n"
msgstr ""
#: stringpool.cc:544
#: stringpool.cc:532
#, c-format
msgid "%s: %s Stringdata structures: %zu\n"
msgstr ""
@ -1023,27 +1128,27 @@ msgstr ""
msgid "versym for symbol %zu has no name: %u"
msgstr ""
#: symtab.cc:1493 symtab.cc:1709
#: symtab.cc:1499 symtab.cc:1715
#, c-format
msgid "%s: unsupported symbol section 0x%x"
msgstr ""
#: symtab.cc:1833
#: symtab.cc:1839
#, c-format
msgid "%s: undefined reference to '%s'"
msgstr ""
#: symtab.cc:1918
#: symtab.cc:1924
#, c-format
msgid "%s: symbol table entries: %zu; buckets: %zu\n"
msgstr ""
#: symtab.cc:1921
#: symtab.cc:1927
#, c-format
msgid "%s: symbol table entries: %zu\n"
msgstr ""
#: symtab.cc:1990
#: symtab.cc:1996
#, c-format
msgid ""
"while linking %s: symbol '%s' defined in multiple places (possible ODR "

View File

@ -1,6 +1,6 @@
// resolve.cc -- symbol resolution for gold
// Copyright 2006, 2007 Free Software Foundation, Inc.
// Copyright 2006, 2007, 2008 Free Software Foundation, Inc.
// Written by Ian Lance Taylor <iant@google.com>.
// This file is part of gold.
@ -277,11 +277,15 @@ Symbol_table::should_override(const Symbol* to, unsigned int frombits,
{
*adjust_common_sizes = false;
unsigned int tobits = symbol_to_bits(to->binding(),
(to->source() == Symbol::FROM_OBJECT
&& to->object()->is_dynamic()),
to->shndx(),
to->type());
unsigned int tobits;
if (to->source() == Symbol::FROM_OBJECT)
tobits = symbol_to_bits(to->binding(),
to->object()->is_dynamic(),
to->shndx(),
to->type());
else
tobits = symbol_to_bits(to->binding(), false, elfcpp::SHN_ABS,
to->type());
// FIXME: Warn if either but not both of TO and SYM are STT_TLS.

View File

@ -1,6 +1,6 @@
/* script-c.h -- C interface for linker scripts in gold. */
/* Copyright 2006, 2007 Free Software Foundation, Inc.
/* Copyright 2006, 2007, 2008 Free Software Foundation, Inc.
Written by Ian Lance Taylor <iant@google.com>.
This file is part of gold.
@ -30,6 +30,31 @@
extern "C" {
#endif
/* A string value for the bison parser. */
struct Parser_string
{
const char* value;
size_t length;
};
/* The expression functions deal with pointers to Expression objects.
Since the bison parser generates C code, this is a hack to keep the
C++ code type safe. This hacks assumes that all pointers look
alike. */
#ifdef __cplusplus
namespace gold
{
class Expression;
}
typedef gold::Expression* Expression_ptr;
#else
typedef void* Expression_ptr;
#endif
/* The bison parser definitions. */
#include "yyscript.h"
/* The bison parser function. */
@ -50,7 +75,7 @@ yyerror(void* closure, const char*);
/* Called by the bison parser to add a file to the link. */
extern void
script_add_file(void* closure, const char*);
script_add_file(void* closure, const char*, size_t);
/* Called by the bison parser to start and stop a group. */
@ -69,11 +94,119 @@ script_end_as_needed(void* closure);
/* Called by the bison parser to set the entry symbol. */
extern void
script_set_entry(void* closure, const char*);
script_set_entry(void* closure, const char*, size_t);
/* Called by the bison parser to parse an OPTION. */
extern void
script_parse_option(void* closure, const char*);
script_parse_option(void* closure, const char*, size_t);
/* Called by the bison parser to push the lexer into expression
mode. */
extern void
script_push_lex_into_expression_mode(void* closure);
/* Called by the bison parser to pop the lexer mode. */
extern void
script_pop_lex_mode(void* closure);
/* Called by the bison parser to set a symbol to a value. PROVIDE is
non-zero if the symbol should be provided--only defined if there is
an undefined reference. HIDDEN is non-zero if the symbol should be
hidden. */
extern void
script_set_symbol(void* closure, const char*, size_t, Expression_ptr,
int provide, int hidden);
/* Called by the bison parser for expressions. */
extern Expression_ptr
script_exp_unary_minus(Expression_ptr);
extern Expression_ptr
script_exp_unary_logical_not(Expression_ptr);
extern Expression_ptr
script_exp_unary_bitwise_not(Expression_ptr);
extern Expression_ptr
script_exp_binary_mult(Expression_ptr, Expression_ptr);
extern Expression_ptr
script_exp_binary_div(Expression_ptr, Expression_ptr);
extern Expression_ptr
script_exp_binary_mod(Expression_ptr, Expression_ptr);
extern Expression_ptr
script_exp_binary_add(Expression_ptr, Expression_ptr);
extern Expression_ptr
script_exp_binary_sub(Expression_ptr, Expression_ptr);
extern Expression_ptr
script_exp_binary_lshift(Expression_ptr, Expression_ptr);
extern Expression_ptr
script_exp_binary_rshift(Expression_ptr, Expression_ptr);
extern Expression_ptr
script_exp_binary_eq(Expression_ptr, Expression_ptr);
extern Expression_ptr
script_exp_binary_ne(Expression_ptr, Expression_ptr);
extern Expression_ptr
script_exp_binary_le(Expression_ptr, Expression_ptr);
extern Expression_ptr
script_exp_binary_ge(Expression_ptr, Expression_ptr);
extern Expression_ptr
script_exp_binary_lt(Expression_ptr, Expression_ptr);
extern Expression_ptr
script_exp_binary_gt(Expression_ptr, Expression_ptr);
extern Expression_ptr
script_exp_binary_bitwise_and(Expression_ptr, Expression_ptr);
extern Expression_ptr
script_exp_binary_bitwise_xor(Expression_ptr, Expression_ptr);
extern Expression_ptr
script_exp_binary_bitwise_or(Expression_ptr, Expression_ptr);
extern Expression_ptr
script_exp_binary_logical_and(Expression_ptr, Expression_ptr);
extern Expression_ptr
script_exp_binary_logical_or(Expression_ptr, Expression_ptr);
extern Expression_ptr
script_exp_trinary_cond(Expression_ptr, Expression_ptr, Expression_ptr);
extern Expression_ptr
script_exp_integer(uint64_t);
extern Expression_ptr
script_exp_string(const char*, size_t);
extern Expression_ptr
script_exp_function_max(Expression_ptr, Expression_ptr);
extern Expression_ptr
script_exp_function_min(Expression_ptr, Expression_ptr);
extern Expression_ptr
script_exp_function_defined(const char*, size_t);
extern Expression_ptr
script_exp_function_sizeof_headers();
extern Expression_ptr
script_exp_function_alignof(const char*, size_t);
extern Expression_ptr
script_exp_function_sizeof(const char*, size_t);
extern Expression_ptr
script_exp_function_addr(const char*, size_t);
extern Expression_ptr
script_exp_function_loadaddr(const char*, size_t);
extern Expression_ptr
script_exp_function_origin(const char*, size_t);
extern Expression_ptr
script_exp_function_length(const char*, size_t);
extern Expression_ptr
script_exp_function_constant(const char*, size_t);
extern Expression_ptr
script_exp_function_absolute(Expression_ptr);
extern Expression_ptr
script_exp_function_align(Expression_ptr, Expression_ptr);
extern Expression_ptr
script_exp_function_data_segment_align(Expression_ptr, Expression_ptr);
extern Expression_ptr
script_exp_function_data_segment_relro_end(Expression_ptr, Expression_ptr);
extern Expression_ptr
script_exp_function_data_segment_end(Expression_ptr);
extern Expression_ptr
script_exp_function_segment_start(const char*, size_t, Expression_ptr);
extern Expression_ptr
script_exp_function_assert(Expression_ptr, const char*, size_t);
#ifdef __cplusplus
}

View File

@ -1,6 +1,6 @@
// script.cc -- handle linker scripts for gold.
// Copyright 2006, 2007 Free Software Foundation, Inc.
// Copyright 2006, 2007, 2008 Free Software Foundation, Inc.
// Written by Ian Lance Taylor <iant@google.com>.
// This file is part of gold.
@ -28,6 +28,7 @@
#include <cstdlib>
#include "filenames.h"
#include "elfcpp.h"
#include "dirsearch.h"
#include "options.h"
#include "fileread.h"
@ -35,7 +36,7 @@
#include "readsyms.h"
#include "parameters.h"
#include "layout.h"
#include "yyscript.h"
#include "symtab.h"
#include "script.h"
#include "script-c.h"
@ -57,6 +58,8 @@ class Token
TOKEN_EOF,
// Token is a string of characters.
TOKEN_STRING,
// Token is a quoted string of characters.
TOKEN_QUOTED_STRING,
// Token is an operator.
TOKEN_OPERATOR,
// Token is a number (an integer).
@ -65,39 +68,33 @@ class Token
// We need an empty constructor so that we can put this STL objects.
Token()
: classification_(TOKEN_INVALID), value_(), opcode_(0),
lineno_(0), charpos_(0)
: classification_(TOKEN_INVALID), value_(NULL), value_length_(0),
opcode_(0), lineno_(0), charpos_(0)
{ }
// A general token with no value.
Token(Classification classification, int lineno, int charpos)
: classification_(classification), value_(), opcode_(0),
lineno_(lineno), charpos_(charpos)
: classification_(classification), value_(NULL), value_length_(0),
opcode_(0), lineno_(lineno), charpos_(charpos)
{
gold_assert(classification == TOKEN_INVALID
|| classification == TOKEN_EOF);
}
// A general token with a value.
Token(Classification classification, const std::string& value,
Token(Classification classification, const char* value, size_t length,
int lineno, int charpos)
: classification_(classification), value_(value), opcode_(0),
lineno_(lineno), charpos_(charpos)
: classification_(classification), value_(value), value_length_(length),
opcode_(0), lineno_(lineno), charpos_(charpos)
{
gold_assert(classification != TOKEN_INVALID
&& classification != TOKEN_EOF);
}
// A token representing a string of characters.
Token(const std::string& s, int lineno, int charpos)
: classification_(TOKEN_STRING), value_(s), opcode_(0),
lineno_(lineno), charpos_(charpos)
{ }
// A token representing an operator.
Token(int opcode, int lineno, int charpos)
: classification_(TOKEN_OPERATOR), value_(), opcode_(opcode),
lineno_(lineno), charpos_(charpos)
: classification_(TOKEN_OPERATOR), value_(NULL), value_length_(0),
opcode_(opcode), lineno_(lineno), charpos_(charpos)
{ }
// Return whether the token is invalid.
@ -127,10 +124,12 @@ class Token
// Get the value of a token.
const std::string&
string_value() const
const char*
string_value(size_t* length) const
{
gold_assert(this->classification_ == TOKEN_STRING);
gold_assert(this->classification_ == TOKEN_STRING
|| this->classification_ == TOKEN_QUOTED_STRING);
*length = this->value_length_;
return this->value_;
}
@ -141,18 +140,23 @@ class Token
return this->opcode_;
}
int64_t
uint64_t
integer_value() const
{
gold_assert(this->classification_ == TOKEN_INTEGER);
return strtoll(this->value_.c_str(), NULL, 0);
// Null terminate.
std::string s(this->value_, this->value_length_);
return strtoull(s.c_str(), NULL, 0);
}
private:
// The token classification.
Classification classification_;
// The token value, for TOKEN_STRING or TOKEN_INTEGER.
std::string value_;
// The token value, for TOKEN_STRING or TOKEN_QUOTED_STRING or
// TOKEN_INTEGER.
const char* value_;
// The length of the token value.
size_t value_length_;
// The token value, for TOKEN_OPERATOR.
int opcode_;
// The line number where this token started (one based).
@ -162,80 +166,95 @@ class Token
int charpos_;
};
// This class handles lexing a file into a sequence of tokens. We
// don't expect linker scripts to be large, so we just read them and
// tokenize them all at once.
// This class handles lexing a file into a sequence of tokens.
class Lex
{
public:
Lex(Input_file* input_file)
: input_file_(input_file), tokens_()
// We unfortunately have to support different lexing modes, because
// when reading different parts of a linker script we need to parse
// things differently.
enum Mode
{
// Reading an ordinary linker script.
LINKER_SCRIPT,
// Reading an expression in a linker script.
EXPRESSION,
// Reading a version script.
VERSION_SCRIPT
};
Lex(const char* input_string, size_t input_length, int parsing_token)
: input_string_(input_string), input_length_(input_length),
current_(input_string), mode_(LINKER_SCRIPT),
first_token_(parsing_token), token_(),
lineno_(1), linestart_(input_string)
{ }
// Tokenize the file. Return the final token, which will be either
// an invalid token or an EOF token. An invalid token indicates
// that tokenization failed.
Token
tokenize();
// Read a file into a string.
static void
read_file(Input_file*, std::string*);
// A token sequence.
typedef std::vector<Token> Token_sequence;
// Return the next token.
const Token*
next_token();
// Return the tokens.
const Token_sequence&
tokens() const
{ return this->tokens_; }
// Return the current lexing mode.
Lex::Mode
mode() const
{ return this->mode_; }
// Set the lexing mode.
void
set_mode(Mode mode)
{ this->mode_ = mode; }
private:
Lex(const Lex&);
Lex& operator=(const Lex&);
// Read the file into a string buffer.
void
read_file(std::string*);
// Make a general token with no value at the current location.
Token
make_token(Token::Classification c, const char* p) const
{ return Token(c, this->lineno_, p - this->linestart_ + 1); }
make_token(Token::Classification c, const char* start) const
{ return Token(c, this->lineno_, start - this->linestart_ + 1); }
// Make a general token with a value at the current location.
Token
make_token(Token::Classification c, const std::string& v, const char* p)
make_token(Token::Classification c, const char* v, size_t len,
const char* start)
const
{ return Token(c, v, this->lineno_, p - this->linestart_ + 1); }
{ return Token(c, v, len, this->lineno_, start - this->linestart_ + 1); }
// Make an operator token at the current location.
Token
make_token(int opcode, const char* p) const
{ return Token(opcode, this->lineno_, p - this->linestart_ + 1); }
make_token(int opcode, const char* start) const
{ return Token(opcode, this->lineno_, start - this->linestart_ + 1); }
// Make an invalid token at the current location.
Token
make_invalid_token(const char* p)
{ return this->make_token(Token::TOKEN_INVALID, p); }
make_invalid_token(const char* start)
{ return this->make_token(Token::TOKEN_INVALID, start); }
// Make an EOF token at the current location.
Token
make_eof_token(const char* p)
{ return this->make_token(Token::TOKEN_EOF, p); }
make_eof_token(const char* start)
{ return this->make_token(Token::TOKEN_EOF, start); }
// Return whether C can be the first character in a name. C2 is the
// next character, since we sometimes need that.
static inline bool
inline bool
can_start_name(char c, char c2);
// Return whether C can appear in a name which has already started.
static inline bool
inline bool
can_continue_name(char c);
// Return whether C, C2, C3 can start a hex number.
static inline bool
inline bool
can_start_hex(char c, char c2, char c3);
// Return whether C can appear in a hex number.
static inline bool
inline bool
can_continue_hex(char c);
// Return whether C can start a non-hex number.
@ -243,7 +262,7 @@ class Lex
can_start_number(char c);
// Return whether C can appear in a non-hex number.
static inline bool
inline bool
can_continue_number(char c)
{ return Lex::can_start_number(c); }
@ -279,20 +298,30 @@ class Lex
// CAN_CONTINUE_FN. The token starts at START. Start matching from
// MATCH. Set *PP to the character following the token.
inline Token
gather_token(Token::Classification, bool (*can_continue_fn)(char),
gather_token(Token::Classification,
bool (Lex::*can_continue_fn)(char),
const char* start, const char* match, const char** pp);
// Build a token from a quoted string.
Token
gather_quoted_string(const char** pp);
// The file we are reading.
Input_file* input_file_;
// The token sequence we create.
Token_sequence tokens_;
// The string we are tokenizing.
const char* input_string_;
// The length of the string.
size_t input_length_;
// The current offset into the string.
const char* current_;
// The current lexing mode.
Mode mode_;
// The code to use for the first token. This is set to 0 after it
// is used.
int first_token_;
// The current token.
Token token_;
// The current line number.
int lineno_;
// The start of the current line in the buffer.
// The start of the current line in the string.
const char* linestart_;
};
@ -301,9 +330,9 @@ class Lex
// data we've already read, so that we read aligned buffers.
void
Lex::read_file(std::string* contents)
Lex::read_file(Input_file* input_file, std::string* contents)
{
off_t filesize = this->input_file_->file().filesize();
off_t filesize = input_file->file().filesize();
contents->clear();
contents->reserve(filesize);
@ -314,7 +343,7 @@ Lex::read_file(std::string* contents)
off_t get = BUFSIZ;
if (get > filesize - off)
get = filesize - off;
this->input_file_->file().read(off, get, buf);
input_file->file().read(off, get, buf);
contents->append(reinterpret_cast<char*>(&buf[0]), get);
off += get;
}
@ -326,8 +355,9 @@ Lex::read_file(std::string* contents)
// forward slash, backslash, and tilde. Tilde is the tricky case
// here; GNU ld also uses it as a bitwise not operator. It is only
// recognized as the operator if it is not immediately followed by
// some character which can appear in a symbol. That is, "~0" is a
// symbol name, and "~ 0" is an expression using bitwise not. We are
// some character which can appear in a symbol. That is, when we
// don't know that we are looking at an expression, "~0" is a file
// name, and "~ 0" is an expression using bitwise not. We are
// compatible.
inline bool
@ -345,11 +375,14 @@ Lex::can_start_name(char c, char c2)
case 'm': case 'n': case 'o': case 'q': case 'p': case 'r':
case 's': case 't': case 'u': case 'v': case 'w': case 'x':
case 'y': case 'z':
case '_': case '.': case '$': case '/': case '\\':
case '_': case '.': case '$':
return true;
case '/': case '\\':
return this->mode_ == LINKER_SCRIPT;
case '~':
return can_continue_name(c2);
return this->mode_ == LINKER_SCRIPT && can_continue_name(c2);
default:
return false;
@ -359,7 +392,8 @@ Lex::can_start_name(char c, char c2)
// Return whether C can continue a name which has already started.
// Subsequent characters in a name are the same as the leading
// characters, plus digits and "=+-:[],?*". So in general the linker
// script language requires spaces around operators.
// script language requires spaces around operators, unless we know
// that we are parsing an expression.
inline bool
Lex::can_continue_name(char c)
@ -376,14 +410,17 @@ Lex::can_continue_name(char c)
case 'm': case 'n': case 'o': case 'q': case 'p': case 'r':
case 's': case 't': case 'u': case 'v': case 'w': case 'x':
case 'y': case 'z':
case '_': case '.': case '$': case '/': case '\\':
case '~':
case '_': case '.': case '$':
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
case '=': case '+': case '-': case ':': case '[': case ']':
case ',': case '?': case '*':
return true;
case '/': case '\\': case '~':
case '=': case '+': case '-':
case ':': case '[': case ']':
case ',': case '?': case '*':
return this->mode_ == LINKER_SCRIPT;
default:
return false;
}
@ -393,8 +430,8 @@ Lex::can_continue_name(char c)
// of digits. The old linker accepts leading '$' for hex, and
// trailing HXBOD. Those are for MRI compatibility and we don't
// accept them. The old linker also accepts trailing MK for mega or
// kilo. Those are mentioned in the documentation, and we accept
// them.
// kilo. FIXME: Those are mentioned in the documentation, and we
// should accept them.
// Return whether C1 C2 C3 can start a hex number.
@ -402,7 +439,7 @@ inline bool
Lex::can_start_hex(char c1, char c2, char c3)
{
if (c1 == '0' && (c2 == 'x' || c2 == 'X'))
return Lex::can_continue_hex(c3);
return this->can_continue_hex(c3);
return false;
}
@ -615,17 +652,15 @@ Lex::skip_line_comment(const char** pp)
inline Token
Lex::gather_token(Token::Classification classification,
bool (*can_continue_fn)(char),
bool (Lex::*can_continue_fn)(char),
const char* start,
const char* match,
const char **pp)
{
while ((*can_continue_fn)(*match))
while ((this->*can_continue_fn)(*match))
++match;
*pp = match;
return this->make_token(classification,
std::string(start, match - start),
start);
return this->make_token(classification, start, match - start, start);
}
// Build a token from a quoted string.
@ -640,9 +675,7 @@ Lex::gather_quoted_string(const char** pp)
if (p[skip] != '"')
return this->make_invalid_token(start);
*pp = p + skip + 1;
return this->make_token(Token::TOKEN_STRING,
std::string(p, skip),
start);
return this->make_token(Token::TOKEN_QUOTED_STRING, p, skip, start);
}
// Return the next token at *PP. Update *PP. General guideline: we
@ -700,10 +733,10 @@ Lex::get_token(const char** pp)
}
// Check for a name.
if (Lex::can_start_name(p[0], p[1]))
if (this->can_start_name(p[0], p[1]))
return this->gather_token(Token::TOKEN_STRING,
Lex::can_continue_name,
p, p + 2, pp);
&Lex::can_continue_name,
p, p + 1, pp);
// We accept any arbitrary name in double quotes, as long as it
// does not cross a line boundary.
@ -715,14 +748,14 @@ Lex::get_token(const char** pp)
// Check for a number.
if (Lex::can_start_hex(p[0], p[1], p[2]))
if (this->can_start_hex(p[0], p[1], p[2]))
return this->gather_token(Token::TOKEN_INTEGER,
Lex::can_continue_hex,
&Lex::can_continue_hex,
p, p + 3, pp);
if (Lex::can_start_number(p[0]))
return this->gather_token(Token::TOKEN_INTEGER,
Lex::can_continue_number,
&Lex::can_continue_number,
p, p + 1, pp);
// Check for operators.
@ -752,34 +785,29 @@ Lex::get_token(const char** pp)
}
}
// Tokenize the file. Return the final token.
// Return the next token.
Token
Lex::tokenize()
const Token*
Lex::next_token()
{
std::string contents;
this->read_file(&contents);
const char* p = contents.c_str();
this->lineno_ = 1;
this->linestart_ = p;
while (true)
// The first token is special.
if (this->first_token_ != 0)
{
Token t(this->get_token(&p));
// Don't let an early null byte fool us into thinking that we've
// reached the end of the file.
if (t.is_eof()
&& static_cast<size_t>(p - contents.c_str()) < contents.length())
t = this->make_invalid_token(p);
if (t.is_invalid() || t.is_eof())
return t;
this->tokens_.push_back(t);
this->token_ = Token(this->first_token_, 0, 0);
this->first_token_ = 0;
return &this->token_;
}
this->token_ = this->get_token(&this->current_);
// Don't let an early null byte fool us into thinking that we've
// reached the end of the file.
if (this->token_.is_eof()
&& (static_cast<size_t>(this->current_ - this->input_string_)
< this->input_length_))
this->token_ = this->make_invalid_token(this->current_);
return &this->token_;
}
// A trivial task which waits for THIS_BLOCKER to be clear and then
@ -823,6 +851,79 @@ class Script_unblock : public Task
Task_token* next_blocker_;
};
// Class Script_options.
Script_options::Script_options()
: entry_(), symbol_assignments_()
{
}
// Add any symbols we are defining to the symbol table.
void
Script_options::add_symbols_to_table(Symbol_table* symtab,
const Target* target)
{
for (Symbol_assignments::iterator p = this->symbol_assignments_.begin();
p != this->symbol_assignments_.end();
++p)
{
elfcpp::STV vis = p->hidden ? elfcpp::STV_HIDDEN : elfcpp::STV_DEFAULT;
p->sym = symtab->define_as_constant(target,
p->name.c_str(),
NULL, // version
0, // value
0, // size
elfcpp::STT_NOTYPE,
elfcpp::STB_GLOBAL,
vis,
0, // nonvis
p->provide);
}
}
// Finalize symbol values.
void
Script_options::finalize_symbols(Symbol_table* symtab, const Layout* layout)
{
if (parameters->get_size() == 32)
{
#if defined(HAVE_TARGET_32_LITTLE) || defined(HAVE_TARGET_32_BIG)
this->sized_finalize_symbols<32>(symtab, layout);
#else
gold_unreachable();
#endif
}
else if (parameters->get_size() == 64)
{
#if defined(HAVE_TARGET_64_LITTLE) || defined(HAVE_TARGET_64_BIG)
this->sized_finalize_symbols<64>(symtab, layout);
#else
gold_unreachable();
#endif
}
else
gold_unreachable();
}
template<int size>
void
Script_options::sized_finalize_symbols(Symbol_table* symtab,
const Layout* layout)
{
for (Symbol_assignments::iterator p = this->symbol_assignments_.begin();
p != this->symbol_assignments_.end();
++p)
{
if (p->sym != NULL)
{
Sized_symbol<size>* ssym = symtab->get_sized_symbol<size>(p->sym);
ssym->set_value(p->value->eval(symtab, layout));
}
}
}
// This class holds data passed through the parser to the lexer and to
// the parser support functions. This avoids global variables. We
// can't use global variables because we need not be called by a
@ -835,12 +936,12 @@ class Parser_closure
const Position_dependent_options& posdep_options,
bool in_group, bool is_in_sysroot,
Command_line* command_line,
Layout* layout,
const Lex::Token_sequence* tokens)
Script_options* script_options,
Lex* lex)
: filename_(filename), posdep_options_(posdep_options),
in_group_(in_group), is_in_sysroot_(is_in_sysroot),
command_line_(command_line), layout_(layout), tokens_(tokens),
next_token_index_(0), inputs_(NULL)
command_line_(command_line), script_options_(script_options),
lex_(lex), lineno_(0), charpos_(0), lex_mode_stack_(), inputs_(NULL)
{ }
// Return the file name.
@ -868,36 +969,52 @@ class Parser_closure
// Returns the Command_line structure passed in at constructor time.
// This value may be NULL. The caller may modify this, which modifies
// the passed-in Command_line object (not a copy).
Command_line* command_line()
Command_line*
command_line()
{ return this->command_line_; }
// Return the Layout structure passed in at constructor time. This
// value may be NULL.
Layout* layout()
{ return this->layout_; }
// Whether we are at the end of the token list.
bool
at_eof() const
{ return this->next_token_index_ >= this->tokens_->size(); }
// Return the options which may be set by a script.
Script_options*
script_options()
{ return this->script_options_; }
// Return the next token, and advance.
const Token*
next_token()
{
const Token* ret = &(*this->tokens_)[this->next_token_index_];
++this->next_token_index_;
return ret;
const Token* token = this->lex_->next_token();
this->lineno_ = token->lineno();
this->charpos_ = token->charpos();
return token;
}
// Return the previous token.
const Token*
last_token() const
// Set a new lexer mode, pushing the current one.
void
push_lex_mode(Lex::Mode mode)
{
gold_assert(this->next_token_index_ > 0);
return &(*this->tokens_)[this->next_token_index_ - 1];
this->lex_mode_stack_.push_back(this->lex_->mode());
this->lex_->set_mode(mode);
}
// Pop the lexer mode.
void
pop_lex_mode()
{
gold_assert(!this->lex_mode_stack_.empty());
this->lex_->set_mode(this->lex_mode_stack_.back());
this->lex_mode_stack_.pop_back();
}
// Return the line number of the last token.
int
lineno() const
{ return this->lineno_; }
// Return the character position in the line of the last token.
int
charpos() const
{ return this->charpos_; }
// Return the list of input files, creating it if necessary. This
// is a space leak--we never free the INPUTS_ pointer.
Input_arguments*
@ -924,13 +1041,16 @@ class Parser_closure
bool is_in_sysroot_;
// May be NULL if the user chooses not to pass one in.
Command_line* command_line_;
// May be NULL if the user chooses not to pass one in.
Layout* layout_;
// The tokens to be returned by the lexer.
const Lex::Token_sequence* tokens_;
// The index of the next token to return.
unsigned int next_token_index_;
// Options which may be set from any linker script.
Script_options* script_options_;
// The lexer.
Lex* lex_;
// The line number of the last token returned by next_token.
int lineno_;
// The column number of the last token returned by next_token.
int charpos_;
// A stack of lexer modes.
std::vector<Lex::Mode> lex_mode_stack_;
// New input files found to add to the link.
Input_arguments* inputs_;
};
@ -948,17 +1068,18 @@ read_input_script(Workqueue* workqueue, const General_options& options,
Input_file* input_file, const unsigned char*, off_t,
Task_token* this_blocker, Task_token* next_blocker)
{
Lex lex(input_file);
if (lex.tokenize().is_invalid())
return false;
std::string input_string;
Lex::read_file(input_file, &input_string);
Lex lex(input_string.c_str(), input_string.length(), PARSING_LINKER_SCRIPT);
Parser_closure closure(input_file->filename().c_str(),
input_argument->file().options(),
input_group != NULL,
input_file->is_in_sysroot(),
NULL,
layout,
&lex.tokens());
layout->script_options(),
&lex);
if (yyparse(&closure) != 0)
return false;
@ -1019,21 +1140,18 @@ read_commandline_script(const char* filename, Command_line* cmdline)
if (!input_file.open(cmdline->options(), dirsearch, task))
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(task);
return false;
}
std::string input_string;
Lex::read_file(&input_file, &input_string);
Lex lex(input_string.c_str(), input_string.length(), PARSING_LINKER_SCRIPT);
Parser_closure closure(filename,
cmdline->position_dependent_options(),
false,
input_file.is_in_sysroot(),
cmdline,
NULL,
&lex.tokens());
cmdline->script_options(),
&lex);
if (yyparse(&closure) != 0)
{
input_file.file().unlock(task);
@ -1047,6 +1165,29 @@ read_commandline_script(const char* filename, Command_line* cmdline)
return true;
}
// Implement the --defsym option on the command line. Return true if
// all is well.
bool
Script_options::define_symbol(const char* definition)
{
Lex lex(definition, strlen(definition), PARSING_DEFSYM);
lex.set_mode(Lex::EXPRESSION);
// Dummy value.
Position_dependent_options posdep_options;
Parser_closure closure("command line", posdep_options, false, false, NULL,
this, &lex);
if (yyparse(&closure) != 0)
return false;
gold_assert(!closure.saw_inputs());
return true;
}
// Manage mapping from keywords to the codes expected by the bison
// parser.
@ -1065,7 +1206,7 @@ class Keyword_to_parsecode
// Return the parsecode corresponding KEYWORD, or 0 if it is not a
// keyword.
static int
keyword_to_parsecode(const char* keyword);
keyword_to_parsecode(const char* keyword, size_t len);
private:
// The array of all keywords.
@ -1085,6 +1226,7 @@ Keyword_to_parsecode::keyword_parsecodes_[] =
{ "ABSOLUTE", ABSOLUTE },
{ "ADDR", ADDR },
{ "ALIGN", ALIGN_K },
{ "ALIGNOF", ALIGNOF },
{ "ASSERT", ASSERT_K },
{ "AS_NEEDED", AS_NEEDED },
{ "AT", AT },
@ -1170,21 +1312,35 @@ const int Keyword_to_parsecode::keyword_count =
extern "C"
{
struct Ktt_key
{
const char* str;
size_t len;
};
static int
ktt_compare(const void* keyv, const void* kttv)
{
const char* key = static_cast<const char*>(keyv);
const Ktt_key* key = static_cast<const Ktt_key*>(keyv);
const Keyword_to_parsecode::Keyword_parsecode* ktt =
static_cast<const Keyword_to_parsecode::Keyword_parsecode*>(kttv);
return strcmp(key, ktt->keyword);
int i = strncmp(key->str, ktt->keyword, key->len);
if (i != 0)
return i;
if (ktt->keyword[key->len] != '\0')
return -1;
return 0;
}
} // End extern "C".
int
Keyword_to_parsecode::keyword_to_parsecode(const char* keyword)
Keyword_to_parsecode::keyword_to_parsecode(const char* keyword, size_t len)
{
void* kttv = bsearch(keyword,
Ktt_key key;
key.str = keyword;
key.len = len;
void* kttv = bsearch(&key,
Keyword_to_parsecode::keyword_parsecodes_,
Keyword_to_parsecode::keyword_count,
sizeof(Keyword_to_parsecode::keyword_parsecodes_[0]),
@ -1209,29 +1365,36 @@ extern "C" int
yylex(YYSTYPE* lvalp, void* closurev)
{
Parser_closure* closure = static_cast<Parser_closure*>(closurev);
if (closure->at_eof())
return 0;
const Token* token = closure->next_token();
switch (token->classification())
{
default:
case Token::TOKEN_INVALID:
case Token::TOKEN_EOF:
gold_unreachable();
case Token::TOKEN_INVALID:
yyerror(closurev, "invalid character");
return 0;
case Token::TOKEN_EOF:
return 0;
case Token::TOKEN_STRING:
{
const char* str = token->string_value().c_str();
int parsecode = Keyword_to_parsecode::keyword_to_parsecode(str);
// This is either a keyword or a STRING.
size_t len;
const char* str = token->string_value(&len);
int parsecode = Keyword_to_parsecode::keyword_to_parsecode(str, len);
if (parsecode != 0)
return parsecode;
lvalp->string = str;
lvalp->string.value = str;
lvalp->string.length = len;
return STRING;
}
case Token::TOKEN_QUOTED_STRING:
lvalp->string.value = token->string_value(&lvalp->string.length);
return STRING;
case Token::TOKEN_OPERATOR:
return token->operator_value();
@ -1247,16 +1410,14 @@ extern "C" void
yyerror(void* closurev, const char* message)
{
Parser_closure* closure = static_cast<Parser_closure*>(closurev);
const Token* token = closure->last_token();
gold_error(_("%s:%d:%d: %s"), closure->filename(), token->lineno(),
token->charpos(), message);
gold_error(_("%s:%d:%d: %s"), closure->filename(), closure->lineno(),
closure->charpos(), message);
}
// Called by the bison parser to add a file to the link.
extern "C" void
script_add_file(void* closurev, const char* name)
script_add_file(void* closurev, const char* name, size_t length)
{
Parser_closure* closure = static_cast<Parser_closure*>(closurev);
@ -1264,17 +1425,16 @@ script_add_file(void* closurev, const char* name)
// sysroot, then we want to prepend the sysroot to the file name.
// For example, this is how we handle a cross link to the x86_64
// libc.so, which refers to /lib/libc.so.6.
std::string name_string;
std::string name_string(name, length);
const char* extra_search_path = ".";
std::string script_directory;
if (IS_ABSOLUTE_PATH (name))
if (IS_ABSOLUTE_PATH(name_string.c_str()))
{
if (closure->is_in_sysroot())
{
const std::string& sysroot(parameters->sysroot());
gold_assert(!sysroot.empty());
name_string = sysroot + name;
name = name_string.c_str();
name_string = sysroot + name_string;
}
}
else
@ -1290,7 +1450,7 @@ script_add_file(void* closurev, const char* name)
}
}
Input_file_argument file(name, false, extra_search_path,
Input_file_argument file(name_string.c_str(), false, extra_search_path,
closure->position_dependent_options());
closure->inputs()->add_file(file);
}
@ -1345,19 +1505,29 @@ script_end_as_needed(void* closurev)
// Called by the bison parser to set the entry symbol.
extern "C" void
script_set_entry(void* closurev, const char* entry)
script_set_entry(void* closurev, const char* entry, size_t length)
{
Parser_closure* closure = static_cast<Parser_closure*>(closurev);
if (closure->command_line() != NULL)
closure->command_line()->set_entry(entry);
else
closure->layout()->set_entry(entry);
closure->script_options()->set_entry(entry, length);
}
// Called by the bison parser to define a symbol.
extern "C" void
script_set_symbol(void* closurev, const char* name, size_t length,
Expression* value, int providei, int hiddeni)
{
Parser_closure* closure = static_cast<Parser_closure*>(closurev);
const bool provide = providei != 0;
const bool hidden = hiddeni != 0;
closure->script_options()->add_symbol_assignment(name, length, value,
provide, hidden);
}
// Called by the bison parser to parse an OPTION.
extern "C" void
script_parse_option(void* closurev, const char* option)
script_parse_option(void* closurev, const char* option, size_t length)
{
Parser_closure* closure = static_cast<Parser_closure*>(closurev);
// We treat the option as a single command-line option, even if
@ -1366,16 +1536,36 @@ script_parse_option(void* closurev, const char* option)
{
// There are some options that we could handle here--e.g.,
// -lLIBRARY. Should we bother?
gold_warning(_("%s: ignoring command OPTION; OPTION is only valid"
gold_warning(_("%s:%d:%d: ignoring command OPTION; OPTION is only valid"
" for scripts specified via -T/--script"),
closure->filename());
closure->filename(), closure->lineno(), closure->charpos());
}
else
{
bool past_a_double_dash_option = false;
char* mutable_option = strdup(option);
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);
free(mutable_option);
}
}
/* Called by the bison parser to push the lexer into expression
mode. */
extern void
script_push_lex_into_expression_mode(void* closurev)
{
Parser_closure* closure = static_cast<Parser_closure*>(closurev);
closure->push_lex_mode(Lex::EXPRESSION);
}
/* Called by the bison parser to pop the lexer mode. */
extern void
script_pop_lex_mode(void* closurev)
{
Parser_closure* closure = static_cast<Parser_closure*>(closurev);
closure->pop_lex_mode();
}

View File

@ -1,6 +1,6 @@
// script.h -- handle linker scripts for gold -*- C++ -*-
// Copyright 2006, 2007 Free Software Foundation, Inc.
// Copyright 2006, 2007, 2008 Free Software Foundation, Inc.
// Written by Ian Lance Taylor <iant@google.com>.
// This file is part of gold.
@ -30,6 +30,8 @@
#ifndef GOLD_SCRIPT_H
#define GOLD_SCRIPT_H
#include <vector>
namespace gold
{
@ -41,9 +43,125 @@ class Input_argument;
class Input_objects;
class Input_group;
class Input_file;
class Target;
class Task_token;
class Workqueue;
// This class represents an expression in a linker script.
class Expression
{
protected:
// These should only be created by child classes.
Expression()
{ }
public:
virtual ~Expression()
{ }
// Return the value of the expression.
uint64_t
eval(const Symbol_table*, const Layout*);
protected:
struct Expression_eval_info;
public:
// Compute the value of the expression (implemented by child class).
// This is public rather than protected because it is called
// directly by children of Expression on other Expression objects.
virtual uint64_t
value(const Expression_eval_info*) = 0;
private:
// May not be copied.
Expression(const Expression&);
Expression& operator=(const Expression&);
};
// We can read a linker script in two different contexts: when
// initially parsing the command line, and when we find an input file
// which is actually a linker script. Also some of the data which can
// be set by a linker script can also be set via command line options
// like -e and --defsym. This means that we have a type of data which
// can be set both during command line option parsing and while
// reading input files. We store that data in an instance of this
// object. We will keep pointers to that instance in both the
// Command_line and Layout objects.
class Script_options
{
public:
Script_options();
// The entry address.
const char*
entry() const
{ return this->entry_.empty() ? NULL : this->entry_.c_str(); }
// Set the entry address.
void
set_entry(const char* entry, size_t length)
{ this->entry_.assign(entry, length); }
// Add a symbol to be defined. These are for symbol definitions
// which appear outside of a SECTIONS clause.
void
add_symbol_assignment(const char* name, size_t length, Expression* value,
bool provided, bool hidden)
{
this->symbol_assignments_.push_back(Symbol_assignment(name, length, value,
provided, hidden));
}
// Define a symbol from the command line.
bool
define_symbol(const char* definition);
// Add all symbol definitions to the symbol table.
void
add_symbols_to_table(Symbol_table*, const Target*);
// Finalize the symbol values.
void
finalize_symbols(Symbol_table*, const Layout*);
private:
// We keep a list of symbol assignments.
struct Symbol_assignment
{
// Symbol name.
std::string name;
// Expression to assign to symbol.
Expression* value;
// Whether the assignment should be provided (only set if there is
// an undefined reference to the symbol.
bool provide;
// Whether the assignment should be hidden.
bool hidden;
// The entry in the symbol table.
Symbol* sym;
Symbol_assignment(const char* namea, size_t lengtha, Expression* valuea,
bool providea, bool hiddena)
: name(namea, lengtha), value(valuea), provide(providea),
hidden(hiddena), sym(NULL)
{ }
};
typedef std::vector<Symbol_assignment> Symbol_assignments;
template<int size>
void
sized_finalize_symbols(Symbol_table*, const Layout*);
// The entry address. This will be empty if not set.
std::string entry_;
// Symbols to set.
Symbol_assignments symbol_assignments_;
};
// 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
// already read BYTES of data into P. Return true if the file was

View File

@ -1,6 +1,6 @@
// symtab.cc -- the gold symbol table
// Copyright 2006, 2007 Free Software Foundation, Inc.
// Copyright 2006, 2007, 2008 Free Software Foundation, Inc.
// Written by Ian Lance Taylor <iant@google.com>.
// This file is part of gold.
@ -1056,11 +1056,13 @@ Symbol_table::do_define_in_output_data(
sym->init(name, od, value, symsize, type, binding, visibility, nonvis,
offset_is_from_end);
if (oldsym != NULL
&& Symbol_table::should_override_with_special(oldsym))
this->override_with_special(oldsym, sym);
if (oldsym == NULL)
return sym;
return sym;
if (Symbol_table::should_override_with_special(oldsym))
this->override_with_special(oldsym, sym);
delete sym;
return oldsym;
}
// Define a symbol based on an Output_segment.
@ -1150,11 +1152,13 @@ Symbol_table::do_define_in_output_segment(
sym->init(name, os, value, symsize, type, binding, visibility, nonvis,
offset_base);
if (oldsym != NULL
&& Symbol_table::should_override_with_special(oldsym))
this->override_with_special(oldsym, sym);
if (oldsym == NULL)
return sym;
return sym;
if (Symbol_table::should_override_with_special(oldsym))
this->override_with_special(oldsym, sym);
delete sym;
return oldsym;
}
// Define a special symbol with a constant value. It is a multiple
@ -1237,11 +1241,13 @@ Symbol_table::do_define_as_constant(
gold_assert(version == NULL || oldsym != NULL);
sym->init(name, value, symsize, type, binding, visibility, nonvis);
if (oldsym != NULL
&& Symbol_table::should_override_with_special(oldsym))
this->override_with_special(oldsym, sym);
if (oldsym == NULL)
return sym;
return sym;
if (Symbol_table::should_override_with_special(oldsym))
this->override_with_special(oldsym, sym);
delete sym;
return oldsym;
}
// Define a set of symbols in output sections.

View File

@ -503,5 +503,10 @@ ver_test_3.o: ver_test_3.cc
ver_test_4.o: ver_test_4.cc
$(CXXCOMPILE) -c -fpic -o $@ $<
check_PROGRAMS += script_test_1
script_test_1_SOURCES = script_test_1.cc
script_test_1_DEPENDENCIES = gcctestdir/ld script_test_1.t
script_test_1_LDFLAGS = -Bgcctestdir/ -Wl,-R,. -T $(srcdir)/script_test_1.t
endif GCC
endif NATIVE_LINKER

View File

@ -171,7 +171,14 @@ check_PROGRAMS = object_unittest$(EXEEXT) $(am__EXEEXT_1) \
@GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_10 = flagstest_compress_debug_sections \
@GCC_TRUE@@NATIVE_LINKER_TRUE@ flagstest_o_specialfile \
@GCC_TRUE@@NATIVE_LINKER_TRUE@ flagstest_o_specialfile_and_compress_debug_sections \
@GCC_TRUE@@NATIVE_LINKER_TRUE@ ver_test
@GCC_TRUE@@NATIVE_LINKER_TRUE@ ver_test script_test_1
@GCC_FALSE@script_test_1_DEPENDENCIES = libgoldtest.a ../libgold.a \
@GCC_FALSE@ ../../libiberty/libiberty.a $(am__DEPENDENCIES_1) \
@GCC_FALSE@ $(am__DEPENDENCIES_1)
@NATIVE_LINKER_FALSE@script_test_1_DEPENDENCIES = libgoldtest.a \
@NATIVE_LINKER_FALSE@ ../libgold.a ../../libiberty/libiberty.a \
@NATIVE_LINKER_FALSE@ $(am__DEPENDENCIES_1) \
@NATIVE_LINKER_FALSE@ $(am__DEPENDENCIES_1)
subdir = testsuite
DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
@ -233,7 +240,8 @@ libgoldtest_a_OBJECTS = $(am_libgoldtest_a_OBJECTS)
@GCC_TRUE@@NATIVE_LINKER_TRUE@am__EXEEXT_7 = flagstest_compress_debug_sections$(EXEEXT) \
@GCC_TRUE@@NATIVE_LINKER_TRUE@ flagstest_o_specialfile$(EXEEXT) \
@GCC_TRUE@@NATIVE_LINKER_TRUE@ flagstest_o_specialfile_and_compress_debug_sections$(EXEEXT) \
@GCC_TRUE@@NATIVE_LINKER_TRUE@ ver_test$(EXEEXT)
@GCC_TRUE@@NATIVE_LINKER_TRUE@ ver_test$(EXEEXT) \
@GCC_TRUE@@NATIVE_LINKER_TRUE@ script_test_1$(EXEEXT)
basic_pic_test_SOURCES = basic_pic_test.c
basic_pic_test_OBJECTS = basic_pic_test.$(OBJEXT)
basic_pic_test_LDADD = $(LDADD)
@ -349,6 +357,11 @@ object_unittest_LDADD = $(LDADD)
object_unittest_DEPENDENCIES = libgoldtest.a ../libgold.a \
../../libiberty/libiberty.a $(am__DEPENDENCIES_1) \
$(am__DEPENDENCIES_1)
am__script_test_1_SOURCES_DIST = script_test_1.cc
@GCC_TRUE@@NATIVE_LINKER_TRUE@am_script_test_1_OBJECTS = \
@GCC_TRUE@@NATIVE_LINKER_TRUE@ script_test_1.$(OBJEXT)
script_test_1_OBJECTS = $(am_script_test_1_OBJECTS)
script_test_1_LDADD = $(LDADD)
am__tls_pic_test_SOURCES_DIST = tls_test_main.cc
@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@am_tls_pic_test_OBJECTS = tls_test_main.$(OBJEXT)
tls_pic_test_OBJECTS = $(am_tls_pic_test_OBJECTS)
@ -503,8 +516,8 @@ SOURCES = $(libgoldtest_a_SOURCES) basic_pic_test.c \
$(exception_static_test_SOURCES) $(exception_test_SOURCES) \
flagstest_compress_debug_sections.c flagstest_o_specialfile.c \
flagstest_o_specialfile_and_compress_debug_sections.c \
$(object_unittest_SOURCES) $(tls_pic_test_SOURCES) \
$(tls_shared_ie_test_SOURCES) \
$(object_unittest_SOURCES) $(script_test_1_SOURCES) \
$(tls_pic_test_SOURCES) $(tls_shared_ie_test_SOURCES) \
$(tls_shared_nonpic_test_SOURCES) $(tls_shared_test_SOURCES) \
$(tls_static_pic_test_SOURCES) $(tls_static_test_SOURCES) \
$(tls_test_SOURCES) $(two_file_pic_test_SOURCES) \
@ -535,7 +548,8 @@ DIST_SOURCES = $(libgoldtest_a_SOURCES) basic_pic_test.c \
$(am__exception_test_SOURCES_DIST) \
flagstest_compress_debug_sections.c flagstest_o_specialfile.c \
flagstest_o_specialfile_and_compress_debug_sections.c \
$(object_unittest_SOURCES) $(am__tls_pic_test_SOURCES_DIST) \
$(object_unittest_SOURCES) $(am__script_test_1_SOURCES_DIST) \
$(am__tls_pic_test_SOURCES_DIST) \
$(am__tls_shared_ie_test_SOURCES_DIST) \
$(am__tls_shared_nonpic_test_SOURCES_DIST) \
$(am__tls_shared_test_SOURCES_DIST) \
@ -905,6 +919,9 @@ object_unittest_SOURCES = object_unittest.cc
@GCC_TRUE@@NATIVE_LINKER_TRUE@ver_test_DEPENDENCIES = gcctestdir/ld ver_test_1.so ver_test_2.so ver_test_4.so
@GCC_TRUE@@NATIVE_LINKER_TRUE@ver_test_LDFLAGS = -Bgcctestdir/ -Wl,-R,.
@GCC_TRUE@@NATIVE_LINKER_TRUE@ver_test_LDADD = ver_test_1.so ver_test_2.so ver_test_4.so
@GCC_TRUE@@NATIVE_LINKER_TRUE@script_test_1_SOURCES = script_test_1.cc
@GCC_TRUE@@NATIVE_LINKER_TRUE@script_test_1_DEPENDENCIES = gcctestdir/ld script_test_1.t
@GCC_TRUE@@NATIVE_LINKER_TRUE@script_test_1_LDFLAGS = -Bgcctestdir/ -Wl,-R,. -T $(srcdir)/script_test_1.t
all: all-am
.SUFFIXES:
@ -1020,6 +1037,9 @@ exception_test$(EXEEXT): $(exception_test_OBJECTS) $(exception_test_DEPENDENCIES
object_unittest$(EXEEXT): $(object_unittest_OBJECTS) $(object_unittest_DEPENDENCIES)
@rm -f object_unittest$(EXEEXT)
$(CXXLINK) $(object_unittest_LDFLAGS) $(object_unittest_OBJECTS) $(object_unittest_LDADD) $(LIBS)
script_test_1$(EXEEXT): $(script_test_1_OBJECTS) $(script_test_1_DEPENDENCIES)
@rm -f script_test_1$(EXEEXT)
$(CXXLINK) $(script_test_1_LDFLAGS) $(script_test_1_OBJECTS) $(script_test_1_LDADD) $(LIBS)
tls_pic_test$(EXEEXT): $(tls_pic_test_OBJECTS) $(tls_pic_test_DEPENDENCIES)
@rm -f tls_pic_test$(EXEEXT)
$(CXXLINK) $(tls_pic_test_LDFLAGS) $(tls_pic_test_OBJECTS) $(tls_pic_test_LDADD) $(LIBS)
@ -1111,6 +1131,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/flagstest_o_specialfile.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/flagstest_o_specialfile_and_compress_debug_sections.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/object_unittest.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/script_test_1.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/testfile.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/testmain.Po@am__quote@

View File

@ -0,0 +1,47 @@
// script_test_1.cc -- linker script test 1 for gold -*- C++ -*-
// Copyright 2008 Free Software Foundation, Inc.
// Written by Ian Lance Taylor <iant@google.com>.
// This file is part of gold.
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
// MA 02110-1301, USA.
// A test for a linker script which sets symbols to values.
#include <cassert>
#include <cstddef>
#include <stdint.h>
extern char a, b, c, d, e, f, g;
int sym = 3;
int common_sym;
int
main(int, char**)
{
assert(reinterpret_cast<intptr_t>(&a) == 123);
assert(reinterpret_cast<intptr_t>(&b) == reinterpret_cast<intptr_t>(&a) * 2);
assert(reinterpret_cast<intptr_t>(&c)
== reinterpret_cast<intptr_t>(&b) + 3 * 6);
assert(reinterpret_cast<intptr_t>(&d)
== (reinterpret_cast<intptr_t>(&b) + 3) * 6);
assert(reinterpret_cast<int*>(&e) == &sym);
assert(reinterpret_cast<intptr_t>(&f)
== reinterpret_cast<intptr_t>(&sym) + 10);
assert(reinterpret_cast<int*>(&g) == &common_sym);
return 0;
}

View File

@ -0,0 +1,29 @@
/* script_test_1.t -- linker script test 1 for gold
Copyright 2008 Free Software Foundation, Inc.
Written by Ian Lance Taylor <iant@google.com>.
This file is part of gold.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
MA 02110-1301, USA. */
a = 123;
b = a * 2;
c = b + 3 * 6;
d = (b + 3) * 6;
e = sym;
f = sym + 10;
g = common_sym;

View File

@ -1,6 +1,6 @@
/* yyscript.y -- linker script grammer for gold. */
/* Copyright 2006, 2007 Free Software Foundation, Inc.
/* Copyright 2006, 2007, 2008 Free Software Foundation, Inc.
Written by Ian Lance Taylor <iant@google.com>.
This file is part of gold.
@ -49,8 +49,12 @@
/* The values associated with tokens. */
%union {
const char* string;
int64_t integer;
/* A string. */
struct Parser_string string;
/* A number. */
uint64_t integer;
/* An expression. */
Expression_ptr expr;
}
/* Operators, including a precedence table for expressions. */
@ -68,6 +72,9 @@
%left '+' '-'
%left '*' '/' '%'
/* A fake operator used to indicate unary operator precedence. */
%right UNARY
/* Constants. */
%token <string> STRING
@ -82,6 +89,7 @@
%token ABSOLUTE
%token ADDR
%token ALIGN_K /* ALIGN */
%token ALIGNOF
%token ASSERT_K /* ASSERT */
%token AS_NEEDED
%token AT
@ -158,11 +166,31 @@
%token OPTION
/* Special tokens used to tell the grammar what type of tokens we are
parsing. The token stream always begins with one of these tokens.
We do this because version scripts can appear embedded within
linker scripts, and because --defsym uses the expression
parser. */
%token PARSING_LINKER_SCRIPT
%token PARSING_VERSION_SCRIPT
%token PARSING_DEFSYM
/* Non-terminal types, where needed. */
%type <expr> parse_exp exp
%%
/* Read the special token to see what to read next. */
top:
PARSING_LINKER_SCRIPT linker_script
| PARSING_VERSION_SCRIPT version_script
| PARSING_DEFSYM defsym_expr
;
/* A file contains a list of commands. */
file_list:
file_list file_cmd
linker_script:
linker_script file_cmd
| /* empty */
;
@ -173,7 +201,7 @@ file_cmd:
'(' input_list ')'
{ script_end_group(closure); }
| OPTION '(' STRING ')'
{ script_parse_option(closure, $3); }
{ script_parse_option(closure, $3.value, $3.length); }
| file_or_sections_cmd
| ignore_cmd
;
@ -197,7 +225,7 @@ input_list:
/* An input file name. */
input_list_element:
STRING
{ script_add_file(closure, $1); }
{ script_add_file(closure, $1.value, $1.length); }
| AS_NEEDED
{ script_start_as_needed(closure); }
'(' input_list ')'
@ -208,7 +236,191 @@ input_list_element:
within a SECTIONS block. */
file_or_sections_cmd:
ENTRY '(' STRING ')'
{ script_set_entry(closure, $3); }
{ script_set_entry(closure, $3.value, $3.length); }
| assignment end
;
/* Set a symbol to a value. */
assignment:
STRING '=' parse_exp
{ script_set_symbol(closure, $1.value, $1.length, $3, 0, 0); }
| STRING PLUSEQ parse_exp
{
Expression_ptr s = script_exp_string($1.value, $1.length);
Expression_ptr e = script_exp_binary_add(s, $3);
script_set_symbol(closure, $1.value, $1.length, e, 0, 0);
}
| STRING MINUSEQ parse_exp
{
Expression_ptr s = script_exp_string($1.value, $1.length);
Expression_ptr e = script_exp_binary_sub(s, $3);
script_set_symbol(closure, $1.value, $1.length, e, 0, 0);
}
| STRING MULTEQ parse_exp
{
Expression_ptr s = script_exp_string($1.value, $1.length);
Expression_ptr e = script_exp_binary_mult(s, $3);
script_set_symbol(closure, $1.value, $1.length, e, 0, 0);
}
| STRING DIVEQ parse_exp
{
Expression_ptr s = script_exp_string($1.value, $1.length);
Expression_ptr e = script_exp_binary_div(s, $3);
script_set_symbol(closure, $1.value, $1.length, e, 0, 0);
}
| STRING LSHIFTEQ parse_exp
{
Expression_ptr s = script_exp_string($1.value, $1.length);
Expression_ptr e = script_exp_binary_lshift(s, $3);
script_set_symbol(closure, $1.value, $1.length, e, 0, 0);
}
| STRING RSHIFTEQ parse_exp
{
Expression_ptr s = script_exp_string($1.value, $1.length);
Expression_ptr e = script_exp_binary_rshift(s, $3);
script_set_symbol(closure, $1.value, $1.length, e, 0, 0);
}
| STRING ANDEQ parse_exp
{
Expression_ptr s = script_exp_string($1.value, $1.length);
Expression_ptr e = script_exp_binary_bitwise_and(s, $3);
script_set_symbol(closure, $1.value, $1.length, e, 0, 0);
}
| STRING OREQ parse_exp
{
Expression_ptr s = script_exp_string($1.value, $1.length);
Expression_ptr e = script_exp_binary_bitwise_or(s, $3);
script_set_symbol(closure, $1.value, $1.length, e, 0, 0);
}
| PROVIDE '(' STRING '=' parse_exp ')'
{ script_set_symbol(closure, $3.value, $3.length, $5, 1, 0); }
| PROVIDE_HIDDEN '(' STRING '=' parse_exp ')'
{ script_set_symbol(closure, $3.value, $3.length, $5, 1, 1); }
;
/* Parse an expression, putting the lexer into the right mode. */
parse_exp:
{ script_push_lex_into_expression_mode(closure); }
exp
{
script_pop_lex_mode(closure);
$$ = $2;
}
;
/* An expression. */
exp:
'(' exp ')'
{ $$ = $2; }
| '-' exp %prec UNARY
{ $$ = script_exp_unary_minus($2); }
| '!' exp %prec UNARY
{ $$ = script_exp_unary_logical_not($2); }
| '~' exp %prec UNARY
{ $$ = script_exp_unary_bitwise_not($2); }
| '+' exp %prec UNARY
{ $$ = $2; }
| exp '*' exp
{ $$ = script_exp_binary_mult($1, $3); }
| exp '/' exp
{ $$ = script_exp_binary_div($1, $3); }
| exp '%' exp
{ $$ = script_exp_binary_mod($1, $3); }
| exp '+' exp
{ $$ = script_exp_binary_add($1, $3); }
| exp '-' exp
{ $$ = script_exp_binary_sub($1, $3); }
| exp LSHIFT exp
{ $$ = script_exp_binary_lshift($1, $3); }
| exp RSHIFT exp
{ $$ = script_exp_binary_rshift($1, $3); }
| exp EQ exp
{ $$ = script_exp_binary_eq($1, $3); }
| exp NE exp
{ $$ = script_exp_binary_ne($1, $3); }
| exp LE exp
{ $$ = script_exp_binary_le($1, $3); }
| exp GE exp
{ $$ = script_exp_binary_ge($1, $3); }
| exp '<' exp
{ $$ = script_exp_binary_lt($1, $3); }
| exp '>' exp
{ $$ = script_exp_binary_gt($1, $3); }
| exp '&' exp
{ $$ = script_exp_binary_bitwise_and($1, $3); }
| exp '^' exp
{ $$ = script_exp_binary_bitwise_xor($1, $3); }
| exp '|' exp
{ $$ = script_exp_binary_bitwise_or($1, $3); }
| exp ANDAND exp
{ $$ = script_exp_binary_logical_and($1, $3); }
| exp OROR exp
{ $$ = script_exp_binary_logical_or($1, $3); }
| exp '?' exp ':' exp
{ $$ = script_exp_trinary_cond($1, $3, $5); }
| INTEGER
{ $$ = script_exp_integer($1); }
| STRING
{ $$ = script_exp_string($1.value, $1.length); }
| MAX_K '(' exp ',' exp ')'
{ $$ = script_exp_function_max($3, $5); }
| MIN_K '(' exp ',' exp ')'
{ $$ = script_exp_function_min($3, $5); }
| DEFINED '(' STRING ')'
{ $$ = script_exp_function_defined($3.value, $3.length); }
| SIZEOF_HEADERS
{ $$ = script_exp_function_sizeof_headers(); }
| ALIGNOF '(' STRING ')'
{ $$ = script_exp_function_alignof($3.value, $3.length); }
| SIZEOF '(' STRING ')'
{ $$ = script_exp_function_sizeof($3.value, $3.length); }
| ADDR '(' STRING ')'
{ $$ = script_exp_function_addr($3.value, $3.length); }
| LOADADDR '(' STRING ')'
{ $$ = script_exp_function_loadaddr($3.value, $3.length); }
| ORIGIN '(' STRING ')'
{ $$ = script_exp_function_origin($3.value, $3.length); }
| LENGTH '(' STRING ')'
{ $$ = script_exp_function_length($3.value, $3.length); }
| CONSTANT '(' STRING ')'
{ $$ = script_exp_function_constant($3.value, $3.length); }
| ABSOLUTE '(' exp ')'
{ $$ = script_exp_function_absolute($3); }
| ALIGN_K '(' exp ')'
{ $$ = script_exp_function_align(script_exp_string(".", 1), $3); }
| ALIGN_K '(' exp ',' exp ')'
{ $$ = script_exp_function_align($3, $5); }
| BLOCK '(' exp ')'
{ $$ = script_exp_function_align(script_exp_string(".", 1), $3); }
| DATA_SEGMENT_ALIGN '(' exp ',' exp ')'
{ $$ = script_exp_function_data_segment_align($3, $5); }
| DATA_SEGMENT_RELRO_END '(' exp ',' exp ')'
{ $$ = script_exp_function_data_segment_relro_end($3, $5); }
| DATA_SEGMENT_END '(' exp ')'
{ $$ = script_exp_function_data_segment_end($3); }
| SEGMENT_START '(' STRING ',' exp ')'
{
$$ = script_exp_function_segment_start($3.value, $3.length, $5);
}
| ASSERT_K '(' exp ',' STRING ')'
{ $$ = script_exp_function_assert($3, $5.value, $5.length); }
;
/* Handle the --defsym option. */
defsym_expr:
STRING '=' parse_exp
{ script_set_symbol(closure, $1.value, $1.length, $3, 0, 0); }
;
/* A version script. Not yet implemented. */
version_script:
;
/* Some statements require a terminator, which may be a semicolon or a
comma. */
end:
';'
| ','
;
/* An optional comma. */