summaryrefslogtreecommitdiff
path: root/gold/expression.cc
diff options
context:
space:
mode:
authorIan Lance Taylor <iant@google.com>2008-01-09 19:57:45 +0000
committerIan Lance Taylor <iant@google.com>2008-01-09 19:57:45 +0000
commitd10411c1a49967794bfbff8fc14565c803a66b90 (patch)
treecc5f71c623bb8bb60e4d6ae14bae0926b575dc71 /gold/expression.cc
parent32cb378daf8d4bb7cee039b31e636d512af4105b (diff)
downloadbinutils-redhat-d10411c1a49967794bfbff8fc14565c803a66b90.tar.gz
Support assignments and expressions in linker scripts.
Diffstat (limited to 'gold/expression.cc')
-rw-r--r--gold/expression.cc508
1 files changed, 508 insertions, 0 deletions
diff --git a/gold/expression.cc b/gold/expression.cc
new file mode 100644
index 0000000000..393328031f
--- /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.