diff --git a/gold/expression.cc b/gold/expression.cc index d57b45cb39..d7536016b0 100644 --- a/gold/expression.cc +++ b/gold/expression.cc @@ -57,13 +57,13 @@ struct Expression::Expression_eval_info // Whether expressions can refer to the dot symbol. The dot symbol // is only available within a SECTIONS clause. bool is_dot_available; - // Whether the dot symbol currently has a value. - bool dot_has_value; // The current value of the dot symbol. uint64_t dot_value; - // Points to the IS_ABSOLUTE variable, which is set to false if the - // expression uses a value which is not absolute. - bool* is_absolute; + // 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. @@ -71,19 +71,19 @@ struct Expression::Expression_eval_info uint64_t Expression::eval(const Symbol_table* symtab, const Layout* layout) { - bool dummy; - return this->eval_maybe_dot(symtab, layout, false, false, 0, &dummy); + Output_section* dummy; + return this->eval_maybe_dot(symtab, layout, 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 dot_has_value, uint64_t dot_value, - bool* is_absolute) + uint64_t dot_value, Output_section* dot_section, + Output_section** result_section_pointer) { - return this->eval_maybe_dot(symtab, layout, true, dot_has_value, dot_value, - is_absolute); + return this->eval_maybe_dot(symtab, layout, true, dot_value, dot_section, + result_section_pointer); } // Evaluate an expression which may or may not refer to the dot @@ -91,20 +91,21 @@ 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, bool dot_has_value, - uint64_t dot_value, bool* is_absolute) + 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.is_dot_available = is_dot_available; - eei.dot_has_value = dot_has_value; eei.dot_value = dot_value; + eei.dot_section = dot_section; - // We assume the value is absolute, and only set this to false if we - // find a section relative reference. - *is_absolute = true; - eei.is_absolute = is_absolute; + // 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); } @@ -167,13 +168,7 @@ Symbol_expression::value(const Expression_eval_info* eei) return 0; } - // If this symbol does not have an absolute value, then the whole - // expression does not have an absolute value. This is not strictly - // accurate: the subtraction of two symbols in the same section is - // absolute. This is unlikely to matter in practice, as this value - // is only used for error checking. - if (!sym->value_is_absolute()) - *eei->is_absolute = false; + *eei->result_section_pointer = sym->output_section(); if (parameters->get_size() == 32) return eei->symtab->get_sized_symbol<32>(sym)->value(); @@ -209,12 +204,7 @@ Dot_expression::value(const Expression_eval_info* eei) "SECTIONS clause")); return 0; } - else if (!eei->dot_has_value) - { - gold_error(_("invalid reference to dot symbol before " - "it has been given a value")); - return 0; - } + *eei->result_section_pointer = eei->dot_section; return eei->dot_value; } @@ -243,8 +233,15 @@ class Unary_expression : public Expression protected: uint64_t - arg_value(const Expression_eval_info* eei) const - { return this->arg_->value(eei); } + arg_value(const Expression_eval_info* eei, + Output_section** arg_section_pointer) const + { + return this->arg_->eval_maybe_dot(eei->symtab, eei->layout, + eei->is_dot_available, + eei->dot_value, + eei->dot_section, + arg_section_pointer); + } void arg_print(FILE* f) const @@ -257,31 +254,38 @@ class Unary_expression : public Expression // 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); } \ - \ - 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); \ +#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->output_is_object()) \ + 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, -) @@ -305,12 +309,26 @@ class Binary_expression : public Expression protected: uint64_t - left_value(const Expression_eval_info* eei) const - { return this->left_->value(eei); } + left_value(const Expression_eval_info* eei, + Output_section** section_pointer) const + { + return this->left_->eval_maybe_dot(eei->symtab, eei->layout, + eei->is_dot_available, + eei->dot_value, + eei->dot_section, + section_pointer); + } uint64_t - right_value(const Expression_eval_info* eei) const - { return this->right_->value(eei); } + right_value(const Expression_eval_info* eei, + Output_section** section_pointer) const + { + return this->right_->eval_maybe_dot(eei->symtab, eei->layout, + eei->is_dot_available, + eei->dot_value, + eei->dot_section, + section_pointer); + } void left_print(FILE* f) const @@ -338,9 +356,15 @@ class Binary_expression : public Expression }; // Handle binary operators. We use a preprocessor macro as a hack to -// capture the C operator. +// 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) \ +#define BINARY_EXPRESSION(NAME, OPERATOR, KEEP_LEFT, KEEP_RIGHT, IS_DIV, WARN) \ class Binary_ ## NAME : public Binary_expression \ { \ public: \ @@ -351,8 +375,27 @@ class Binary_expression : public Expression uint64_t \ value(const Expression_eval_info* eei) \ { \ - return (this->left_value(eei) \ - OPERATOR this->right_value(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->output_is_object()) \ + 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 \ @@ -372,24 +415,24 @@ class Binary_expression : public Expression 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, ||) +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. @@ -409,16 +452,37 @@ class Trinary_expression : public Expression protected: uint64_t - arg1_value(const Expression_eval_info* eei) const - { return this->arg1_->value(eei); } + arg1_value(const Expression_eval_info* eei, + Output_section** section_pointer) const + { + return this->arg1_->eval_maybe_dot(eei->symtab, eei->layout, + eei->is_dot_available, + eei->dot_value, + eei->dot_section, + section_pointer); + } uint64_t - arg2_value(const Expression_eval_info* eei) const - { return this->arg2_->value(eei); } + arg2_value(const Expression_eval_info* eei, + Output_section** section_pointer) const + { + return this->arg1_->eval_maybe_dot(eei->symtab, eei->layout, + eei->is_dot_available, + eei->dot_value, + eei->dot_section, + section_pointer); + } uint64_t - arg3_value(const Expression_eval_info* eei) const - { return this->arg3_->value(eei); } + arg3_value(const Expression_eval_info* eei, + Output_section** section_pointer) const + { + return this->arg1_->eval_maybe_dot(eei->symtab, eei->layout, + eei->is_dot_available, + eei->dot_value, + eei->dot_section, + section_pointer); + } void arg1_print(FILE* f) const @@ -450,9 +514,11 @@ class Trinary_cond : public Trinary_expression uint64_t value(const Expression_eval_info* eei) { - return (this->arg1_value(eei) - ? this->arg2_value(eei) - : this->arg3_value(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 @@ -485,7 +551,18 @@ class Max_expression : public Binary_expression uint64_t value(const Expression_eval_info* eei) - { return std::max(this->left_value(eei), this->right_value(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->output_is_object()) + gold_warning(_("max applied to section relative value")); + return std::max(left, right); + } void print(FILE* f) const @@ -509,7 +586,18 @@ class Min_expression : public Binary_expression uint64_t value(const Expression_eval_info* eei) - { return std::min(this->left_value(eei), this->right_value(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->output_is_object()) + gold_warning(_("min applied to section relative value")); + return std::min(left, right); + } void print(FILE* f) const @@ -534,8 +622,13 @@ class Align_expression : public Binary_expression uint64_t value(const Expression_eval_info* eei) { - uint64_t align = this->right_value(eei); - uint64_t value = this->left_value(eei); + Output_section* align_section; + uint64_t align = this->right_value(eei, &align_section); + if (align_section != NULL + && parameters->output_is_object()) + 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; @@ -564,7 +657,7 @@ class Assert_expression : public Unary_expression uint64_t value(const Expression_eval_info* eei) { - uint64_t value = this->arg_value(eei); + uint64_t value = this->arg_value(eei, eei->result_section_pointer); if (!value) gold_error("%s", this->message_.c_str()); return value; @@ -621,8 +714,7 @@ Addr_expression::value(const Expression_eval_info* eei) return 0; } - // Note that the address of a section is an absolute address, and we - // should not clear *EEI->IS_ABSOLUTE here. + *eei->result_section_pointer = os; return os->address(); } diff --git a/gold/output.h b/gold/output.h index 5e68e7c294..fbfdb25626 100644 --- a/gold/output.h +++ b/gold/output.h @@ -131,6 +131,11 @@ class Output_data is_section_flag_set(elfcpp::Elf_Xword shf) const { return this->do_is_section_flag_set(shf); } + // Return the output section that this goes in, if there is one. + Output_section* + output_section() + { return this->do_output_section(); } + // Return the output section index, if there is an output section. unsigned int out_shndx() const @@ -273,6 +278,11 @@ class Output_data do_is_section_flag_set(elfcpp::Elf_Xword) const { return false; } + // Return the output section, if there is one. + virtual Output_section* + do_output_section() + { return NULL; } + // Return the output section index, if there is an output section. virtual unsigned int do_out_shndx() const @@ -574,6 +584,11 @@ class Output_section_data : public Output_data do_addralign() const { return this->addralign_; } + // Return the output section. + Output_section* + do_output_section() + { return this->output_section_; } + // Return the section index of the output section. unsigned int do_out_shndx() const; @@ -585,7 +600,7 @@ class Output_section_data : public Output_data private: // The output section for this section. - const Output_section* output_section_; + Output_section* output_section_; // The required alignment. uint64_t addralign_; }; @@ -1903,6 +1918,11 @@ class Output_section : public Output_data print_merge_stats(); protected: + // Return the output section--i.e., the object itself. + Output_section* + do_output_section() + { return this; } + // Return the section index in the output file. unsigned int do_out_shndx() const diff --git a/gold/script-sections.cc b/gold/script-sections.cc index 7f51e8bfd9..341599c5b4 100644 --- a/gold/script-sections.cc +++ b/gold/script-sections.cc @@ -61,7 +61,7 @@ class Sections_element // Finalize symbols and check assertions. virtual void - finalize_symbols(Symbol_table*, const Layout*, bool*, uint64_t*) + finalize_symbols(Symbol_table*, const Layout*, uint64_t*) { } // Return the output section name to use for an input file name and @@ -80,7 +80,7 @@ class Sections_element // Set section addresses. This includes applying assignments if the // the expression is an absolute value. virtual void - set_section_addresses(Symbol_table*, Layout*, bool*, uint64_t*) + set_section_addresses(Symbol_table*, Layout*, uint64_t*) { } // Check a constraint (ONLY_IF_RO, etc.) on an output section. If @@ -129,10 +129,9 @@ class Sections_element_assignment : public Sections_element // Finalize the symbol. void finalize_symbols(Symbol_table* symtab, const Layout* layout, - bool* dot_has_value, uint64_t* dot_value) + uint64_t* dot_value) { - this->assignment_.finalize_with_dot(symtab, layout, *dot_has_value, - *dot_value); + this->assignment_.finalize_with_dot(symtab, layout, *dot_value, NULL); } // Set the section address. There is no section here, but if the @@ -140,10 +139,9 @@ class Sections_element_assignment : public Sections_element // absolute symbols when setting dot. void set_section_addresses(Symbol_table* symtab, Layout* layout, - bool* dot_has_value, uint64_t* dot_value) + uint64_t* dot_value) { - this->assignment_.set_if_absolute(symtab, layout, true, *dot_has_value, - *dot_value); + this->assignment_.set_if_absolute(symtab, layout, true, *dot_value); } // Print for debugging. @@ -171,25 +169,24 @@ class Sections_element_dot_assignment : public Sections_element // Finalize the symbol. void finalize_symbols(Symbol_table* symtab, const Layout* layout, - bool* dot_has_value, uint64_t* dot_value) + uint64_t* dot_value) { - bool dummy; - *dot_value = this->val_->eval_with_dot(symtab, layout, *dot_has_value, - *dot_value, &dummy); - *dot_has_value = true; + // We ignore the section of the result because outside of an + // output section definition the dot symbol is always considered + // to be absolute. + Output_section* dummy; + *dot_value = this->val_->eval_with_dot(symtab, layout, *dot_value, + NULL, &dummy); } // Update the dot symbol while setting section addresses. void set_section_addresses(Symbol_table* symtab, Layout* layout, - bool* dot_has_value, uint64_t* dot_value) + uint64_t* dot_value) { - bool is_absolute; - *dot_value = this->val_->eval_with_dot(symtab, layout, *dot_has_value, - *dot_value, &is_absolute); - if (!is_absolute) - gold_error(_("dot set to non-absolute value")); - *dot_has_value = true; + Output_section* dummy; + *dot_value = this->val_->eval_with_dot(symtab, layout, *dot_value, + NULL, &dummy); } // Print for debugging. @@ -217,8 +214,7 @@ class Sections_element_assertion : public Sections_element // Check the assertion. void - finalize_symbols(Symbol_table* symtab, const Layout* layout, bool*, - uint64_t*) + finalize_symbols(Symbol_table* symtab, const Layout* layout, uint64_t*) { this->assertion_.check(symtab, layout); } // Print for debugging. @@ -254,7 +250,7 @@ class Output_section_element // Finalize symbols and check assertions. virtual void - finalize_symbols(Symbol_table*, const Layout*, bool*, uint64_t*) + finalize_symbols(Symbol_table*, const Layout*, uint64_t*, Output_section**) { } // Return whether this element matches FILE_NAME and SECTION_NAME. @@ -267,7 +263,8 @@ class Output_section_element // the expression is an absolute value. virtual void set_section_addresses(Symbol_table*, Layout*, Output_section*, uint64_t, - uint64_t*, std::string*, Input_section_list*) + uint64_t*, Output_section**, std::string*, + Input_section_list*) { } // Print the element for debugging purposes. @@ -313,10 +310,10 @@ class Output_section_element_assignment : public Output_section_element // Finalize the symbol. void finalize_symbols(Symbol_table* symtab, const Layout* layout, - bool* dot_has_value, uint64_t* dot_value) + uint64_t* dot_value, Output_section** dot_section) { - this->assignment_.finalize_with_dot(symtab, layout, *dot_has_value, - *dot_value); + this->assignment_.finalize_with_dot(symtab, layout, *dot_value, + *dot_section); } // Set the section address. There is no section here, but if the @@ -324,10 +321,10 @@ class Output_section_element_assignment : public Output_section_element // absolute symbols when setting dot. void set_section_addresses(Symbol_table* symtab, Layout* layout, Output_section*, - uint64_t, uint64_t* dot_value, std::string*, - Input_section_list*) + uint64_t, uint64_t* dot_value, Output_section**, + std::string*, Input_section_list*) { - this->assignment_.set_if_absolute(symtab, layout, true, true, *dot_value); + this->assignment_.set_if_absolute(symtab, layout, true, *dot_value); } // Print for debugging. @@ -354,19 +351,17 @@ class Output_section_element_dot_assignment : public Output_section_element // Finalize the symbol. void finalize_symbols(Symbol_table* symtab, const Layout* layout, - bool* dot_has_value, uint64_t* dot_value) + uint64_t* dot_value, Output_section** dot_section) { - bool dummy; - *dot_value = this->val_->eval_with_dot(symtab, layout, *dot_has_value, - *dot_value, &dummy); - *dot_has_value = true; + *dot_value = this->val_->eval_with_dot(symtab, layout, *dot_value, + *dot_section, dot_section); } // Update the dot symbol while setting section addresses. void set_section_addresses(Symbol_table* symtab, Layout* layout, Output_section*, - uint64_t, uint64_t* dot_value, std::string*, - Input_section_list*); + uint64_t, uint64_t* dot_value, Output_section**, + std::string*, Input_section_list*); // Print for debugging. void @@ -390,14 +385,12 @@ Output_section_element_dot_assignment::set_section_addresses( Output_section* output_section, uint64_t, uint64_t* dot_value, + Output_section** dot_section, std::string* fill, Input_section_list*) { - bool is_absolute; - uint64_t next_dot = this->val_->eval_with_dot(symtab, layout, true, - *dot_value, &is_absolute); - if (!is_absolute) - gold_error(_("dot set to non-absolute value")); + uint64_t next_dot = this->val_->eval_with_dot(symtab, layout, *dot_value, + *dot_section, dot_section); if (next_dot < *dot_value) gold_error(_("dot may not move backward")); if (next_dot > *dot_value && output_section != NULL) @@ -438,6 +431,99 @@ class Output_section_element_assertion : public Output_section_element Script_assertion assertion_; }; +// We use a special instance of Output_section_data to handle BYTE, +// SHORT, etc. This permits forward references to symbols in the +// expressions. + +class Output_data_expression : public Output_section_data +{ + public: + Output_data_expression(int size, bool is_signed, Expression* val, + const Symbol_table* symtab, const Layout* layout, + uint64_t dot_value, Output_section* dot_section) + : Output_section_data(size, 0), + is_signed_(is_signed), val_(val), symtab_(symtab), + layout_(layout), dot_value_(dot_value), dot_section_(dot_section) + { } + + protected: + // Write the data to the output file. + void + do_write(Output_file*); + + // Write the data to a buffer. + void + do_write_to_buffer(unsigned char*); + + private: + template + void + endian_write_to_buffer(uint64_t, unsigned char*); + + bool is_signed_; + Expression* val_; + const Symbol_table* symtab_; + const Layout* layout_; + uint64_t dot_value_; + Output_section* dot_section_; +}; + +// Write the data element to the output file. + +void +Output_data_expression::do_write(Output_file* of) +{ + unsigned char* view = of->get_output_view(this->offset(), this->data_size()); + this->write_to_buffer(view); + of->write_output_view(this->offset(), this->data_size(), view); +} + +// Write the data element to a buffer. + +void +Output_data_expression::do_write_to_buffer(unsigned char* buf) +{ + Output_section* dummy; + uint64_t val = this->val_->eval_with_dot(this->symtab_, this->layout_, + this->dot_value_, + this->dot_section_, &dummy); + + if (parameters->is_big_endian()) + this->endian_write_to_buffer(val, buf); + else + this->endian_write_to_buffer(val, buf); +} + +template +void +Output_data_expression::endian_write_to_buffer(uint64_t val, + unsigned char* buf) +{ + switch (this->data_size()) + { + case 1: + elfcpp::Swap_unaligned<8, big_endian>::writeval(buf, val); + break; + case 2: + elfcpp::Swap_unaligned<16, big_endian>::writeval(buf, val); + break; + case 4: + elfcpp::Swap_unaligned<32, big_endian>::writeval(buf, val); + break; + case 8: + if (parameters->get_size() == 32) + { + val &= 0xffffffff; + if (this->is_signed_ && (val & 0x80000000) != 0) + val |= 0xffffffff00000000LL; + } + elfcpp::Swap_unaligned<64, big_endian>::writeval(buf, val); + break; + default: + gold_unreachable(); + } +} + // A data item in an output section. class Output_section_element_data : public Output_section_element @@ -449,13 +535,14 @@ class Output_section_element_data : public Output_section_element // Finalize symbols--we just need to update dot. void - finalize_symbols(Symbol_table*, const Layout*, bool*, uint64_t* dot_value) + finalize_symbols(Symbol_table*, const Layout*, uint64_t* dot_value, + Output_section**) { *dot_value += this->size_; } // Store the value in the section. void set_section_addresses(Symbol_table*, Layout*, Output_section*, uint64_t, - uint64_t* dot_value, std::string*, + uint64_t* dot_value, Output_section**, std::string*, Input_section_list*); // Print for debugging. @@ -463,10 +550,6 @@ class Output_section_element_data : public Output_section_element print(FILE*) const; private: - template - std::string - set_fill_string(uint64_t); - // The size in bytes. int size_; // Whether the value is signed. @@ -478,71 +561,27 @@ class Output_section_element_data : public Output_section_element // Store the value in the section. void -Output_section_element_data::set_section_addresses(Symbol_table* symtab, - Layout* layout, - Output_section* os, - uint64_t, - uint64_t* dot_value, - std::string*, - Input_section_list*) +Output_section_element_data::set_section_addresses( + Symbol_table* symtab, + Layout* layout, + Output_section* os, + uint64_t, + uint64_t* dot_value, + Output_section** dot_section, + std::string*, + Input_section_list*) { gold_assert(os != NULL); - - bool is_absolute; - uint64_t val = this->val_->eval_with_dot(symtab, layout, true, *dot_value, - &is_absolute); - if (!is_absolute) - gold_error(_("data directive with non-absolute value")); - - std::string fill; - if (parameters->is_big_endian()) - fill = this->set_fill_string(val); - else - fill = this->set_fill_string(val); - - os->add_output_section_data(new Output_data_const(fill, 0)); - + os->add_output_section_data(new Output_data_expression(this->size_, + this->is_signed_, + this->val_, + symtab, + layout, + *dot_value, + *dot_section)); *dot_value += this->size_; } -// Get the value to store in a std::string. - -template -std::string - Output_section_element_data::set_fill_string(uint64_t val) -{ - std::string ret; - unsigned char buf[8]; - switch (this->size_) - { - case 1: - elfcpp::Swap_unaligned<8, big_endian>::writeval(buf, val); - ret.assign(reinterpret_cast(buf), 1); - break; - case 2: - elfcpp::Swap_unaligned<16, big_endian>::writeval(buf, val); - ret.assign(reinterpret_cast(buf), 2); - break; - case 4: - elfcpp::Swap_unaligned<32, big_endian>::writeval(buf, val); - ret.assign(reinterpret_cast(buf), 4); - break; - case 8: - if (parameters->get_size() == 32) - { - val &= 0xffffffff; - if (this->is_signed_ && (val & 0x80000000) != 0) - val |= 0xffffffff00000000LL; - } - elfcpp::Swap_unaligned<64, big_endian>::writeval(buf, val); - ret.assign(reinterpret_cast(buf), 8); - break; - default: - gold_unreachable(); - } - return ret; -} - // Print for debugging. void @@ -586,15 +625,16 @@ class Output_section_element_fill : public Output_section_element // Update the fill value while setting section addresses. void set_section_addresses(Symbol_table* symtab, Layout* layout, Output_section*, - uint64_t, uint64_t* dot_value, std::string* fill, - Input_section_list*) + uint64_t, uint64_t* dot_value, + Output_section** dot_section, + std::string* fill, Input_section_list*) { - bool is_absolute; - uint64_t fill_val = this->val_->eval_with_dot(symtab, layout, true, - *dot_value, - &is_absolute); - if (!is_absolute) - gold_error(_("fill set to non-absolute value")); + Output_section* fill_section; + uint64_t fill_val = this->val_->eval_with_dot(symtab, layout, + *dot_value, *dot_section, + &fill_section); + if (fill_section != NULL) + gold_warning(_("fill value is not absolute")); // FIXME: The GNU linker supports fill values of arbitrary length. unsigned char fill_buff[4]; elfcpp::Swap_unaligned<32, true>::writeval(fill_buff, fill_val); @@ -633,11 +673,11 @@ class Output_section_element_input : public Output_section_element // Finalize symbols--just update the value of the dot symbol. void - finalize_symbols(Symbol_table*, const Layout*, bool* dot_has_value, - uint64_t* dot_value) + finalize_symbols(Symbol_table*, const Layout*, uint64_t* dot_value, + Output_section** dot_section) { *dot_value = this->final_dot_value_; - *dot_has_value = true; + *dot_section = this->final_dot_section_; } // See whether we match FILE_NAME and SECTION_NAME as an input @@ -649,7 +689,8 @@ class Output_section_element_input : public Output_section_element void set_section_addresses(Symbol_table* symtab, Layout* layout, Output_section*, uint64_t subalign, uint64_t* dot_value, - std::string* fill, Input_section_list*); + Output_section**, std::string* fill, + Input_section_list*); // Print for debugging. void @@ -707,6 +748,9 @@ class Output_section_element_input : public Output_section_element bool keep_; // The value of dot after including all matching sections. uint64_t final_dot_value_; + // The section where dot is defined after including all matching + // sections. + Output_section* final_dot_section_; }; // Construct Output_section_element_input. The parser records strings @@ -722,7 +766,8 @@ Output_section_element_input::Output_section_element_input( filename_exclusions_(), input_section_patterns_(), keep_(keep), - final_dot_value_(0) + final_dot_value_(0), + final_dot_section_(NULL) { // The filename pattern "*" is common, and matches all files. Turn // it into the empty string. @@ -885,6 +930,7 @@ Output_section_element_input::set_section_addresses( Output_section* output_section, uint64_t subalign, uint64_t* dot_value, + Output_section** dot_section, std::string* fill, Input_section_list* input_sections) { @@ -1001,6 +1047,7 @@ Output_section_element_input::set_section_addresses( } this->final_dot_value_ = *dot_value; + this->final_dot_section_ = *dot_section; } // Print for debugging. @@ -1153,7 +1200,7 @@ class Output_section_definition : public Sections_element // Finalize symbols and check assertions. void - finalize_symbols(Symbol_table*, const Layout*, bool*, uint64_t*); + finalize_symbols(Symbol_table*, const Layout*, uint64_t*); // Return the output section name to use for an input file name and // section name. @@ -1168,7 +1215,7 @@ class Output_section_definition : public Sections_element // Set the section address. void set_section_addresses(Symbol_table* symtab, Layout* layout, - bool* dot_has_value, uint64_t* dot_value); + uint64_t* dot_value); // Check a constraint (ONLY_IF_RO, etc.) on an output section. If // this section is constrained, and the input sections do not match, @@ -1333,7 +1380,6 @@ Output_section_definition::add_symbols_to_table(Symbol_table* symtab) void Output_section_definition::finalize_symbols(Symbol_table* symtab, const Layout* layout, - bool* dot_has_value, uint64_t* dot_value) { if (this->output_section_ != NULL) @@ -1343,28 +1389,28 @@ Output_section_definition::finalize_symbols(Symbol_table* symtab, uint64_t address = *dot_value; if (this->address_ != NULL) { - bool dummy; + Output_section* dummy; address = this->address_->eval_with_dot(symtab, layout, - *dot_has_value, *dot_value, + *dot_value, NULL, &dummy); } if (this->align_ != NULL) { - bool dummy; + Output_section* dummy; uint64_t align = this->align_->eval_with_dot(symtab, layout, - *dot_has_value, *dot_value, + NULL, &dummy); address = align_address(address, align); } *dot_value = address; } - *dot_has_value = true; + Output_section* dot_section = this->output_section_; for (Output_section_elements::iterator p = this->elements_.begin(); p != this->elements_.end(); ++p) - (*p)->finalize_symbols(symtab, layout, dot_has_value, dot_value); + (*p)->finalize_symbols(symtab, layout, dot_value, &dot_section); } // Return the output section name to use for an input section name. @@ -1514,25 +1560,16 @@ Output_section_definition::place_orphan_here(const Output_section *os, void Output_section_definition::set_section_addresses(Symbol_table* symtab, Layout* layout, - bool* dot_has_value, uint64_t* dot_value) { - bool is_absolute; uint64_t address; - if (this->address_ != NULL) - { - address = this->address_->eval_with_dot(symtab, layout, *dot_has_value, - *dot_value, &is_absolute); - if (!is_absolute) - gold_error(_("address of section %s is not absolute"), - this->name_.c_str()); - } + if (this->address_ == NULL) + address = *dot_value; else { - if (!*dot_has_value) - gold_error(_("no address given for section %s"), - this->name_.c_str()); - address = *dot_value; + Output_section* dummy; + address = this->address_->eval_with_dot(symtab, layout, *dot_value, + NULL, &dummy); } uint64_t align; @@ -1545,11 +1582,12 @@ Output_section_definition::set_section_addresses(Symbol_table* symtab, } else { - align = this->align_->eval_with_dot(symtab, layout, *dot_has_value, - *dot_value, &is_absolute); - if (!is_absolute) - gold_error(_("alignment of section %s is not absolute"), - this->name_.c_str()); + Output_section* align_section; + align = this->align_->eval_with_dot(symtab, layout, *dot_value, + NULL, &align_section); + if (align_section != NULL) + gold_warning(_("alignment of section %s is not absolute"), + this->name_.c_str()); if (this->output_section_ != NULL) this->output_section_->set_addralign(align); } @@ -1557,7 +1595,6 @@ Output_section_definition::set_section_addresses(Symbol_table* symtab, address = align_address(address, align); *dot_value = address; - *dot_has_value = true; // The address of non-SHF_ALLOC sections is forced to zero, // regardless of what the linker script wants. @@ -1567,12 +1604,10 @@ Output_section_definition::set_section_addresses(Symbol_table* symtab, if (this->load_address_ != NULL && this->output_section_ != NULL) { + Output_section* dummy; uint64_t load_address = - this->load_address_->eval_with_dot(symtab, layout, *dot_has_value, - *dot_value, &is_absolute); - if (!is_absolute) - gold_error(_("load address of section %s is not absolute"), - this->name_.c_str()); + this->load_address_->eval_with_dot(symtab, layout, *dot_value, + this->output_section_, &dummy); this->output_section_->set_load_address(load_address); } @@ -1581,11 +1616,12 @@ Output_section_definition::set_section_addresses(Symbol_table* symtab, subalign = 0; else { - subalign = this->subalign_->eval_with_dot(symtab, layout, *dot_has_value, - *dot_value, &is_absolute); - if (!is_absolute) - gold_error(_("subalign of section %s is not absolute"), - this->name_.c_str()); + Output_section* subalign_section; + subalign = this->subalign_->eval_with_dot(symtab, layout, *dot_value, + NULL, &subalign_section); + if (subalign_section != NULL) + gold_warning(_("subalign of section %s is not absolute"), + this->name_.c_str()); } std::string fill; @@ -1593,13 +1629,14 @@ Output_section_definition::set_section_addresses(Symbol_table* symtab, { // FIXME: The GNU linker supports fill values of arbitrary // length. + Output_section* fill_section; uint64_t fill_val = this->fill_->eval_with_dot(symtab, layout, - *dot_has_value, *dot_value, - &is_absolute); - if (!is_absolute) - gold_error(_("fill of section %s is not absolute"), - this->name_.c_str()); + NULL, + &fill_section); + if (fill_section != NULL) + gold_warning(_("fill of section %s is not absolute"), + this->name_.c_str()); unsigned char fill_buff[4]; elfcpp::Swap_unaligned<32, true>::writeval(fill_buff, fill_val); fill.assign(reinterpret_cast(fill_buff), 4); @@ -1617,11 +1654,13 @@ Output_section_definition::set_section_addresses(Symbol_table* symtab, *dot_value = address; } + Output_section* dot_section = this->output_section_; for (Output_section_elements::iterator p = this->elements_.begin(); p != this->elements_.end(); ++p) (*p)->set_section_addresses(symtab, layout, this->output_section_, - subalign, dot_value, &fill, &input_sections); + subalign, dot_value, &dot_section, &fill, + &input_sections); gold_assert(input_sections.empty()); } @@ -1806,7 +1845,7 @@ class Orphan_output_section : public Sections_element // Set section addresses. void - set_section_addresses(Symbol_table*, Layout*, bool*, uint64_t*); + set_section_addresses(Symbol_table*, Layout*, uint64_t*); // Get the list of segments to use for an allocated section when // using a PHDRS clause. If this is an allocated section, return @@ -1845,14 +1884,10 @@ Orphan_output_section::place_orphan_here(const Output_section* os, void Orphan_output_section::set_section_addresses(Symbol_table*, Layout*, - bool* dot_has_value, uint64_t* dot_value) { typedef std::list > Input_section_list; - if (!*dot_has_value) - gold_error(_("no address for orphan section %s"), this->os_->name()); - uint64_t address = *dot_value; address = align_address(address, this->os_->addralign()); @@ -2177,12 +2212,11 @@ Script_sections::finalize_symbols(Symbol_table* symtab, const Layout* layout) { if (!this->saw_sections_clause_) return; - bool dot_has_value = false; uint64_t dot_value = 0; for (Sections_elements::iterator p = this->sections_elements_->begin(); p != this->sections_elements_->end(); ++p) - (*p)->finalize_symbols(symtab, layout, &dot_has_value, &dot_value); + (*p)->finalize_symbols(symtab, layout, &dot_value); } // Return the name of the output section to use for an input file name @@ -2290,12 +2324,12 @@ Script_sections::set_section_addresses(Symbol_table* symtab, Layout* layout) } } - bool dot_has_value = false; + // For a relocatable link, we implicitly set dot to zero. uint64_t dot_value = 0; for (Sections_elements::iterator p = this->sections_elements_->begin(); p != this->sections_elements_->end(); ++p) - (*p)->set_section_addresses(symtab, layout, &dot_has_value, &dot_value); + (*p)->set_section_addresses(symtab, layout, &dot_value); if (this->phdrs_elements_ != NULL) { diff --git a/gold/script.cc b/gold/script.cc index 68784f6910..128acae746 100644 --- a/gold/script.cc +++ b/gold/script.cc @@ -915,7 +915,7 @@ Symbol_assignment::add_to_table(Symbol_table* symtab) void Symbol_assignment::finalize(Symbol_table* symtab, const Layout* layout) { - this->finalize_maybe_dot(symtab, layout, false, false, 0); + this->finalize_maybe_dot(symtab, layout, false, 0, NULL); } // Finalize a symbol value which can refer to the dot symbol. @@ -923,10 +923,10 @@ Symbol_assignment::finalize(Symbol_table* symtab, const Layout* layout) void Symbol_assignment::finalize_with_dot(Symbol_table* symtab, const Layout* layout, - bool dot_has_value, - uint64_t dot_value) + uint64_t dot_value, + Output_section* dot_section) { - this->finalize_maybe_dot(symtab, layout, true, dot_has_value, dot_value); + this->finalize_maybe_dot(symtab, layout, true, dot_value, dot_section); } // Finalize a symbol value, internal version. @@ -935,8 +935,8 @@ void Symbol_assignment::finalize_maybe_dot(Symbol_table* symtab, const Layout* layout, bool is_dot_available, - bool dot_has_value, - uint64_t dot_value) + uint64_t dot_value, + Output_section* dot_section) { // If we were only supposed to provide this symbol, the sym_ field // will be NULL if the symbol was not referenced. @@ -949,8 +949,8 @@ Symbol_assignment::finalize_maybe_dot(Symbol_table* symtab, if (parameters->get_size() == 32) { #if defined(HAVE_TARGET_32_LITTLE) || defined(HAVE_TARGET_32_BIG) - this->sized_finalize<32>(symtab, layout, is_dot_available, dot_has_value, - dot_value); + this->sized_finalize<32>(symtab, layout, is_dot_available, dot_value, + dot_section); #else gold_unreachable(); #endif @@ -958,8 +958,8 @@ Symbol_assignment::finalize_maybe_dot(Symbol_table* symtab, else if (parameters->get_size() == 64) { #if defined(HAVE_TARGET_64_LITTLE) || defined(HAVE_TARGET_64_BIG) - this->sized_finalize<64>(symtab, layout, is_dot_available, dot_has_value, - dot_value); + this->sized_finalize<64>(symtab, layout, is_dot_available, dot_value, + dot_section); #else gold_unreachable(); #endif @@ -971,33 +971,33 @@ Symbol_assignment::finalize_maybe_dot(Symbol_table* symtab, template void Symbol_assignment::sized_finalize(Symbol_table* symtab, const Layout* layout, - bool is_dot_available, bool dot_has_value, - uint64_t dot_value) + bool is_dot_available, uint64_t dot_value, + Output_section* dot_section) { - bool dummy; + Output_section* section; uint64_t final_val = this->val_->eval_maybe_dot(symtab, layout, is_dot_available, - dot_has_value, dot_value, - &dummy); + dot_value, dot_section, + §ion); Sized_symbol* ssym = symtab->get_sized_symbol(this->sym_); ssym->set_value(final_val); + if (section != NULL) + ssym->set_output_section(section); } // Set the symbol value if the expression yields an absolute value. void Symbol_assignment::set_if_absolute(Symbol_table* symtab, const Layout* layout, - bool is_dot_available, bool dot_has_value, - uint64_t dot_value) + bool is_dot_available, uint64_t dot_value) { if (this->sym_ == NULL) return; - bool is_absolute; + Output_section* val_section; uint64_t val = this->val_->eval_maybe_dot(symtab, layout, is_dot_available, - dot_has_value, dot_value, - &is_absolute); - if (!is_absolute) + dot_value, NULL, &val_section); + if (val_section != NULL) return; if (parameters->get_size() == 32) @@ -1158,7 +1158,7 @@ Script_options::set_section_addresses(Symbol_table* symtab, Layout* layout) for (Symbol_assignments::iterator p = this->symbol_assignments_.begin(); p != this->symbol_assignments_.end(); ++p) - (*p)->set_if_absolute(symtab, layout, false, false, 0); + (*p)->set_if_absolute(symtab, layout, false, 0); return this->script_sections_.set_section_addresses(symtab, layout); } diff --git a/gold/script.h b/gold/script.h index 81e7ab8d36..64d7fd6f8b 100644 --- a/gold/script.h +++ b/gold/script.h @@ -72,20 +72,26 @@ class Expression eval(const Symbol_table*, const Layout*); // Return the value of an expression which is permitted to refer to - // the dot symbol. This sets *IS_ABSOLUTE to indicate whether this - // is an absolute value; it will be false if a non-absolute symbol - // was referenced in the expression; this is used to detect invalid - // uses when setting a section address. + // 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. uint64_t - eval_with_dot(const Symbol_table*, const Layout*, bool dot_has_value, - uint64_t dot_value, bool* is_absolute); + eval_with_dot(const Symbol_table*, const Layout*, uint64_t dot_value, + Output_section* dot_section, Output_section** result_section); // Return the value of an expression which may or may not be // permitted to refer to the dot symbol, depending on // is_dot_available. uint64_t eval_maybe_dot(const Symbol_table*, const Layout*, bool is_dot_available, - bool dot_has_value, uint64_t dot_value, bool* is_absolute); + uint64_t dot_value, Output_section* dot_section, + Output_section** result_section); // Print the expression to the FILE. This is for debugging. virtual void @@ -208,14 +214,15 @@ class Symbol_assignment // Finalize the symbol value when it can refer to the dot symbol. void - finalize_with_dot(Symbol_table*, const Layout*, bool dot_has_value, - uint64_t dot_value); + 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. This is - // used while processing a SECTIONS clause. + // used while processing a SECTIONS clause. We assume that dot is + // an absolute value here. void set_if_absolute(Symbol_table*, const Layout*, bool is_dot_available, - bool dot_has_value, uint64_t dot_value); + uint64_t dot_value); // Print the assignment to the FILE. This is for debugging. void @@ -225,13 +232,13 @@ class Symbol_assignment // Shared by finalize and finalize_with_dot. void finalize_maybe_dot(Symbol_table*, const Layout*, bool is_dot_available, - bool dot_has_value, uint64_t dot_value); + uint64_t dot_value, Output_section* dot_section); // Sized version of finalize. template void sized_finalize(Symbol_table*, const Layout*, bool is_dot_available, - bool dot_has_value, uint64_t dot_value); + uint64_t dot_value, Output_section*); // Symbol name. std::string name_; diff --git a/gold/symtab.cc b/gold/symtab.cc index 54ead06930..86d8b112fc 100644 --- a/gold/symtab.cc +++ b/gold/symtab.cc @@ -298,20 +298,57 @@ Symbol::final_value_is_known() const return parameters->doing_static_link(); } -// Return whether the symbol has an absolute value. +// Return the output section where this symbol is defined. -bool -Symbol::value_is_absolute() const +Output_section* +Symbol::output_section() const { switch (this->source_) { case FROM_OBJECT: - return this->u_.from_object.shndx == elfcpp::SHN_ABS; + { + unsigned int shndx = this->u_.from_object.shndx; + if (shndx != elfcpp::SHN_UNDEF && shndx < elfcpp::SHN_LORESERVE) + { + gold_assert(!this->u_.from_object.object->is_dynamic()); + Relobj* relobj = static_cast(this->u_.from_object.object); + section_offset_type dummy; + return relobj->output_section(shndx, &dummy); + } + return NULL; + } + case IN_OUTPUT_DATA: + return this->u_.in_output_data.output_data->output_section(); + case IN_OUTPUT_SEGMENT: - return false; case CONSTANT: - return true; + return NULL; + + default: + gold_unreachable(); + } +} + +// Set the symbol's output section. This is used for symbols defined +// in scripts. This should only be called after the symbol table has +// been finalized. + +void +Symbol::set_output_section(Output_section* os) +{ + switch (this->source_) + { + case FROM_OBJECT: + case IN_OUTPUT_DATA: + gold_assert(this->output_section() == os); + break; + case CONSTANT: + this->source_ = IN_OUTPUT_DATA; + this->u_.in_output_data.output_data = os; + this->u_.in_output_data.offset_is_from_end = false; + break; + case IN_OUTPUT_SEGMENT: default: gold_unreachable(); } diff --git a/gold/symtab.h b/gold/symtab.h index 4d25840871..b2417f665b 100644 --- a/gold/symtab.h +++ b/gold/symtab.h @@ -568,9 +568,16 @@ class Symbol return true; } - // Return whether this symbol currently has an absolute value. - bool - value_is_absolute() const; + // Return the output section where this symbol is defined. Return + // NULL if the symbol has an absolute value. + Output_section* + output_section() const; + + // Set the symbol's output section. This is used for symbols + // defined in scripts. This should only be called after the symbol + // table has been finalized. + void + set_output_section(Output_section*); // Return whether there should be a warning for references to this // symbol.