diff options
author | Andrew Hsieh <andrewhsieh@google.com> | 2014-06-13 12:38:00 -0700 |
---|---|---|
committer | Andrew Hsieh <andrewhsieh@google.com> | 2014-06-13 12:38:00 -0700 |
commit | 54f1b3cf509cd889905287cb8ce6c5ae33911a21 (patch) | |
tree | e39b1a7fa04db86a8215b7f9d4656d74e394aec0 /binutils-2.25/gold/script.h | |
parent | 2a6558a8ecfb81d75215b4ec7dc61113e12cfd5f (diff) | |
download | toolchain_binutils-54f1b3cf509cd889905287cb8ce6c5ae33911a21.zip toolchain_binutils-54f1b3cf509cd889905287cb8ce6c5ae33911a21.tar.gz toolchain_binutils-54f1b3cf509cd889905287cb8ce6c5ae33911a21.tar.bz2 |
Add upstream binutils-2.25 snapshot 4/4 2014
For MIPS -mmsa support
Change-Id: I08c4f002fa7b33dec85ed75956e6ab551bb03c96
Diffstat (limited to 'binutils-2.25/gold/script.h')
-rw-r--r-- | binutils-2.25/gold/script.h | 594 |
1 files changed, 594 insertions, 0 deletions
diff --git a/binutils-2.25/gold/script.h b/binutils-2.25/gold/script.h new file mode 100644 index 0000000..f41f438 --- /dev/null +++ b/binutils-2.25/gold/script.h @@ -0,0 +1,594 @@ +// script.h -- handle linker scripts for gold -*- C++ -*- + +// Copyright 2006, 2007, 2008, 2009, 2010 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. + +// We implement a subset of the original GNU ld linker script language +// for compatibility. The goal is not to implement the entire +// language. It is merely to implement enough to handle common uses. +// In particular we need to handle /usr/lib/libc.so on a typical +// GNU/Linux system, and we want to handle linker scripts used by the +// Linux kernel build. + +#ifndef GOLD_SCRIPT_H +#define GOLD_SCRIPT_H + +#include <cstdio> +#include <string> +#include <vector> + +#include "script-sections.h" + +namespace gold +{ + +class General_options; +class Command_line; +class Symbol_table; +class Layout; +class Mapfile; +class Input_argument; +class Input_arguments; +class Input_objects; +class Input_group; +class Input_file; +class Output_segment; +class Task_token; +class Workqueue; +struct Version_dependency_list; +struct Version_expression_list; +struct Version_tree; +struct Version_expression; +class Lazy_demangler; +class Incremental_script_entry; + +// 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 which is not permitted to + // refer to the dot symbol. CHECK_ASSERTIONS is true if we should + // check whether assertions are true. + uint64_t + eval(const Symbol_table*, const Layout*, bool check_assertions); + + // Return the value of an expression which is permitted to refer to + // the dot symbol. DOT_VALUE is the absolute value of the dot + // symbol. DOT_SECTION is the section in which dot is defined; it + // should be NULL if the dot symbol has an absolute value (e.g., is + // defined in a SECTIONS clause outside of any output section + // definition). This sets *RESULT_SECTION to indicate where the + // value is defined. If the value is absolute *RESULT_SECTION will + // be NULL. Note that the returned value is still an absolute + // value; to get a section relative value the caller must subtract + // the section address. If RESULT_ALIGNMENT is not NULL, this sets + // *RESULT_ALIGNMENT to the alignment of the value of that alignment + // is larger than *RESULT_ALIGNMENT; this will only be non-zero if + // this is an ALIGN expression. If IS_SECTION_DOT_ASSIGMENT is true, + // we are evaluating an assignment to dot within an output section, + // and an absolute value should be interpreted as an offset within + // the section. + uint64_t + eval_with_dot(const Symbol_table*, const Layout*, bool check_assertions, + uint64_t dot_value, Output_section* dot_section, + Output_section** result_section, uint64_t* result_alignment, + bool is_section_dot_assignment); + + // Return the value of an expression which may or may not be + // permitted to refer to the dot symbol, depending on + // is_dot_available. If IS_SECTION_DOT_ASSIGMENT is true, + // we are evaluating an assignment to dot within an output section, + // and an absolute value should be interpreted as an offset within + // the section. + uint64_t + eval_maybe_dot(const Symbol_table*, const Layout*, bool check_assertions, + bool is_dot_available, uint64_t dot_value, + Output_section* dot_section, + Output_section** result_section, uint64_t* result_alignment, + bool is_section_dot_assignment); + + // Print the expression to the FILE. This is for debugging. + virtual void + print(FILE*) const = 0; + + 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&); +}; + + +// Version_script_info stores information parsed from the version +// script, either provided by --version-script or as part of a linker +// script. A single Version_script_info object per target is owned by +// Script_options. + +class Version_script_info +{ + public: + // The languages which can be specified in a versionn script. + enum Language + { + LANGUAGE_C, // No demangling. + LANGUAGE_CXX, // C++ demangling. + LANGUAGE_JAVA, // Java demangling. + LANGUAGE_COUNT + }; + + Version_script_info(); + + ~Version_script_info(); + + // Clear everything. + void + clear(); + + // Finalize the version control information. + void + finalize(); + + // Return whether the information is finalized. + bool + is_finalized() const + { return this->is_finalized_; } + + // Return whether any version were defined in the version script. + bool + empty() const + { return this->version_trees_.empty(); } + + // If there is a version associated with SYMBOL, return true, and + // set *VERSION to the version, and *IS_GLOBAL to whether the symbol + // should be global. Otherwise, return false. + bool + get_symbol_version(const char* symbol, std::string* version, + bool* is_global) const; + + // Return whether this symbol matches the local: section of some + // version. + bool + symbol_is_local(const char* symbol) const + { + bool is_global; + return (this->get_symbol_version(symbol, NULL, &is_global) + && !is_global); + } + + // Return the names of versions defined in the version script. + std::vector<std::string> + get_versions() const; + + // Return the list of dependencies for this version. + std::vector<std::string> + get_dependencies(const char* version) const; + + // The following functions should only be used by the bison helper + // functions. They allocate new structs whose memory belongs to + // Version_script_info. The bison functions copy the information + // from the version script into these structs. + struct Version_dependency_list* + allocate_dependency_list(); + + struct Version_expression_list* + allocate_expression_list(); + + struct Version_tree* + allocate_version_tree(); + + // Build the lookup tables after all data have been read. + void + build_lookup_tables(); + + // Give an error if there are any unmatched names in the version + // script. + void + check_unmatched_names(const Symbol_table*) const; + + // Print contents to the FILE. This is for debugging. + void + print(FILE*) const; + + private: + void + print_expression_list(FILE* f, const Version_expression_list*) const; + + bool + get_symbol_version_helper(const char* symbol, + bool check_global, + std::string* pversion) const; + + // Fast lookup information for a given language. + + // We map from exact match strings to Version_tree's. Historically + // version scripts sometimes have the same symbol multiple times, + // which is ambiguous. We warn about that case by storing the + // second Version_tree we see. + struct Version_tree_match + { + Version_tree_match(const Version_tree* r, bool ig, + const Version_expression* e) + : real(r), is_global(ig), expression(e), ambiguous(NULL) + { } + + // The Version_tree that we return. + const Version_tree* real; + // True if this is a global match for the REAL member, false if it + // is a local match. + bool is_global; + // Point back to the Version_expression for which we created this + // match. + const Version_expression* expression; + // If not NULL, another Version_tree that defines the symbol. + const Version_tree* ambiguous; + }; + + // Map from an exact match string to a Version_tree. + + typedef Unordered_map<std::string, Version_tree_match> Exact; + + // Fast lookup information for a glob pattern. + struct Glob + { + Glob() + : expression(NULL), version(NULL), is_global(false) + { } + + Glob(const Version_expression* e, const Version_tree* v, bool ig) + : expression(e), version(v), is_global(ig) + { } + + // A pointer to the version expression holding the pattern to + // match and the language to use for demangling the symbol before + // doing the match. + const Version_expression* expression; + // The Version_tree we use if this pattern matches. + const Version_tree* version; + // True if this is a global symbol. + bool is_global; + }; + + typedef std::vector<Glob> Globs; + + bool + unquote(std::string*) const; + + void + add_exact_match(const std::string&, const Version_tree*, bool is_global, + const Version_expression*, Exact*); + + void + build_expression_list_lookup(const Version_expression_list*, + const Version_tree*, bool); + + const char* + get_name_to_match(const char*, int, + Lazy_demangler*, Lazy_demangler*) const; + + // All the version dependencies we allocate. + std::vector<Version_dependency_list*> dependency_lists_; + // All the version expressions we allocate. + std::vector<Version_expression_list*> expression_lists_; + // The list of versions. + std::vector<Version_tree*> version_trees_; + // Exact matches for global symbols, by language. + Exact* exact_[LANGUAGE_COUNT]; + // A vector of glob patterns mapping to Version_trees. + Globs globs_; + // The default version to use, if there is one. This is from a + // pattern of "*". + const Version_tree* default_version_; + // True if the default version is global. + bool default_is_global_; + // Whether this has been finalized. + bool is_finalized_; +}; + +// This class manages assignments to symbols. These can appear in +// three different locations in scripts: outside of a SECTIONS clause, +// within a SECTIONS clause, and within an output section definition +// within a SECTIONS clause. This can also appear on the command line +// via the --defsym command line option. + +class Symbol_assignment +{ + public: + Symbol_assignment(const char* name, size_t namelen, bool is_defsym, + Expression* val, bool provide, bool hidden) + : name_(name, namelen), val_(val), is_defsym_(is_defsym), + provide_(provide), hidden_(hidden), sym_(NULL) + { } + + // Add the symbol to the symbol table. + void + add_to_table(Symbol_table*); + + // Finalize the symbol value. + void + finalize(Symbol_table*, const Layout*); + + // Finalize the symbol value when it can refer to the dot symbol. + void + finalize_with_dot(Symbol_table*, const Layout*, uint64_t dot_value, + Output_section* dot_section); + + // Set the symbol value, but only if the value is absolute or relative to + // DOT_SECTION. This is used while processing a SECTIONS clause. + // We assume that dot is an absolute value here. We do not check assertions. + void + set_if_absolute(Symbol_table*, const Layout*, bool is_dot_available, + uint64_t dot_value, Output_section* dot_section); + + const std::string& + name() const + { return this->name_; } + + // Print the assignment to the FILE. This is for debugging. + void + print(FILE*) const; + + private: + // Shared by finalize and finalize_with_dot. + void + finalize_maybe_dot(Symbol_table*, const Layout*, bool is_dot_available, + uint64_t dot_value, Output_section* dot_section); + + // Sized version of finalize. + template<int size> + void + sized_finalize(Symbol_table*, const Layout*, bool is_dot_available, + uint64_t dot_value, Output_section*); + + // Symbol name. + std::string name_; + // Expression to assign to symbol. + Expression* val_; + // True if this symbol is defined by a --defsym, false if it is + // defined in a linker script. + bool is_defsym_; + // 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_; +}; + +// This class manages assertions in linker scripts. These can appear +// in all the places where a Symbol_assignment can appear. + +class Script_assertion +{ + public: + Script_assertion(Expression* check, const char* message, + size_t messagelen) + : check_(check), message_(message, messagelen) + { } + + // Check the assertion. + void + check(const Symbol_table*, const Layout*); + + // Print the assertion to the FILE. This is for debugging. + void + print(FILE*) const; + + private: + // The expression to check. + Expression* check_; + // The message to issue if the expression fails. + std::string message_; +}; + +// 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(); + + // Add a symbol to be defined. + void + add_symbol_assignment(const char* name, size_t length, bool is_defsym, + Expression* value, bool provide, bool hidden); + + // Look for an assigned symbol. + bool + is_pending_assignment(const char* name); + + // Add a reference to a symbol. + void + add_symbol_reference(const char* name, size_t length); + + // Add an assertion. + void + add_assertion(Expression* check, const char* message, size_t messagelen); + + // Define a symbol from the command line. + bool + define_symbol(const char* definition); + + // Create sections required by any linker scripts. + void + create_script_sections(Layout*); + + // Add all symbol definitions to the symbol table. + void + add_symbols_to_table(Symbol_table*); + + // Used to iterate over symbols which are referenced in expressions + // but not defined. + typedef Unordered_set<std::string>::const_iterator referenced_const_iterator; + + referenced_const_iterator + referenced_begin() const + { return this->symbol_references_.begin(); } + + referenced_const_iterator + referenced_end() const + { return this->symbol_references_.end(); } + + // Return whether a symbol is referenced but not defined. + bool + is_referenced(const std::string& name) const + { + return (this->symbol_references_.find(name) + != this->symbol_references_.end()); + } + + // Return whether there are any symbols which were referenced but + // not defined. + bool + any_unreferenced() const + { return !this->symbol_references_.empty(); } + + // Finalize the symbol values. Also check assertions. + void + finalize_symbols(Symbol_table*, const Layout*); + + // Version information parsed from a version script. Everything + // else has a pointer to this object. + Version_script_info* + version_script_info() + { return &this->version_script_info_; } + + const Version_script_info* + version_script_info() const + { return &this->version_script_info_; } + + // A SECTIONS clause parsed from a linker script. Everything else + // has a pointer to this object. + Script_sections* + script_sections() + { return &this->script_sections_; } + + const Script_sections* + script_sections() const + { return &this->script_sections_; } + + // Whether we saw a SECTIONS clause. + bool + saw_sections_clause() const + { return this->script_sections_.saw_sections_clause(); } + + // Whether we saw a PHDRS clause. + bool + saw_phdrs_clause() const + { return this->script_sections_.saw_phdrs_clause(); } + + // Set section addresses using a SECTIONS clause. Return the + // segment which should hold the file header and segment headers; + // this may return NULL, in which case the headers are not in a + // loadable segment. + Output_segment* + set_section_addresses(Symbol_table*, Layout*); + + // Print the script to the FILE. This is for debugging. + void + print(FILE*) const; + + private: + // We keep a list of symbol assignments which occur outside of a + // SECTIONS clause. + typedef std::vector<Symbol_assignment*> Symbol_assignments; + + // We keep a list of all assertions whcih occur outside of a + // SECTIONS clause. + typedef std::vector<Script_assertion*> Assertions; + + // The entry address. This will be empty if not set. + std::string entry_; + // Symbols to set. + Symbol_assignments symbol_assignments_; + // Symbols defined in an expression, for faster lookup. + Unordered_set<std::string> symbol_definitions_; + // Symbols referenced in an expression. + Unordered_set<std::string> symbol_references_; + // Assertions to check. + Assertions assertions_; + // Version information parsed from a version script. + Version_script_info version_script_info_; + // Information from any SECTIONS clauses. + Script_sections script_sections_; +}; + +// 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. Return +// true if the file was handled. This has to handle /usr/lib/libc.so +// on a GNU/Linux system. *USED_NEXT_BLOCKER is set to indicate +// whether the function took over NEXT_BLOCKER. + +bool +read_input_script(Workqueue*, Symbol_table*, Layout*, Dirsearch*, int, + Input_objects*, Mapfile*, Input_group*, + const Input_argument*, Input_file*, + Task_token* next_blocker, bool* used_next_blocker); + +// FILE was found as an argument to --script (-T). +// Read it as a script, and execute its contents immediately. + +bool +read_commandline_script(const char* filename, Command_line* cmdline); + +// 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); + +// FILENAME was found as an argument to --dynamic-list. Read it as a +// version script (actually, a versym_node from a version script), and +// store its contents in DYNAMIC_LIST. + +bool +read_dynamic_list(const char* filename, Command_line* cmdline, + Script_options* dynamic_list); + +} // End namespace gold. + +#endif // !defined(GOLD_SCRIPT_H) |