forked from Imagelibrary/binutils-gdb
From Andrew Chatham and Craig Silverstein: Add support for version
scripts.
This commit is contained in:
475
gold/script.cc
475
gold/script.cc
@@ -22,6 +22,7 @@
|
||||
|
||||
#include "gold.h"
|
||||
|
||||
#include <fnmatch.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <cstdio>
|
||||
@@ -29,6 +30,7 @@
|
||||
#include "filenames.h"
|
||||
|
||||
#include "elfcpp.h"
|
||||
#include "demangle.h"
|
||||
#include "dirsearch.h"
|
||||
#include "options.h"
|
||||
#include "fileread.h"
|
||||
@@ -245,26 +247,32 @@ class Lex
|
||||
inline bool
|
||||
can_start_name(char c, char c2);
|
||||
|
||||
// Return whether C can appear in a name which has already started.
|
||||
inline bool
|
||||
can_continue_name(char c);
|
||||
// If C can appear in a name which has already started, return a
|
||||
// pointer to a character later in the token or just past
|
||||
// it. Otherwise, return NULL.
|
||||
inline const char*
|
||||
can_continue_name(const char* c);
|
||||
|
||||
// Return whether C, C2, C3 can start a hex number.
|
||||
inline bool
|
||||
can_start_hex(char c, char c2, char c3);
|
||||
|
||||
// Return whether C can appear in a hex number.
|
||||
inline bool
|
||||
can_continue_hex(char c);
|
||||
// If C can appear in a hex number which has already started, return
|
||||
// a pointer to a character later in the token or just past
|
||||
// it. Otherwise, return NULL.
|
||||
inline const char*
|
||||
can_continue_hex(const char* c);
|
||||
|
||||
// Return whether C can start a non-hex number.
|
||||
static inline bool
|
||||
can_start_number(char c);
|
||||
|
||||
// Return whether C can appear in a non-hex number.
|
||||
inline bool
|
||||
can_continue_number(char c)
|
||||
{ return Lex::can_start_number(c); }
|
||||
// If C can appear in a decimal number which has already started,
|
||||
// return a pointer to a character later in the token or just past
|
||||
// it. Otherwise, return NULL.
|
||||
inline const char*
|
||||
can_continue_number(const char* c)
|
||||
{ return Lex::can_start_number(*c) ? c + 1 : NULL; }
|
||||
|
||||
// If C1 C2 C3 form a valid three character operator, return the
|
||||
// opcode. Otherwise return 0.
|
||||
@@ -299,7 +307,7 @@ class Lex
|
||||
// MATCH. Set *PP to the character following the token.
|
||||
inline Token
|
||||
gather_token(Token::Classification,
|
||||
bool (Lex::*can_continue_fn)(char),
|
||||
const char* (Lex::*can_continue_fn)(const char*),
|
||||
const char* start, const char* match, const char** pp);
|
||||
|
||||
// Build a token from a quoted string.
|
||||
@@ -382,7 +390,10 @@ Lex::can_start_name(char c, char c2)
|
||||
return this->mode_ == LINKER_SCRIPT;
|
||||
|
||||
case '~':
|
||||
return this->mode_ == LINKER_SCRIPT && can_continue_name(c2);
|
||||
return this->mode_ == LINKER_SCRIPT && can_continue_name(&c2);
|
||||
|
||||
case '*': case '[':
|
||||
return this->mode_ == VERSION_SCRIPT;
|
||||
|
||||
default:
|
||||
return false;
|
||||
@@ -395,10 +406,10 @@ Lex::can_start_name(char c, char c2)
|
||||
// script language requires spaces around operators, unless we know
|
||||
// that we are parsing an expression.
|
||||
|
||||
inline bool
|
||||
Lex::can_continue_name(char c)
|
||||
inline const char*
|
||||
Lex::can_continue_name(const char* c)
|
||||
{
|
||||
switch (c)
|
||||
switch (*c)
|
||||
{
|
||||
case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
|
||||
case 'G': case 'H': case 'I': case 'J': case 'K': case 'L':
|
||||
@@ -413,16 +424,38 @@ Lex::can_continue_name(char c)
|
||||
case '_': case '.': case '$':
|
||||
case '0': case '1': case '2': case '3': case '4':
|
||||
case '5': case '6': case '7': case '8': case '9':
|
||||
return true;
|
||||
return c + 1;
|
||||
|
||||
case '/': case '\\': case '~':
|
||||
case '=': case '+': case '-':
|
||||
case ':': case '[': case ']':
|
||||
case ',': case '?': case '*':
|
||||
return this->mode_ == LINKER_SCRIPT;
|
||||
case '=': case '+':
|
||||
case ',': case '?':
|
||||
if (this->mode_ == LINKER_SCRIPT)
|
||||
return c + 1;
|
||||
return NULL;
|
||||
|
||||
case '[': case ']': case '*': case '-':
|
||||
if (this->mode_ == LINKER_SCRIPT || this->mode_ == VERSION_SCRIPT)
|
||||
return c + 1;
|
||||
return NULL;
|
||||
|
||||
case '^':
|
||||
if (this->mode_ == VERSION_SCRIPT)
|
||||
return c + 1;
|
||||
return NULL;
|
||||
|
||||
case ':':
|
||||
if (this->mode_ == LINKER_SCRIPT)
|
||||
return c + 1;
|
||||
else if (this->mode_ == VERSION_SCRIPT && (c[1] == ':'))
|
||||
{
|
||||
// A name can have '::' in it, as that's a c++ namespace
|
||||
// separator. But a single colon is not part of a name.
|
||||
return c + 2;
|
||||
}
|
||||
return NULL;
|
||||
|
||||
default:
|
||||
return false;
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -439,25 +472,25 @@ inline bool
|
||||
Lex::can_start_hex(char c1, char c2, char c3)
|
||||
{
|
||||
if (c1 == '0' && (c2 == 'x' || c2 == 'X'))
|
||||
return this->can_continue_hex(c3);
|
||||
return this->can_continue_hex(&c3);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Return whether C can appear in a hex number.
|
||||
|
||||
inline bool
|
||||
Lex::can_continue_hex(char c)
|
||||
inline const char*
|
||||
Lex::can_continue_hex(const char* c)
|
||||
{
|
||||
switch (c)
|
||||
switch (*c)
|
||||
{
|
||||
case '0': case '1': case '2': case '3': case '4':
|
||||
case '5': case '6': case '7': case '8': case '9':
|
||||
case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
|
||||
case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
|
||||
return true;
|
||||
return c + 1;
|
||||
|
||||
default:
|
||||
return false;
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -652,13 +685,14 @@ Lex::skip_line_comment(const char** pp)
|
||||
|
||||
inline Token
|
||||
Lex::gather_token(Token::Classification classification,
|
||||
bool (Lex::*can_continue_fn)(char),
|
||||
const char* (Lex::*can_continue_fn)(const char*),
|
||||
const char* start,
|
||||
const char* match,
|
||||
const char **pp)
|
||||
{
|
||||
while ((this->*can_continue_fn)(*match))
|
||||
++match;
|
||||
const char* new_match = NULL;
|
||||
while ((new_match = (this->*can_continue_fn)(match)))
|
||||
match = new_match;
|
||||
*pp = match;
|
||||
return this->make_token(classification, start, match - start, start);
|
||||
}
|
||||
@@ -941,8 +975,13 @@ class Parser_closure
|
||||
: filename_(filename), posdep_options_(posdep_options),
|
||||
in_group_(in_group), is_in_sysroot_(is_in_sysroot),
|
||||
command_line_(command_line), script_options_(script_options),
|
||||
version_script_info_(script_options->version_script_info()),
|
||||
lex_(lex), lineno_(0), charpos_(0), lex_mode_stack_(), inputs_(NULL)
|
||||
{ }
|
||||
{
|
||||
// We start out processing C symbols in the default lex mode.
|
||||
language_stack_.push_back("");
|
||||
lex_mode_stack_.push_back(lex->mode());
|
||||
}
|
||||
|
||||
// Return the file name.
|
||||
const char*
|
||||
@@ -978,6 +1017,11 @@ class Parser_closure
|
||||
script_options()
|
||||
{ return this->script_options_; }
|
||||
|
||||
// Return the object in which version script information should be stored.
|
||||
Version_script_info*
|
||||
version_script()
|
||||
{ return this->version_script_info_; }
|
||||
|
||||
// Return the next token, and advance.
|
||||
const Token*
|
||||
next_token()
|
||||
@@ -1005,6 +1049,11 @@ class Parser_closure
|
||||
this->lex_mode_stack_.pop_back();
|
||||
}
|
||||
|
||||
// Return the current lexer mode.
|
||||
Lex::Mode
|
||||
lex_mode() const
|
||||
{ return this->lex_mode_stack_.back(); }
|
||||
|
||||
// Return the line number of the last token.
|
||||
int
|
||||
lineno() const
|
||||
@@ -1030,6 +1079,23 @@ class Parser_closure
|
||||
saw_inputs() const
|
||||
{ return this->inputs_ != NULL && !this->inputs_->empty(); }
|
||||
|
||||
// Return the current language being processed in a version script
|
||||
// (eg, "C++"). The empty string represents unmangled C names.
|
||||
const std::string&
|
||||
get_current_language() const
|
||||
{ return this->language_stack_.back(); }
|
||||
|
||||
// Push a language onto the stack when entering an extern block.
|
||||
void push_language(const std::string& lang)
|
||||
{ this->language_stack_.push_back(lang); }
|
||||
|
||||
// Pop a language off of the stack when exiting an extern block.
|
||||
void pop_language()
|
||||
{
|
||||
gold_assert(!this->language_stack_.empty());
|
||||
this->language_stack_.pop_back();
|
||||
}
|
||||
|
||||
private:
|
||||
// The name of the file we are reading.
|
||||
const char* filename_;
|
||||
@@ -1043,6 +1109,8 @@ class Parser_closure
|
||||
Command_line* command_line_;
|
||||
// Options which may be set from any linker script.
|
||||
Script_options* script_options_;
|
||||
// Information parsed from a version script.
|
||||
Version_script_info* version_script_info_;
|
||||
// The lexer.
|
||||
Lex* lex_;
|
||||
// The line number of the last token returned by next_token.
|
||||
@@ -1051,6 +1119,9 @@ class Parser_closure
|
||||
int charpos_;
|
||||
// A stack of lexer modes.
|
||||
std::vector<Lex::Mode> lex_mode_stack_;
|
||||
// A stack of which extern/language block we're inside. Can be C++,
|
||||
// java, or empty for C.
|
||||
std::vector<std::string> language_stack_;
|
||||
// New input files found to add to the link.
|
||||
Input_arguments* inputs_;
|
||||
};
|
||||
@@ -1119,11 +1190,13 @@ read_input_script(Workqueue* workqueue, const General_options& options,
|
||||
return true;
|
||||
}
|
||||
|
||||
// FILENAME was found as an argument to --script (-T).
|
||||
// Read it as a script, and execute its contents immediately.
|
||||
// Helper function for read_version_script() and
|
||||
// read_commandline_script(). Processes the given file in the mode
|
||||
// indicated by first_token and lex_mode.
|
||||
|
||||
bool
|
||||
read_commandline_script(const char* filename, Command_line* cmdline)
|
||||
static bool
|
||||
read_script_file(const char* filename, Command_line* cmdline,
|
||||
int first_token, Lex::Mode lex_mode)
|
||||
{
|
||||
// TODO: if filename is a relative filename, search for it manually
|
||||
// using "." + cmdline->options()->search_path() -- not dirsearch.
|
||||
@@ -1143,7 +1216,8 @@ read_commandline_script(const char* filename, Command_line* cmdline)
|
||||
std::string input_string;
|
||||
Lex::read_file(&input_file, &input_string);
|
||||
|
||||
Lex lex(input_string.c_str(), input_string.length(), PARSING_LINKER_SCRIPT);
|
||||
Lex lex(input_string.c_str(), input_string.length(), first_token);
|
||||
lex.set_mode(lex_mode);
|
||||
|
||||
Parser_closure closure(filename,
|
||||
cmdline->position_dependent_options(),
|
||||
@@ -1165,6 +1239,27 @@ read_commandline_script(const char* filename, Command_line* cmdline)
|
||||
return true;
|
||||
}
|
||||
|
||||
// FILENAME was found as an argument to --script (-T).
|
||||
// Read it as a script, and execute its contents immediately.
|
||||
|
||||
bool
|
||||
read_commandline_script(const char* filename, Command_line* cmdline)
|
||||
{
|
||||
return read_script_file(filename, cmdline,
|
||||
PARSING_LINKER_SCRIPT, Lex::LINKER_SCRIPT);
|
||||
}
|
||||
|
||||
// FILE was found as an argument to --version-script. Read it as a
|
||||
// version script, and store its contents in
|
||||
// cmdline->script_options()->version_script_info().
|
||||
|
||||
bool
|
||||
read_version_script(const char* filename, Command_line* cmdline)
|
||||
{
|
||||
return read_script_file(filename, cmdline,
|
||||
PARSING_VERSION_SCRIPT, Lex::VERSION_SCRIPT);
|
||||
}
|
||||
|
||||
// Implement the --defsym option on the command line. Return true if
|
||||
// all is well.
|
||||
|
||||
@@ -1189,7 +1284,8 @@ Script_options::define_symbol(const char* definition)
|
||||
}
|
||||
|
||||
// Manage mapping from keywords to the codes expected by the bison
|
||||
// parser.
|
||||
// parser. We construct one global object for each lex mode with
|
||||
// keywords.
|
||||
|
||||
class Keyword_to_parsecode
|
||||
{
|
||||
@@ -1203,25 +1299,27 @@ class Keyword_to_parsecode
|
||||
int parsecode;
|
||||
};
|
||||
|
||||
Keyword_to_parsecode(const Keyword_parsecode* keywords,
|
||||
int keyword_count)
|
||||
: keyword_parsecodes_(keywords), keyword_count_(keyword_count)
|
||||
{ }
|
||||
|
||||
// Return the parsecode corresponding KEYWORD, or 0 if it is not a
|
||||
// keyword.
|
||||
static int
|
||||
keyword_to_parsecode(const char* keyword, size_t len);
|
||||
int
|
||||
keyword_to_parsecode(const char* keyword, size_t len) const;
|
||||
|
||||
private:
|
||||
// The array of all keywords.
|
||||
static const Keyword_parsecode keyword_parsecodes_[];
|
||||
|
||||
// The number of keywords.
|
||||
static const int keyword_count;
|
||||
const Keyword_parsecode* keyword_parsecodes_;
|
||||
const int keyword_count_;
|
||||
};
|
||||
|
||||
// Mapping from keyword string to keyword parsecode. This array must
|
||||
// be kept in sorted order. Parsecodes are looked up using bsearch.
|
||||
// This array must correspond to the list of parsecodes in yyscript.y.
|
||||
|
||||
const Keyword_to_parsecode::Keyword_parsecode
|
||||
Keyword_to_parsecode::keyword_parsecodes_[] =
|
||||
static const Keyword_to_parsecode::Keyword_parsecode
|
||||
script_keyword_parsecodes[] =
|
||||
{
|
||||
{ "ABSOLUTE", ABSOLUTE },
|
||||
{ "ADDR", ADDR },
|
||||
@@ -1303,9 +1401,23 @@ Keyword_to_parsecode::keyword_parsecodes_[] =
|
||||
{ "sizeof_headers", SIZEOF_HEADERS },
|
||||
};
|
||||
|
||||
const int Keyword_to_parsecode::keyword_count =
|
||||
(sizeof(Keyword_to_parsecode::keyword_parsecodes_)
|
||||
/ sizeof(Keyword_to_parsecode::keyword_parsecodes_[0]));
|
||||
static const Keyword_to_parsecode
|
||||
script_keywords(&script_keyword_parsecodes[0],
|
||||
(sizeof(script_keyword_parsecodes)
|
||||
/ sizeof(script_keyword_parsecodes[0])));
|
||||
|
||||
static const Keyword_to_parsecode::Keyword_parsecode
|
||||
version_script_keyword_parsecodes[] =
|
||||
{
|
||||
{ "extern", EXTERN },
|
||||
{ "global", GLOBAL },
|
||||
{ "local", LOCAL },
|
||||
};
|
||||
|
||||
static const Keyword_to_parsecode
|
||||
version_script_keywords(&version_script_keyword_parsecodes[0],
|
||||
(sizeof(version_script_keyword_parsecodes)
|
||||
/ sizeof(version_script_keyword_parsecodes[0])));
|
||||
|
||||
// Comparison function passed to bsearch.
|
||||
|
||||
@@ -1335,16 +1447,17 @@ ktt_compare(const void* keyv, const void* kttv)
|
||||
} // End extern "C".
|
||||
|
||||
int
|
||||
Keyword_to_parsecode::keyword_to_parsecode(const char* keyword, size_t len)
|
||||
Keyword_to_parsecode::keyword_to_parsecode(const char* keyword,
|
||||
size_t len) const
|
||||
{
|
||||
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]),
|
||||
ktt_compare);
|
||||
this->keyword_parsecodes_,
|
||||
this->keyword_count_,
|
||||
sizeof(this->keyword_parsecodes_[0]),
|
||||
ktt_compare);
|
||||
if (kttv == NULL)
|
||||
return 0;
|
||||
Keyword_parsecode* ktt = static_cast<Keyword_parsecode*>(kttv);
|
||||
@@ -1383,7 +1496,18 @@ yylex(YYSTYPE* lvalp, void* closurev)
|
||||
// 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);
|
||||
int parsecode = 0;
|
||||
switch (closure->lex_mode())
|
||||
{
|
||||
case Lex::LINKER_SCRIPT:
|
||||
parsecode = script_keywords.keyword_to_parsecode(str, len);
|
||||
break;
|
||||
case Lex::VERSION_SCRIPT:
|
||||
parsecode = version_script_keywords.keyword_to_parsecode(str, len);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (parsecode != 0)
|
||||
return parsecode;
|
||||
lvalp->string.value = str;
|
||||
@@ -1561,6 +1685,16 @@ script_push_lex_into_expression_mode(void* closurev)
|
||||
closure->push_lex_mode(Lex::EXPRESSION);
|
||||
}
|
||||
|
||||
/* Called by the bison parser to push the lexer into version
|
||||
mode. */
|
||||
|
||||
extern void
|
||||
script_push_lex_into_version_mode(void* closurev)
|
||||
{
|
||||
Parser_closure* closure = static_cast<Parser_closure*>(closurev);
|
||||
closure->push_lex_mode(Lex::VERSION_SCRIPT);
|
||||
}
|
||||
|
||||
/* Called by the bison parser to pop the lexer mode. */
|
||||
|
||||
extern void
|
||||
@@ -1569,3 +1703,234 @@ script_pop_lex_mode(void* closurev)
|
||||
Parser_closure* closure = static_cast<Parser_closure*>(closurev);
|
||||
closure->pop_lex_mode();
|
||||
}
|
||||
|
||||
// The following structs are used within the VersionInfo class as well
|
||||
// as in the bison helper functions. They store the information
|
||||
// parsed from the version script.
|
||||
|
||||
// A single version expression.
|
||||
// For example, pattern="std::map*" and language="C++".
|
||||
// pattern and language should be from the stringpool
|
||||
struct Version_expression {
|
||||
Version_expression(const std::string& pattern,
|
||||
const std::string& language)
|
||||
: pattern(pattern), language(language) {}
|
||||
|
||||
std::string pattern;
|
||||
std::string language;
|
||||
};
|
||||
|
||||
|
||||
// A list of expressions.
|
||||
struct Version_expression_list {
|
||||
std::vector<struct Version_expression> expressions;
|
||||
};
|
||||
|
||||
|
||||
// A list of which versions upon which another version depends.
|
||||
// Strings should be from the Stringpool.
|
||||
struct Version_dependency_list {
|
||||
std::vector<std::string> dependencies;
|
||||
};
|
||||
|
||||
|
||||
// The total definition of a version. It includes the tag for the
|
||||
// version, its global and local expressions, and any dependencies.
|
||||
struct Version_tree {
|
||||
Version_tree()
|
||||
: tag(), global(NULL), local(NULL), dependencies(NULL) {}
|
||||
|
||||
std::string tag;
|
||||
const struct Version_expression_list* global;
|
||||
const struct Version_expression_list* local;
|
||||
const struct Version_dependency_list* dependencies;
|
||||
};
|
||||
|
||||
Version_script_info::~Version_script_info()
|
||||
{
|
||||
for (size_t k = 0; k < dependency_lists_.size(); ++k)
|
||||
delete dependency_lists_[k];
|
||||
for (size_t k = 0; k < version_trees_.size(); ++k)
|
||||
delete version_trees_[k];
|
||||
for (size_t k = 0; k < expression_lists_.size(); ++k)
|
||||
delete expression_lists_[k];
|
||||
}
|
||||
|
||||
std::vector<std::string>
|
||||
Version_script_info::get_versions() const
|
||||
{
|
||||
std::vector<std::string> ret;
|
||||
for (size_t j = 0; j < version_trees_.size(); ++j)
|
||||
ret.push_back(version_trees_[j]->tag);
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::vector<std::string>
|
||||
Version_script_info::get_dependencies(const char* version) const
|
||||
{
|
||||
std::vector<std::string> ret;
|
||||
for (size_t j = 0; j < version_trees_.size(); ++j)
|
||||
if (version_trees_[j]->tag == version)
|
||||
{
|
||||
const struct Version_dependency_list* deps =
|
||||
version_trees_[j]->dependencies;
|
||||
if (deps != NULL)
|
||||
for (size_t k = 0; k < deps->dependencies.size(); ++k)
|
||||
ret.push_back(deps->dependencies[k]);
|
||||
return ret;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
const std::string&
|
||||
Version_script_info::get_symbol_version_helper(const char* symbol_name,
|
||||
bool check_global) const
|
||||
{
|
||||
for (size_t j = 0; j < version_trees_.size(); ++j)
|
||||
{
|
||||
// Is it a global symbol for this version?
|
||||
const Version_expression_list* exp =
|
||||
check_global ? version_trees_[j]->global : version_trees_[j]->local;
|
||||
if (exp != NULL)
|
||||
for (size_t k = 0; k < exp->expressions.size(); ++k)
|
||||
{
|
||||
const char* name_to_match = symbol_name;
|
||||
char* demangled_name = NULL;
|
||||
if (exp->expressions[k].language == "C++")
|
||||
{
|
||||
demangled_name = cplus_demangle(symbol_name,
|
||||
DMGL_ANSI | DMGL_PARAMS);
|
||||
// This isn't a C++ symbol.
|
||||
if (demangled_name == NULL)
|
||||
continue;
|
||||
name_to_match = demangled_name;
|
||||
}
|
||||
else if (exp->expressions[k].language == "Java")
|
||||
{
|
||||
demangled_name = cplus_demangle(symbol_name,
|
||||
(DMGL_ANSI | DMGL_PARAMS
|
||||
| DMGL_JAVA));
|
||||
// This isn't a Java symbol.
|
||||
if (demangled_name == NULL)
|
||||
continue;
|
||||
name_to_match = demangled_name;
|
||||
}
|
||||
bool matched = fnmatch(exp->expressions[k].pattern.c_str(),
|
||||
name_to_match, FNM_NOESCAPE) == 0;
|
||||
if (demangled_name != NULL)
|
||||
free(demangled_name);
|
||||
if (matched)
|
||||
return version_trees_[j]->tag;
|
||||
}
|
||||
}
|
||||
static const std::string empty = "";
|
||||
return empty;
|
||||
}
|
||||
|
||||
struct Version_dependency_list*
|
||||
Version_script_info::allocate_dependency_list()
|
||||
{
|
||||
dependency_lists_.push_back(new Version_dependency_list);
|
||||
return dependency_lists_.back();
|
||||
}
|
||||
|
||||
struct Version_expression_list*
|
||||
Version_script_info::allocate_expression_list()
|
||||
{
|
||||
expression_lists_.push_back(new Version_expression_list);
|
||||
return expression_lists_.back();
|
||||
}
|
||||
|
||||
struct Version_tree*
|
||||
Version_script_info::allocate_version_tree()
|
||||
{
|
||||
version_trees_.push_back(new Version_tree);
|
||||
return version_trees_.back();
|
||||
}
|
||||
|
||||
// Register an entire version node. For example:
|
||||
//
|
||||
// GLIBC_2.1 {
|
||||
// global: foo;
|
||||
// } GLIBC_2.0;
|
||||
//
|
||||
// - tag is "GLIBC_2.1"
|
||||
// - tree contains the information "global: foo"
|
||||
// - deps contains "GLIBC_2.0"
|
||||
|
||||
extern "C" void
|
||||
script_register_vers_node(void*,
|
||||
const char* tag,
|
||||
int taglen,
|
||||
struct Version_tree *tree,
|
||||
struct Version_dependency_list *deps)
|
||||
{
|
||||
gold_assert(tree != NULL);
|
||||
gold_assert(tag != NULL);
|
||||
tree->dependencies = deps;
|
||||
tree->tag = std::string(tag, taglen);
|
||||
}
|
||||
|
||||
// Add a dependencies to the list of existing dependencies, if any,
|
||||
// and return the expanded list.
|
||||
|
||||
extern "C" struct Version_dependency_list *
|
||||
script_add_vers_depend(void* closurev,
|
||||
struct Version_dependency_list *all_deps,
|
||||
const char *depend_to_add, int deplen)
|
||||
{
|
||||
Parser_closure* closure = static_cast<Parser_closure*>(closurev);
|
||||
if (all_deps == NULL)
|
||||
all_deps = closure->version_script()->allocate_dependency_list();
|
||||
all_deps->dependencies.push_back(std::string(depend_to_add, deplen));
|
||||
return all_deps;
|
||||
}
|
||||
|
||||
// Add a pattern expression to an existing list of expressions, if any.
|
||||
// TODO: In the old linker, the last argument used to be a bool, but I
|
||||
// don't know what it meant.
|
||||
|
||||
extern "C" struct Version_expression_list *
|
||||
script_new_vers_pattern(void* closurev,
|
||||
struct Version_expression_list *expressions,
|
||||
const char *pattern, int patlen)
|
||||
{
|
||||
Parser_closure* closure = static_cast<Parser_closure*>(closurev);
|
||||
if (expressions == NULL)
|
||||
expressions = closure->version_script()->allocate_expression_list();
|
||||
expressions->expressions.push_back(
|
||||
Version_expression(std::string(pattern, patlen),
|
||||
closure->get_current_language()));
|
||||
return expressions;
|
||||
}
|
||||
|
||||
// Combine the global and local expressions into a a Version_tree.
|
||||
|
||||
extern "C" struct Version_tree *
|
||||
script_new_vers_node(void* closurev,
|
||||
struct Version_expression_list *global,
|
||||
struct Version_expression_list *local)
|
||||
{
|
||||
Parser_closure* closure = static_cast<Parser_closure*>(closurev);
|
||||
Version_tree* tree = closure->version_script()->allocate_version_tree();
|
||||
tree->global = global;
|
||||
tree->local = local;
|
||||
return tree;
|
||||
}
|
||||
|
||||
// Handle a transition in language, such as at the
|
||||
// start or end of 'extern "C++"'
|
||||
|
||||
extern "C" void
|
||||
version_script_push_lang(void* closurev, const char* lang, int langlen)
|
||||
{
|
||||
Parser_closure* closure = static_cast<Parser_closure*>(closurev);
|
||||
closure->push_language(std::string(lang, langlen));
|
||||
}
|
||||
|
||||
extern "C" void
|
||||
version_script_pop_lang(void* closurev)
|
||||
{
|
||||
Parser_closure* closure = static_cast<Parser_closure*>(closurev);
|
||||
closure->pop_language();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user