Support assignments and expressions in linker scripts.

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

View file

@ -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();
}