Support assignments and expressions in linker scripts.
This commit is contained in:
parent
cda30489fc
commit
e5756efb6d
21 changed files with 1876 additions and 444 deletions
|
@ -37,6 +37,7 @@ CCFILES = \
|
|||
dwarf_reader.cc \
|
||||
ehframe.cc \
|
||||
errors.cc \
|
||||
expression.cc \
|
||||
fileread.cc \
|
||||
gold.cc \
|
||||
gold-threads.cc \
|
||||
|
|
|
@ -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
508
gold/expression.cc
Normal 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.
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
11
gold/main.cc
11
gold/main.cc
|
@ -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;
|
||||
|
|
|
@ -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_()
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -16,6 +16,7 @@ ehframe.cc
|
|||
ehframe.h
|
||||
errors.cc
|
||||
errors.h
|
||||
expression.cc
|
||||
fileread.cc
|
||||
fileread.h
|
||||
gold.cc
|
||||
|
|
429
gold/po/gold.pot
429
gold/po/gold.pot
|
@ -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 "
|
||||
|
|
|
@ -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.
|
||||
|
||||
|
|
141
gold/script-c.h
141
gold/script-c.h
|
@ -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
|
||||
}
|
||||
|
|
580
gold/script.cc
580
gold/script.cc
|
@ -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();
|
||||
}
|
||||
|
|
120
gold/script.h
120
gold/script.h
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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@
|
||||
|
|
47
gold/testsuite/script_test_1.cc
Normal file
47
gold/testsuite/script_test_1.cc
Normal 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;
|
||||
}
|
29
gold/testsuite/script_test_1.t
Normal file
29
gold/testsuite/script_test_1.t
Normal 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;
|
228
gold/yyscript.y
228
gold/yyscript.y
|
@ -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. */
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue