X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=gold%2Fexpression.cc;h=b0bd875add2144c2b7eaa9bffc64d8c77521c866;hb=50838d1be72ddd30e0b5f081933482424ae5a6b0;hp=1cc646f8538e3a1abbd698af13ae7b71883b9778;hpb=3edc73f245b7f714af35f98ccc69212358d7a594;p=deliverable%2Fbinutils-gdb.git diff --git a/gold/expression.cc b/gold/expression.cc index 1cc646f853..b0bd875add 100644 --- a/gold/expression.cc +++ b/gold/expression.cc @@ -1,6 +1,6 @@ // expression.cc -- expressions in linker scripts for gold -// Copyright 2006, 2007, 2008 Free Software Foundation, Inc. +// Copyright (C) 2006-2020 Free Software Foundation, Inc. // Written by Ian Lance Taylor . // This file is part of gold. @@ -54,6 +54,8 @@ struct Expression::Expression_eval_info 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; @@ -64,26 +66,44 @@ struct Expression::Expression_eval_info Output_section* dot_section; // Points to where the section of the result should be stored. Output_section** result_section_pointer; + // Pointer to where the alignment of the result should be stored. + uint64_t* result_alignment_pointer; + // Pointer to where the type of the symbol on the RHS should be stored. + elfcpp::STT* type_pointer; + // Pointer to where the visibility of the symbol on the RHS should be stored. + elfcpp::STV* vis_pointer; + // Pointer to where the rest of the symbol's st_other field should be stored. + unsigned char* nonvis_pointer; + // Whether the value is valid. In Symbol_assignment::set_if_absolute, we + // may be trying to evaluate the address of a section whose address is not + // yet finalized, and we need to fail the evaluation gracefully. + bool *is_valid_pointer; }; // Evaluate an expression. uint64_t -Expression::eval(const Symbol_table* symtab, const Layout* layout) +Expression::eval(const Symbol_table* symtab, const Layout* layout, + bool check_assertions) { - Output_section* dummy; - return this->eval_maybe_dot(symtab, layout, false, 0, NULL, &dummy); + return this->eval_maybe_dot(symtab, layout, check_assertions, false, 0, + NULL, NULL, NULL, NULL, NULL, NULL, false, NULL); } // Evaluate an expression which may refer to the dot symbol. uint64_t Expression::eval_with_dot(const Symbol_table* symtab, const Layout* layout, - uint64_t dot_value, Output_section* dot_section, - Output_section** result_section_pointer) + bool check_assertions, uint64_t dot_value, + Output_section* dot_section, + Output_section** result_section_pointer, + uint64_t* result_alignment_pointer, + bool is_section_dot_assignment) { - return this->eval_maybe_dot(symtab, layout, true, dot_value, dot_section, - result_section_pointer); + return this->eval_maybe_dot(symtab, layout, check_assertions, true, + dot_value, dot_section, result_section_pointer, + result_alignment_pointer, NULL, NULL, NULL, + is_section_dot_assignment, NULL); } // Evaluate an expression which may or may not refer to the dot @@ -91,23 +111,59 @@ Expression::eval_with_dot(const Symbol_table* symtab, const Layout* layout, uint64_t Expression::eval_maybe_dot(const Symbol_table* symtab, const Layout* layout, - bool is_dot_available, uint64_t dot_value, - Output_section* dot_section, - Output_section** result_section_pointer) + bool check_assertions, bool is_dot_available, + uint64_t dot_value, Output_section* dot_section, + Output_section** result_section_pointer, + uint64_t* result_alignment_pointer, + elfcpp::STT* type_pointer, + elfcpp::STV* vis_pointer, + unsigned char* nonvis_pointer, + bool is_section_dot_assignment, + bool* is_valid_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; + // if we find a section-relative reference. + if (result_section_pointer != NULL) + *result_section_pointer = NULL; eei.result_section_pointer = result_section_pointer; - return this->value(&eei); + // For symbol=symbol assignments, we need to track the type, visibility, + // and remaining st_other bits. + eei.type_pointer = type_pointer; + eei.vis_pointer = vis_pointer; + eei.nonvis_pointer = nonvis_pointer; + + eei.result_alignment_pointer = result_alignment_pointer; + + // Assume the value is valid until we try to evaluate an expression + // that can't be evaluated yet. + bool is_valid = true; + eei.is_valid_pointer = &is_valid; + + uint64_t val = this->value(&eei); + + if (is_valid_pointer != NULL) + *is_valid_pointer = is_valid; + else + gold_assert(is_valid); + + // If this is an assignment to dot within a section, and the value + // is absolute, treat it as a section-relative offset. + if (is_section_dot_assignment && *result_section_pointer == NULL) + { + gold_assert(dot_section != NULL); + val += dot_section->address(); + *result_section_pointer = dot_section; + } + return val; } // A number. @@ -149,6 +205,14 @@ class Symbol_expression : public Expression uint64_t value(const Expression_eval_info*); + void + set_expr_sym_in_real_elf(Symbol_table* symtab) const + { + Symbol* sym = symtab->lookup(this->name_.c_str()); + if (sym != NULL) + sym->set_in_real_elf(); + } + void print(FILE* f) const { fprintf(f, "%s", this->name_.c_str()); } @@ -168,11 +232,18 @@ Symbol_expression::value(const Expression_eval_info* eei) return 0; } - *eei->result_section_pointer = sym->output_section(); + if (eei->result_section_pointer != NULL) + *eei->result_section_pointer = sym->output_section(); + if (eei->type_pointer != NULL) + *eei->type_pointer = sym->type(); + if (eei->vis_pointer != NULL) + *eei->vis_pointer = sym->visibility(); + if (eei->nonvis_pointer != NULL) + *eei->nonvis_pointer = sym->nonvis(); - if (parameters->get_size() == 32) + if (parameters->target().get_size() == 32) return eei->symtab->get_sized_symbol<32>(sym)->value(); - else if (parameters->get_size() == 64) + else if (parameters->target().get_size() == 64) return eei->symtab->get_sized_symbol<64>(sym)->value(); else gold_unreachable(); @@ -204,7 +275,8 @@ Dot_expression::value(const Expression_eval_info* eei) "SECTIONS clause")); return 0; } - *eei->result_section_pointer = eei->dot_section; + if (eei->result_section_pointer != NULL) + *eei->result_section_pointer = eei->dot_section; return eei->dot_value; } @@ -237,16 +309,27 @@ class Unary_expression : public Expression 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); + arg_section_pointer, + eei->result_alignment_pointer, + NULL, + NULL, + NULL, + false, + eei->is_valid_pointer); } void arg_print(FILE* f) const { this->arg_->print(f); } + void + set_expr_sym_in_real_elf(Symbol_table* symtab) const + { return this->arg_->set_expr_sym_in_real_elf(symtab); } + private: Expression* arg_; }; @@ -267,7 +350,7 @@ class Unary_expression : public Expression { \ Output_section* arg_section; \ uint64_t ret = OPERATOR this->arg_value(eei, &arg_section); \ - if (arg_section != NULL && parameters->output_is_object()) \ + if (arg_section != NULL && parameters->options().relocatable()) \ gold_warning(_("unary " #NAME " applied to section " \ "relative value")); \ return ret; \ @@ -310,24 +393,40 @@ class Binary_expression : public Expression protected: uint64_t left_value(const Expression_eval_info* eei, - Output_section** section_pointer) const + Output_section** section_pointer, + uint64_t* alignment_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); + section_pointer, + alignment_pointer, + NULL, + NULL, + NULL, + false, + eei->is_valid_pointer); } uint64_t right_value(const Expression_eval_info* eei, - Output_section** section_pointer) const + Output_section** section_pointer, + uint64_t* alignment_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); + section_pointer, + alignment_pointer, + NULL, + NULL, + NULL, + false, + eei->is_valid_pointer); } void @@ -341,7 +440,7 @@ class Binary_expression : public Expression // This is a call to function FUNCTION_NAME. Print it. This is for // debugging. void - print_function(FILE* f, const char *function_name) const + print_function(FILE* f, const char* function_name) const { fprintf(f, "%s(", function_name); this->left_print(f); @@ -350,6 +449,13 @@ class Binary_expression : public Expression fprintf(f, ")"); } + void + set_expr_sym_in_real_elf(Symbol_table* symtab) const + { + this->left_->set_expr_sym_in_real_elf(symtab); + this->right_->set_expr_sym_in_real_elf(symtab); + } + private: Expression* left_; Expression* right_; @@ -376,18 +482,34 @@ class Binary_expression : public Expression value(const Expression_eval_info* eei) \ { \ Output_section* left_section; \ - uint64_t left = this->left_value(eei, &left_section); \ + uint64_t left_alignment = 0; \ + uint64_t left = this->left_value(eei, &left_section, \ + &left_alignment); \ Output_section* right_section; \ - uint64_t right = this->right_value(eei, &right_section); \ + uint64_t right_alignment = 0; \ + uint64_t right = this->right_value(eei, &right_section, \ + &right_alignment); \ if (KEEP_RIGHT && left_section == NULL && right_section != NULL) \ - *eei->result_section_pointer = right_section; \ + { \ + if (eei->result_section_pointer != NULL) \ + *eei->result_section_pointer = right_section; \ + if (eei->result_alignment_pointer != NULL \ + && right_alignment > *eei->result_alignment_pointer) \ + *eei->result_alignment_pointer = right_alignment; \ + } \ else if (KEEP_LEFT \ && left_section != NULL \ && right_section == NULL) \ - *eei->result_section_pointer = left_section; \ + { \ + if (eei->result_section_pointer != NULL) \ + *eei->result_section_pointer = left_section; \ + if (eei->result_alignment_pointer != NULL \ + && left_alignment > *eei->result_alignment_pointer) \ + *eei->result_alignment_pointer = left_alignment; \ + } \ else if ((WARN || left_section != right_section) \ && (left_section != NULL || right_section != NULL) \ - && parameters->output_is_object()) \ + && parameters->options().relocatable()) \ gold_warning(_("binary " #NAME " applied to section " \ "relative value")); \ if (IS_DIV && right == 0) \ @@ -456,32 +578,55 @@ class Trinary_expression : public Expression 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); + section_pointer, + NULL, + NULL, + NULL, + NULL, + false, + eei->is_valid_pointer); } uint64_t arg2_value(const Expression_eval_info* eei, - Output_section** section_pointer) const + Output_section** section_pointer, + uint64_t* alignment_pointer) const { - return this->arg1_->eval_maybe_dot(eei->symtab, eei->layout, + return this->arg2_->eval_maybe_dot(eei->symtab, eei->layout, + eei->check_assertions, eei->is_dot_available, eei->dot_value, eei->dot_section, - section_pointer); + section_pointer, + alignment_pointer, + NULL, + NULL, + NULL, + false, + eei->is_valid_pointer); } uint64_t arg3_value(const Expression_eval_info* eei, - Output_section** section_pointer) const + Output_section** section_pointer, + uint64_t* alignment_pointer) const { - return this->arg1_->eval_maybe_dot(eei->symtab, eei->layout, + return this->arg3_->eval_maybe_dot(eei->symtab, eei->layout, + eei->check_assertions, eei->is_dot_available, eei->dot_value, eei->dot_section, - section_pointer); + section_pointer, + alignment_pointer, + NULL, + NULL, + NULL, + false, + eei->is_valid_pointer); } void @@ -496,6 +641,14 @@ class Trinary_expression : public Expression arg3_print(FILE* f) const { this->arg3_->print(f); } + void + set_expr_sym_in_real_elf(Symbol_table* symtab) const + { + this->arg1_->set_expr_sym_in_real_elf(symtab); + this->arg2_->set_expr_sym_in_real_elf(symtab); + this->arg3_->set_expr_sym_in_real_elf(symtab); + } + private: Expression* arg1_; Expression* arg2_; @@ -517,8 +670,10 @@ class Trinary_cond : public Trinary_expression 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)); + ? this->arg2_value(eei, eei->result_section_pointer, + eei->result_alignment_pointer) + : this->arg3_value(eei, eei->result_section_pointer, + eei->result_alignment_pointer)); } void @@ -553,14 +708,30 @@ class Max_expression : public Binary_expression value(const Expression_eval_info* eei) { Output_section* left_section; - uint64_t left = this->left_value(eei, &left_section); + uint64_t left_alignment; + uint64_t left = this->left_value(eei, &left_section, &left_alignment); Output_section* right_section; - uint64_t right = this->right_value(eei, &right_section); + uint64_t right_alignment; + uint64_t right = this->right_value(eei, &right_section, &right_alignment); if (left_section == right_section) - *eei->result_section_pointer = left_section; + { + if (eei->result_section_pointer != NULL) + *eei->result_section_pointer = left_section; + } else if ((left_section != NULL || right_section != NULL) - && parameters->output_is_object()) + && parameters->options().relocatable()) gold_warning(_("max applied to section relative value")); + if (eei->result_alignment_pointer != NULL) + { + uint64_t ra = *eei->result_alignment_pointer; + if (left > right) + ra = std::max(ra, left_alignment); + else if (right > left) + ra = std::max(ra, right_alignment); + else + ra = std::max(ra, std::max(left_alignment, right_alignment)); + *eei->result_alignment_pointer = ra; + } return std::max(left, right); } @@ -588,14 +759,30 @@ class Min_expression : public Binary_expression value(const Expression_eval_info* eei) { Output_section* left_section; - uint64_t left = this->left_value(eei, &left_section); + uint64_t left_alignment; + uint64_t left = this->left_value(eei, &left_section, &left_alignment); Output_section* right_section; - uint64_t right = this->right_value(eei, &right_section); + uint64_t right_alignment; + uint64_t right = this->right_value(eei, &right_section, &right_alignment); if (left_section == right_section) - *eei->result_section_pointer = left_section; + { + if (eei->result_section_pointer != NULL) + *eei->result_section_pointer = left_section; + } else if ((left_section != NULL || right_section != NULL) - && parameters->output_is_object()) + && parameters->options().relocatable()) gold_warning(_("min applied to section relative value")); + if (eei->result_alignment_pointer != NULL) + { + uint64_t ra = *eei->result_alignment_pointer; + if (left < right) + ra = std::max(ra, left_alignment); + else if (right < left) + ra = std::max(ra, right_alignment); + else + ra = std::max(ra, std::max(left_alignment, right_alignment)); + *eei->result_alignment_pointer = ra; + } return std::min(left, right); } @@ -633,6 +820,11 @@ class Section_expression : public Expression 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; @@ -646,14 +838,28 @@ 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) + 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()) { - gold_error("%s called on nonexistent output section '%s'", - this->function_name(), section_name); - return 0; + 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); } - return this->value_from_output_section(eei, os); + gold_error("%s called on nonexistent output section '%s'", + this->function_name(), section_name); + return 0; } // ABSOLUTE function. @@ -668,10 +874,10 @@ class Absolute_expression : public Unary_expression uint64_t value(const Expression_eval_info* eei) { - Output_section* dummy; - uint64_t ret = this->arg_value(eei, &dummy); + uint64_t ret = this->arg_value(eei, NULL); // Force the value to be absolute. - *eei->result_section_pointer = NULL; + if (eei->result_section_pointer != NULL) + *eei->result_section_pointer = NULL; return ret; } @@ -703,12 +909,21 @@ class Align_expression : public Binary_expression value(const Expression_eval_info* eei) { Output_section* align_section; - uint64_t align = this->right_value(eei, &align_section); + uint64_t align = this->right_value(eei, &align_section, NULL); if (align_section != NULL - && parameters->output_is_object()) + && parameters->options().relocatable()) gold_warning(_("aligning to section relative value")); - uint64_t value = this->left_value(eei, eei->result_section_pointer); + if (eei->result_alignment_pointer != NULL + && align > *eei->result_alignment_pointer) + { + uint64_t a = align; + while ((a & (a - 1)) != 0) + a &= a - 1; + *eei->result_alignment_pointer = a; + } + + uint64_t value = this->left_value(eei, eei->result_section_pointer, NULL); if (align <= 1) return value; return ((value + align - 1) / align) * align; @@ -738,7 +953,7 @@ class Assert_expression : public Unary_expression value(const Expression_eval_info* eei) { uint64_t value = this->arg_value(eei, eei->result_section_pointer); - if (!value) + if (!value && eei->check_assertions) gold_error("%s", this->message_.c_str()); return value; } @@ -776,10 +991,19 @@ class Addr_expression : public Section_expression value_from_output_section(const Expression_eval_info* eei, Output_section* os) { - *eei->result_section_pointer = os; - return os->address(); + if (eei->result_section_pointer != NULL) + *eei->result_section_pointer = os; + if (os->is_address_valid()) + return os->address(); + *eei->is_valid_pointer = false; + return 0; } + 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"; } @@ -806,6 +1030,11 @@ class Alignof_expression : public Section_expression 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"; } @@ -862,9 +1091,9 @@ Constant_expression::value(const Expression_eval_info*) switch (this->function_) { case CONSTANT_MAXPAGESIZE: - return parameters->target()->abi_pagesize(); + return parameters->target().abi_pagesize(); case CONSTANT_COMMONPAGESIZE: - return parameters->target()->common_pagesize(); + return parameters->target().common_pagesize(); default: gold_unreachable(); } @@ -971,11 +1200,17 @@ class Loadaddr_expression : public Section_expression return os->load_address(); else { - *eei->result_section_pointer = os; + if (eei->result_section_pointer != NULL) + *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"; } @@ -1008,6 +1243,11 @@ class Sizeof_expression : public Section_expression 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"; } @@ -1040,12 +1280,12 @@ Sizeof_headers_expression::value(const Expression_eval_info* eei) { unsigned int ehdr_size; unsigned int phdr_size; - if (parameters->get_size() == 32) + 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->get_size() == 64) + else if (parameters->target().get_size() == 64) { ehdr_size = elfcpp::Elf_sizes<64>::ehdr_size; phdr_size = elfcpp::Elf_sizes<64>::phdr_size; @@ -1062,32 +1302,62 @@ 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. +// SEGMENT_START. -extern "C" Expression* -script_exp_function_segment_start(const char*, size_t, Expression*) +class Segment_start_expression : public Unary_expression { - gold_fatal(_("SEGMENT_START not implemented")); -} + public: + Segment_start_expression(const char* segment_name, size_t segment_name_len, + Expression* default_value) + : Unary_expression(default_value), + segment_name_(segment_name, segment_name_len) + { } -// Functions for memory regions. These can not be implemented unless -// and until we implement memory regions. + uint64_t + value(const Expression_eval_info*); -extern "C" Expression* -script_exp_function_origin(const char*, size_t) + void + print(FILE* f) const + { + fprintf(f, "SEGMENT_START(\"%s\", ", this->segment_name_.c_str()); + this->arg_print(f); + fprintf(f, ")"); + } + + private: + std::string segment_name_; +}; + +uint64_t +Segment_start_expression::value(const Expression_eval_info* eei) { - gold_fatal(_("ORIGIN not implemented")); + // Check for command line overrides. + if (parameters->options().user_set_Ttext() + && this->segment_name_ == ".text") + return parameters->options().Ttext(); + else if (parameters->options().user_set_Tdata() + && this->segment_name_ == ".data") + return parameters->options().Tdata(); + else if (parameters->options().user_set_Tbss() + && this->segment_name_ == ".bss") + return parameters->options().Tbss(); + else + { + uint64_t ret = this->arg_value(eei, NULL); + // Force the value to be absolute. + if (eei->result_section_pointer != NULL) + *eei->result_section_pointer = NULL; + return ret; + } } extern "C" Expression* -script_exp_function_length(const char*, size_t) +script_exp_function_segment_start(const char* segment_name, + size_t segment_name_len, + Expression* default_value) { - gold_fatal(_("LENGTH not implemented")); + return new Segment_start_expression(segment_name, segment_name_len, + default_value); } } // End namespace gold.