diff options
author | Ian Lance Taylor <iant@google.com> | 2008-01-09 19:57:45 +0000 |
---|---|---|
committer | Ian Lance Taylor <iant@google.com> | 2008-01-09 19:57:45 +0000 |
commit | e5756efb6d46f569d2e99d19f726b32b84f58bd7 (patch) | |
tree | 953c35bf025a640d99bccbd4acbce67dc8b677b5 /gold/expression.cc | |
parent | cda30489fc0f7870150158863780d67f5efedd90 (diff) | |
download | fsf-binutils-gdb-e5756efb6d46f569d2e99d19f726b32b84f58bd7.zip fsf-binutils-gdb-e5756efb6d46f569d2e99d19f726b32b84f58bd7.tar.gz fsf-binutils-gdb-e5756efb6d46f569d2e99d19f726b32b84f58bd7.tar.bz2 |
Support assignments and expressions in linker scripts.
Diffstat (limited to 'gold/expression.cc')
-rw-r--r-- | gold/expression.cc | 508 |
1 files changed, 508 insertions, 0 deletions
diff --git a/gold/expression.cc b/gold/expression.cc new file mode 100644 index 0000000..3933280 --- /dev/null +++ b/gold/expression.cc @@ -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. |