URL
https://opencores.org/ocsvn/openrisc_me/openrisc_me/trunk
Subversion Repositories openrisc_me
[/] [openrisc/] [trunk/] [gnu-src/] [binutils-2.20.1/] [gold/] [expression.cc] - Rev 205
Compare with Previous | Blame | View Log
// 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 "elfcpp.h" #include "parameters.h" #include "symtab.h" #include "layout.h" #include "output.h" #include "script.h" #include "script-c.h" namespace gold { // This file holds the code which handles linker expressions. // The dot symbol, which linker scripts refer to simply as ".", // requires special treatment. The dot symbol is set several times, // section addresses will refer to it, output sections will change it, // and it can be set based on the value of other symbols. We simplify // the handling by prohibiting setting the dot symbol to the value of // a non-absolute symbol. // 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 { // The symbol table. const Symbol_table* symtab; // The layout--we use this to get section information. const Layout* layout; // Whether to check assertions. bool check_assertions; // Whether expressions can refer to the dot symbol. The dot symbol // is only available within a SECTIONS clause. bool is_dot_available; // The current value of the dot symbol. uint64_t dot_value; // The section in which the dot symbol is defined; this is NULL if // it is absolute. Output_section* dot_section; // Points to where the section of the result should be stored. Output_section** result_section_pointer; }; // Evaluate an expression. uint64_t Expression::eval(const Symbol_table* symtab, const Layout* layout, bool check_assertions) { Output_section* dummy; return this->eval_maybe_dot(symtab, layout, check_assertions, false, 0, NULL, &dummy); } // Evaluate an expression which may refer to the dot symbol. uint64_t Expression::eval_with_dot(const Symbol_table* symtab, const Layout* layout, bool check_assertions, uint64_t dot_value, Output_section* dot_section, Output_section** result_section_pointer) { return this->eval_maybe_dot(symtab, layout, check_assertions, true, dot_value, dot_section, result_section_pointer); } // Evaluate an expression which may or may not refer to the dot // symbol. uint64_t Expression::eval_maybe_dot(const Symbol_table* symtab, const Layout* layout, bool check_assertions, bool is_dot_available, uint64_t dot_value, Output_section* dot_section, Output_section** result_section_pointer) { Expression_eval_info eei; eei.symtab = symtab; eei.layout = layout; eei.check_assertions = check_assertions; eei.is_dot_available = is_dot_available; eei.dot_value = dot_value; eei.dot_section = dot_section; // We assume the value is absolute, and only set this to a section // if we find a section relative reference. *result_section_pointer = NULL; eei.result_section_pointer = result_section_pointer; 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_; } void print(FILE* f) const { fprintf(f, "0x%llx", static_cast<unsigned long long>(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*); void print(FILE* f) const { fprintf(f, "%s", this->name_.c_str()); } 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; } *eei->result_section_pointer = sym->output_section(); if (parameters->target().get_size() == 32) return eei->symtab->get_sized_symbol<32>(sym)->value(); else if (parameters->target().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*); void print(FILE* f) const { fprintf(f, "."); } }; uint64_t Dot_expression::value(const Expression_eval_info* eei) { if (!eei->is_dot_available) { gold_error(_("invalid reference to dot symbol outside of " "SECTIONS clause")); return 0; } *eei->result_section_pointer = eei->dot_section; return eei->dot_value; } // 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, Output_section** arg_section_pointer) const { return this->arg_->eval_maybe_dot(eei->symtab, eei->layout, eei->check_assertions, eei->is_dot_available, eei->dot_value, eei->dot_section, arg_section_pointer); } void arg_print(FILE* f) const { this->arg_->print(f); } 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) \ { \ Output_section* arg_section; \ uint64_t ret = OPERATOR this->arg_value(eei, &arg_section); \ if (arg_section != NULL && parameters->options().relocatable()) \ gold_warning(_("unary " #NAME " applied to section " \ "relative value")); \ return ret; \ } \ \ void \ print(FILE* f) const \ { \ fprintf(f, "(%s ", #OPERATOR); \ this->arg_print(f); \ fprintf(f, ")"); \ } \ }; \ \ 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, Output_section** section_pointer) const { return this->left_->eval_maybe_dot(eei->symtab, eei->layout, eei->check_assertions, eei->is_dot_available, eei->dot_value, eei->dot_section, section_pointer); } uint64_t right_value(const Expression_eval_info* eei, Output_section** section_pointer) const { return this->right_->eval_maybe_dot(eei->symtab, eei->layout, eei->check_assertions, eei->is_dot_available, eei->dot_value, eei->dot_section, section_pointer); } void left_print(FILE* f) const { this->left_->print(f); } void right_print(FILE* f) const { this->right_->print(f); } // This is a call to function FUNCTION_NAME. Print it. This is for // debugging. void print_function(FILE* f, const char *function_name) const { fprintf(f, "%s(", function_name); this->left_print(f); fprintf(f, ", "); this->right_print(f); fprintf(f, ")"); } private: Expression* left_; Expression* right_; }; // Handle binary operators. We use a preprocessor macro as a hack to // capture the C operator. KEEP_LEFT means that if the left operand // is section relative and the right operand is not, the result uses // the same section as the left operand. KEEP_RIGHT is the same with // left and right swapped. IS_DIV means that we need to give an error // if the right operand is zero. WARN means that we should warn if // used on section relative values in a relocatable link. We always // warn if used on values in different sections in a relocatable link. #define BINARY_EXPRESSION(NAME, OPERATOR, KEEP_LEFT, KEEP_RIGHT, IS_DIV, WARN) \ 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) \ { \ Output_section* left_section; \ uint64_t left = this->left_value(eei, &left_section); \ Output_section* right_section; \ uint64_t right = this->right_value(eei, &right_section); \ if (KEEP_RIGHT && left_section == NULL && right_section != NULL) \ *eei->result_section_pointer = right_section; \ else if (KEEP_LEFT \ && left_section != NULL \ && right_section == NULL) \ *eei->result_section_pointer = left_section; \ else if ((WARN || left_section != right_section) \ && (left_section != NULL || right_section != NULL) \ && parameters->options().relocatable()) \ gold_warning(_("binary " #NAME " applied to section " \ "relative value")); \ if (IS_DIV && right == 0) \ { \ gold_error(_(#NAME " by zero")); \ return 0; \ } \ return left OPERATOR right; \ } \ \ void \ print(FILE* f) const \ { \ fprintf(f, "("); \ this->left_print(f); \ fprintf(f, " %s ", #OPERATOR); \ this->right_print(f); \ fprintf(f, ")"); \ } \ }; \ \ extern "C" Expression* \ script_exp_binary_ ## NAME(Expression* left, Expression* right) \ { \ return new Binary_ ## NAME(left, right); \ } BINARY_EXPRESSION(mult, *, false, false, false, true) BINARY_EXPRESSION(div, /, false, false, true, true) BINARY_EXPRESSION(mod, %, false, false, true, true) BINARY_EXPRESSION(add, +, true, true, false, true) BINARY_EXPRESSION(sub, -, true, false, false, false) BINARY_EXPRESSION(lshift, <<, false, false, false, true) BINARY_EXPRESSION(rshift, >>, false, false, false, true) BINARY_EXPRESSION(eq, ==, false, false, false, false) BINARY_EXPRESSION(ne, !=, false, false, false, false) BINARY_EXPRESSION(le, <=, false, false, false, false) BINARY_EXPRESSION(ge, >=, false, false, false, false) BINARY_EXPRESSION(lt, <, false, false, false, false) BINARY_EXPRESSION(gt, >, false, false, false, false) BINARY_EXPRESSION(bitwise_and, &, true, true, false, true) BINARY_EXPRESSION(bitwise_xor, ^, true, true, false, true) BINARY_EXPRESSION(bitwise_or, |, true, true, false, true) BINARY_EXPRESSION(logical_and, &&, false, false, false, true) BINARY_EXPRESSION(logical_or, ||, false, false, false, true) // 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, Output_section** section_pointer) const { return this->arg1_->eval_maybe_dot(eei->symtab, eei->layout, eei->check_assertions, eei->is_dot_available, eei->dot_value, eei->dot_section, section_pointer); } uint64_t arg2_value(const Expression_eval_info* eei, Output_section** section_pointer) const { return this->arg1_->eval_maybe_dot(eei->symtab, eei->layout, eei->check_assertions, eei->is_dot_available, eei->dot_value, eei->dot_section, section_pointer); } uint64_t arg3_value(const Expression_eval_info* eei, Output_section** section_pointer) const { return this->arg1_->eval_maybe_dot(eei->symtab, eei->layout, eei->check_assertions, eei->is_dot_available, eei->dot_value, eei->dot_section, section_pointer); } void arg1_print(FILE* f) const { this->arg1_->print(f); } void arg2_print(FILE* f) const { this->arg2_->print(f); } void arg3_print(FILE* f) const { this->arg3_->print(f); } 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) { Output_section* arg1_section; uint64_t arg1 = this->arg1_value(eei, &arg1_section); return (arg1 ? this->arg2_value(eei, eei->result_section_pointer) : this->arg3_value(eei, eei->result_section_pointer)); } void print(FILE* f) const { fprintf(f, "("); this->arg1_print(f); fprintf(f, " ? "); this->arg2_print(f); fprintf(f, " : "); this->arg3_print(f); fprintf(f, ")"); } }; 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) { Output_section* left_section; uint64_t left = this->left_value(eei, &left_section); Output_section* right_section; uint64_t right = this->right_value(eei, &right_section); if (left_section == right_section) *eei->result_section_pointer = left_section; else if ((left_section != NULL || right_section != NULL) && parameters->options().relocatable()) gold_warning(_("max applied to section relative value")); return std::max(left, right); } void print(FILE* f) const { this->print_function(f, "MAX"); } }; 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) { Output_section* left_section; uint64_t left = this->left_value(eei, &left_section); Output_section* right_section; uint64_t right = this->right_value(eei, &right_section); if (left_section == right_section) *eei->result_section_pointer = left_section; else if ((left_section != NULL || right_section != NULL) && parameters->options().relocatable()) gold_warning(_("min applied to section relative value")); return std::min(left, right); } void print(FILE* f) const { this->print_function(f, "MIN"); } }; extern "C" Expression* script_exp_function_min(Expression* left, Expression* right) { return new Min_expression(left, right); } // Class Section_expression. This is a parent class used for // functions which take the name of an output section. class Section_expression : public Expression { public: Section_expression(const char* section_name, size_t section_name_len) : section_name_(section_name, section_name_len) { } uint64_t value(const Expression_eval_info*); void print(FILE* f) const { fprintf(f, "%s(%s)", this->function_name(), this->section_name_.c_str()); } protected: // The child class must implement this. virtual uint64_t value_from_output_section(const Expression_eval_info*, Output_section*) = 0; // The child class must implement this. virtual uint64_t value_from_script_output_section(uint64_t address, uint64_t load_address, uint64_t addralign, uint64_t size) = 0; // The child class must implement this. virtual const char* function_name() const = 0; private: std::string section_name_; }; uint64_t Section_expression::value(const Expression_eval_info* eei) { const char* section_name = this->section_name_.c_str(); Output_section* os = eei->layout->find_output_section(section_name); if (os != NULL) return this->value_from_output_section(eei, os); uint64_t address; uint64_t load_address; uint64_t addralign; uint64_t size; const Script_options* ss = eei->layout->script_options(); if (ss->saw_sections_clause()) { if (ss->script_sections()->get_output_section_info(section_name, &address, &load_address, &addralign, &size)) return this->value_from_script_output_section(address, load_address, addralign, size); } gold_error("%s called on nonexistent output section '%s'", this->function_name(), section_name); return 0; } // ABSOLUTE function. class Absolute_expression : public Unary_expression { public: Absolute_expression(Expression* arg) : Unary_expression(arg) { } uint64_t value(const Expression_eval_info* eei) { Output_section* dummy; uint64_t ret = this->arg_value(eei, &dummy); // Force the value to be absolute. *eei->result_section_pointer = NULL; return ret; } void print(FILE* f) const { fprintf(f, "ABSOLUTE("); this->arg_print(f); fprintf(f, ")"); } }; extern "C" Expression* script_exp_function_absolute(Expression* arg) { return new Absolute_expression(arg); } // 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) { Output_section* align_section; uint64_t align = this->right_value(eei, &align_section); if (align_section != NULL && parameters->options().relocatable()) gold_warning(_("aligning to section relative value")); uint64_t value = this->left_value(eei, eei->result_section_pointer); if (align <= 1) return value; return ((value + align - 1) / align) * align; } void print(FILE* f) const { this->print_function(f, "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, eei->result_section_pointer); if (!value && eei->check_assertions) gold_error("%s", this->message_.c_str()); return value; } void print(FILE* f) const { fprintf(f, "ASSERT("); this->arg_print(f); fprintf(f, ", %s)", this->message_.c_str()); } 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); } // ADDR function. class Addr_expression : public Section_expression { public: Addr_expression(const char* section_name, size_t section_name_len) : Section_expression(section_name, section_name_len) { } protected: uint64_t value_from_output_section(const Expression_eval_info* eei, Output_section* os) { *eei->result_section_pointer = os; return os->address(); } uint64_t value_from_script_output_section(uint64_t address, uint64_t, uint64_t, uint64_t) { return address; } const char* function_name() const { return "ADDR"; } }; extern "C" Expression* script_exp_function_addr(const char* section_name, size_t section_name_len) { return new Addr_expression(section_name, section_name_len); } // ALIGNOF. class Alignof_expression : public Section_expression { public: Alignof_expression(const char* section_name, size_t section_name_len) : Section_expression(section_name, section_name_len) { } protected: uint64_t value_from_output_section(const Expression_eval_info*, Output_section* os) { return os->addralign(); } uint64_t value_from_script_output_section(uint64_t, uint64_t, uint64_t addralign, uint64_t) { return addralign; } const char* function_name() const { return "ALIGNOF"; } }; extern "C" Expression* script_exp_function_alignof(const char* section_name, size_t section_name_len) { return new Alignof_expression(section_name, section_name_len); } // CONSTANT. It would be nice if we could simply evaluate this // immediately and return an Integer_expression, but unfortunately we // don't know the target. class Constant_expression : public Expression { public: Constant_expression(const char* name, size_t length); uint64_t value(const Expression_eval_info*); void print(FILE* f) const; private: enum Constant_function { CONSTANT_MAXPAGESIZE, CONSTANT_COMMONPAGESIZE }; Constant_function function_; }; Constant_expression::Constant_expression(const char* name, size_t length) { if (length == 11 && strncmp(name, "MAXPAGESIZE", length) == 0) this->function_ = CONSTANT_MAXPAGESIZE; else if (length == 14 && strncmp(name, "COMMONPAGESIZE", length) == 0) this->function_ = CONSTANT_COMMONPAGESIZE; else { std::string s(name, length); gold_error(_("unknown constant %s"), s.c_str()); this->function_ = CONSTANT_MAXPAGESIZE; } } uint64_t Constant_expression::value(const Expression_eval_info*) { switch (this->function_) { case CONSTANT_MAXPAGESIZE: return parameters->target().abi_pagesize(); case CONSTANT_COMMONPAGESIZE: return parameters->target().common_pagesize(); default: gold_unreachable(); } } void Constant_expression::print(FILE* f) const { const char* name; switch (this->function_) { case CONSTANT_MAXPAGESIZE: name = "MAXPAGESIZE"; break; case CONSTANT_COMMONPAGESIZE: name = "COMMONPAGESIZE"; break; default: gold_unreachable(); } fprintf(f, "CONSTANT(%s)", name); } extern "C" Expression* script_exp_function_constant(const char* name, size_t length) { return new Constant_expression(name, length); } // DATA_SEGMENT_ALIGN. FIXME: we don't implement this; we always fall // back to the general case. extern "C" Expression* script_exp_function_data_segment_align(Expression* left, Expression*) { Expression* e1 = script_exp_function_align(script_exp_string(".", 1), left); Expression* e2 = script_exp_binary_sub(left, script_exp_integer(1)); Expression* e3 = script_exp_binary_bitwise_and(script_exp_string(".", 1), e2); return script_exp_binary_add(e1, e3); } // DATA_SEGMENT_RELRO. FIXME: This is not implemented. extern "C" Expression* script_exp_function_data_segment_relro_end(Expression*, Expression* right) { return right; } // DATA_SEGMENT_END. FIXME: This is not implemented. extern "C" Expression* script_exp_function_data_segment_end(Expression* val) { return val; } // DEFINED function. class Defined_expression : public Expression { public: Defined_expression(const char* symbol_name, size_t symbol_name_len) : symbol_name_(symbol_name, symbol_name_len) { } uint64_t value(const Expression_eval_info* eei) { Symbol* sym = eei->symtab->lookup(this->symbol_name_.c_str()); return sym != NULL && sym->is_defined(); } void print(FILE* f) const { fprintf(f, "DEFINED(%s)", this->symbol_name_.c_str()); } private: std::string symbol_name_; }; extern "C" Expression* script_exp_function_defined(const char* symbol_name, size_t symbol_name_len) { return new Defined_expression(symbol_name, symbol_name_len); } // LOADADDR function class Loadaddr_expression : public Section_expression { public: Loadaddr_expression(const char* section_name, size_t section_name_len) : Section_expression(section_name, section_name_len) { } protected: uint64_t value_from_output_section(const Expression_eval_info* eei, Output_section* os) { if (os->has_load_address()) return os->load_address(); else { *eei->result_section_pointer = os; return os->address(); } } uint64_t value_from_script_output_section(uint64_t, uint64_t load_address, uint64_t, uint64_t) { return load_address; } const char* function_name() const { return "LOADADDR"; } }; extern "C" Expression* script_exp_function_loadaddr(const char* section_name, size_t section_name_len) { return new Loadaddr_expression(section_name, section_name_len); } // SIZEOF function class Sizeof_expression : public Section_expression { public: Sizeof_expression(const char* section_name, size_t section_name_len) : Section_expression(section_name, section_name_len) { } protected: uint64_t value_from_output_section(const Expression_eval_info*, Output_section* os) { // We can not use data_size here, as the size of the section may // not have been finalized. Instead we get whatever the current // size is. This will work correctly for backward references in // linker scripts. return os->current_data_size(); } uint64_t value_from_script_output_section(uint64_t, uint64_t, uint64_t, uint64_t size) { return size; } const char* function_name() const { return "SIZEOF"; } }; extern "C" Expression* script_exp_function_sizeof(const char* section_name, size_t section_name_len) { return new Sizeof_expression(section_name, section_name_len); } // SIZEOF_HEADERS. class Sizeof_headers_expression : public Expression { public: Sizeof_headers_expression() { } uint64_t value(const Expression_eval_info*); void print(FILE* f) const { fprintf(f, "SIZEOF_HEADERS"); } }; uint64_t Sizeof_headers_expression::value(const Expression_eval_info* eei) { unsigned int ehdr_size; unsigned int phdr_size; if (parameters->target().get_size() == 32) { ehdr_size = elfcpp::Elf_sizes<32>::ehdr_size; phdr_size = elfcpp::Elf_sizes<32>::phdr_size; } else if (parameters->target().get_size() == 64) { ehdr_size = elfcpp::Elf_sizes<64>::ehdr_size; phdr_size = elfcpp::Elf_sizes<64>::phdr_size; } else gold_unreachable(); return ehdr_size + phdr_size * eei->layout->expected_segment_count(); } extern "C" Expression* script_exp_function_sizeof_headers() { return new Sizeof_headers_expression(); } // In the GNU linker SEGMENT_START basically returns the value for // -Ttext, -Tdata, or -Tbss. We could implement this by copying the // values from General_options to Parameters. But I doubt that // anybody actually uses it. The point of it for the GNU linker was // because -Ttext set the address of the .text section rather than the // text segment. In gold -Ttext sets the text segment address anyhow. extern "C" Expression* script_exp_function_segment_start(const char*, size_t, Expression*) { gold_fatal(_("SEGMENT_START not implemented")); } // Functions for memory regions. These can not be implemented unless // and until we implement memory regions. 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")); } } // End namespace gold.