2011-10-28 Cary Coutant PR gold/13023 * expression.cc (Expression::eval_with_dot): Add is_section_dot_assignment parameter. (Expression::eval_maybe_dot): Likewise. Adjust value when rhs is absolute and assigning to dot within a section. * script-sections.cc (Output_section_element_assignment::set_section_addresses): Pass dot_section to set_if_absolute. (Output_section_element_dot_assignment::finalize_symbols): Pass TRUE as is_section_dot_assignment flag to eval_with_dot. (Output_section_element_dot_assignment::set_section_addresses): Likewise. * script.cc (Symbol_assignment::set_if_absolute): Add dot_section parameter. Also set value if relative to dot_section; set the symbol's output_section. * script.h (Expression::eval_with_dot): Add is_section_dot_assignment parameter. Adjust all callers. (Expression::eval_maybe_dot): Likewise. (Symbol_assignment::set_if_absolute): Add dot_section parameter. Adjust all callers. * testsuite/script_test_2.t: Test assignment of an absolute value to dot within an output section element. commit 65ff8bb95ef1657037a19a7c7c71222b065694c7 Author: Cary Coutant Date: Fri Oct 28 13:47:25 2011 -0700 Fix assignment to dot in scripts (PR 13023). diff --git a/gold/expression.cc b/gold/expression.cc index e527b5e..b611a68 100644 --- a/gold/expression.cc +++ b/gold/expression.cc @@ -77,7 +77,7 @@ Expression::eval(const Symbol_table* symtab, const Layout* layout, bool check_assertions) { return this->eval_maybe_dot(symtab, layout, check_assertions, - false, 0, NULL, NULL, NULL); + false, 0, NULL, NULL, NULL, false); } // Evaluate an expression which may refer to the dot symbol. @@ -87,11 +87,13 @@ 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, - uint64_t* result_alignment_pointer) + uint64_t* result_alignment_pointer, + bool is_section_dot_assignment) { return this->eval_maybe_dot(symtab, layout, check_assertions, true, dot_value, dot_section, result_section_pointer, - result_alignment_pointer); + result_alignment_pointer, + is_section_dot_assignment); } // Evaluate an expression which may or may not refer to the dot @@ -102,7 +104,8 @@ 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, - uint64_t* result_alignment_pointer) + uint64_t* result_alignment_pointer, + bool is_section_dot_assignment) { Expression_eval_info eei; eei.symtab = symtab; @@ -113,14 +116,24 @@ Expression::eval_maybe_dot(const Symbol_table* symtab, const Layout* layout, 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. + // if we find a section-relative reference. if (result_section_pointer != NULL) *result_section_pointer = NULL; eei.result_section_pointer = result_section_pointer; eei.result_alignment_pointer = result_alignment_pointer; - return this->value(&eei); + uint64_t val = this->value(&eei); + + // 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. @@ -257,7 +270,8 @@ class Unary_expression : public Expression eei->dot_value, eei->dot_section, arg_section_pointer, - eei->result_alignment_pointer); + eei->result_alignment_pointer, + false); } void @@ -336,7 +350,8 @@ class Binary_expression : public Expression eei->dot_value, eei->dot_section, section_pointer, - alignment_pointer); + alignment_pointer, + false); } uint64_t @@ -350,7 +365,8 @@ class Binary_expression : public Expression eei->dot_value, eei->dot_section, section_pointer, - alignment_pointer); + alignment_pointer, + false); } void @@ -500,7 +516,8 @@ class Trinary_expression : public Expression eei->dot_value, eei->dot_section, section_pointer, - NULL); + NULL, + false); } uint64_t @@ -514,7 +531,8 @@ class Trinary_expression : public Expression eei->dot_value, eei->dot_section, section_pointer, - alignment_pointer); + alignment_pointer, + false); } uint64_t @@ -528,7 +546,8 @@ class Trinary_expression : public Expression eei->dot_value, eei->dot_section, section_pointer, - alignment_pointer); + alignment_pointer, + false); } void diff --git a/gold/script-sections.cc b/gold/script-sections.cc index eba6b9d..f90c0b3 100644 --- a/gold/script-sections.cc +++ b/gold/script-sections.cc @@ -680,7 +680,7 @@ class Sections_element_assignment : public Sections_element set_section_addresses(Symbol_table* symtab, Layout* layout, uint64_t* dot_value, uint64_t*, uint64_t*) { - this->assignment_.set_if_absolute(symtab, layout, true, *dot_value); + this->assignment_.set_if_absolute(symtab, layout, true, *dot_value, NULL); } // Print for debugging. @@ -714,7 +714,7 @@ class Sections_element_dot_assignment : public Sections_element // output section definition the dot symbol is always considered // to be absolute. *dot_value = this->val_->eval_with_dot(symtab, layout, true, *dot_value, - NULL, NULL, NULL); + NULL, NULL, NULL, false); } // Update the dot symbol while setting section addresses. @@ -724,7 +724,7 @@ class Sections_element_dot_assignment : public Sections_element uint64_t* load_address) { *dot_value = this->val_->eval_with_dot(symtab, layout, false, *dot_value, - NULL, NULL, dot_alignment); + NULL, NULL, dot_alignment, false); *load_address = *dot_value; } @@ -866,9 +866,11 @@ class Output_section_element_assignment : public Output_section_element void set_section_addresses(Symbol_table* symtab, Layout* layout, Output_section*, uint64_t, uint64_t* dot_value, uint64_t*, - Output_section**, std::string*, Input_section_list*) + Output_section** dot_section, std::string*, + Input_section_list*) { - this->assignment_.set_if_absolute(symtab, layout, true, *dot_value); + this->assignment_.set_if_absolute(symtab, layout, true, *dot_value, + *dot_section); } // Print for debugging. @@ -904,14 +906,16 @@ class Output_section_element_dot_assignment : public Output_section_element uint64_t* dot_value, Output_section** dot_section) { *dot_value = this->val_->eval_with_dot(symtab, layout, true, *dot_value, - *dot_section, dot_section, NULL); + *dot_section, dot_section, NULL, + true); } // 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, uint64_t*, - Output_section**, std::string*, Input_section_list*); + Output_section** dot_section, std::string*, + Input_section_list*); // Print for debugging. void @@ -942,7 +946,8 @@ Output_section_element_dot_assignment::set_section_addresses( { uint64_t next_dot = this->val_->eval_with_dot(symtab, layout, false, *dot_value, *dot_section, - dot_section, dot_alignment); + dot_section, dot_alignment, + true); if (next_dot < *dot_value) gold_error(_("dot may not move backward")); if (next_dot > *dot_value && output_section != NULL) @@ -1043,7 +1048,8 @@ Output_data_expression::do_write_to_buffer(unsigned char* buf) { uint64_t val = this->val_->eval_with_dot(this->symtab_, this->layout_, true, this->dot_value_, - this->dot_section_, NULL, NULL); + this->dot_section_, NULL, NULL, + false); if (parameters->target().is_big_endian()) this->endian_write_to_buffer(val, buf); @@ -1193,7 +1199,7 @@ class Output_section_element_fill : public Output_section_element Output_section* fill_section; uint64_t fill_val = this->val_->eval_with_dot(symtab, layout, false, *dot_value, *dot_section, - &fill_section, NULL); + &fill_section, NULL, false); if (fill_section != NULL) gold_warning(_("fill value is not absolute")); // FIXME: The GNU linker supports fill values of arbitrary length. @@ -2114,13 +2120,13 @@ Output_section_definition::finalize_symbols(Symbol_table* symtab, { address = this->address_->eval_with_dot(symtab, layout, true, *dot_value, NULL, - NULL, NULL); + NULL, NULL, false); } if (this->align_ != NULL) { uint64_t align = this->align_->eval_with_dot(symtab, layout, true, *dot_value, NULL, - NULL, NULL); + NULL, NULL, false); address = align_address(address, align); } *dot_value = address; @@ -2309,7 +2315,7 @@ Output_section_definition::set_section_addresses(Symbol_table* symtab, else address = this->address_->eval_with_dot(symtab, layout, true, *dot_value, NULL, NULL, - dot_alignment); + dot_alignment, false); uint64_t align; if (this->align_ == NULL) { @@ -2322,7 +2328,7 @@ Output_section_definition::set_section_addresses(Symbol_table* symtab, { Output_section* align_section; align = this->align_->eval_with_dot(symtab, layout, true, *dot_value, - NULL, &align_section, NULL); + NULL, &align_section, NULL, false); if (align_section != NULL) gold_warning(_("alignment of section %s is not absolute"), this->name_.c_str()); @@ -2407,7 +2413,7 @@ Output_section_definition::set_section_addresses(Symbol_table* symtab, laddr = this->load_address_->eval_with_dot(symtab, layout, true, *dot_value, this->output_section_, - NULL, NULL); + NULL, NULL, false); if (this->output_section_ != NULL) this->output_section_->set_load_address(laddr); } @@ -2422,7 +2428,8 @@ Output_section_definition::set_section_addresses(Symbol_table* symtab, Output_section* subalign_section; subalign = this->subalign_->eval_with_dot(symtab, layout, true, *dot_value, NULL, - &subalign_section, NULL); + &subalign_section, NULL, + false); if (subalign_section != NULL) gold_warning(_("subalign of section %s is not absolute"), this->name_.c_str()); @@ -2437,7 +2444,7 @@ Output_section_definition::set_section_addresses(Symbol_table* symtab, uint64_t fill_val = this->fill_->eval_with_dot(symtab, layout, true, *dot_value, NULL, &fill_section, - NULL); + NULL, false); if (fill_section != NULL) gold_warning(_("fill of section %s is not absolute"), this->name_.c_str()); diff --git a/gold/script.cc b/gold/script.cc index 7df0c9e..b471cf9 100644 --- a/gold/script.cc +++ b/gold/script.cc @@ -983,18 +983,20 @@ Symbol_assignment::sized_finalize(Symbol_table* symtab, const Layout* layout, uint64_t final_val = this->val_->eval_maybe_dot(symtab, layout, true, is_dot_available, dot_value, dot_section, - §ion, NULL); + §ion, NULL, false); 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. +// Set the symbol value if the expression yields an absolute value or +// a value relative to DOT_SECTION. void Symbol_assignment::set_if_absolute(Symbol_table* symtab, const Layout* layout, - bool is_dot_available, uint64_t dot_value) + bool is_dot_available, uint64_t dot_value, + Output_section* dot_section) { if (this->sym_ == NULL) return; @@ -1002,8 +1004,9 @@ Symbol_assignment::set_if_absolute(Symbol_table* symtab, const Layout* layout, Output_section* val_section; uint64_t val = this->val_->eval_maybe_dot(symtab, layout, false, is_dot_available, dot_value, - NULL, &val_section, NULL); - if (val_section != NULL) + dot_section, &val_section, NULL, + false); + if (val_section != NULL && val_section != dot_section) return; if (parameters->target().get_size() == 32) @@ -1026,6 +1029,8 @@ Symbol_assignment::set_if_absolute(Symbol_table* symtab, const Layout* layout, } else gold_unreachable(); + if (val_section != NULL) + this->sym_->set_output_section(val_section); } // Print for debugging. @@ -1215,7 +1220,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, 0); + (*p)->set_if_absolute(symtab, layout, false, 0, NULL); return this->script_sections_.set_section_addresses(symtab, layout); } diff --git a/gold/script.h b/gold/script.h index 73079a4..f41f438 100644 --- a/gold/script.h +++ b/gold/script.h @@ -90,20 +90,28 @@ class Expression // the section address. If RESULT_ALIGNMENT is not NULL, this sets // *RESULT_ALIGNMENT to the alignment of the value of that alignment // is larger than *RESULT_ALIGNMENT; this will only be non-zero if - // this is an ALIGN expression. + // this is an ALIGN expression. If IS_SECTION_DOT_ASSIGMENT is true, + // we are evaluating an assignment to dot within an output section, + // and an absolute value should be interpreted as an offset within + // the section. uint64_t eval_with_dot(const Symbol_table*, const Layout*, bool check_assertions, uint64_t dot_value, Output_section* dot_section, - Output_section** result_section, uint64_t* result_alignment); + Output_section** result_section, uint64_t* result_alignment, + bool is_section_dot_assignment); // Return the value of an expression which may or may not be // permitted to refer to the dot symbol, depending on - // is_dot_available. + // is_dot_available. If IS_SECTION_DOT_ASSIGMENT is true, + // we are evaluating an assignment to dot within an output section, + // and an absolute value should be interpreted as an offset within + // the section. uint64_t eval_maybe_dot(const Symbol_table*, const Layout*, bool check_assertions, bool is_dot_available, uint64_t dot_value, Output_section* dot_section, - Output_section** result_section, uint64_t* result_alignment); + Output_section** result_section, uint64_t* result_alignment, + bool is_section_dot_assignment); // Print the expression to the FILE. This is for debugging. virtual void @@ -339,12 +347,12 @@ class Symbol_assignment 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. We assume that dot is - // an absolute value here. We do not check assertions. + // Set the symbol value, but only if the value is absolute or relative to + // DOT_SECTION. This is used while processing a SECTIONS clause. + // We assume that dot is an absolute value here. We do not check assertions. void set_if_absolute(Symbol_table*, const Layout*, bool is_dot_available, - uint64_t dot_value); + uint64_t dot_value, Output_section* dot_section); const std::string& name() const diff --git a/gold/testsuite/script_test_2.t b/gold/testsuite/script_test_2.t index 73d39df..6a0188f 100644 --- a/gold/testsuite/script_test_2.t +++ b/gold/testsuite/script_test_2.t @@ -49,7 +49,7 @@ SECTIONS /* This should match the remaining sections. */ *(.gold_test) - . = . + 4; + . = 60; start_data = .; BYTE(1) SHORT(2)