Fix internal error in gold when script uses section address in assignment.
When processing assignment expressions in a linker script, gold processes absolute assignments early, but when one of those assignments involves the address of a section that has not yet been finalized, we get an internal error in address. This patch fixes the problem by gracefully returning from expression evaluation even if the address is not yet valid, and deferring the assignment in such a case. gold/ PR gold/14746 * expression.cc (Expression::Expression_eval_info): Add is_valid_pointer field. (Expression::eval_maybe_dot): Add is_valid_pointer parameter. Adjust all callers. (Addr_expression::value_from_output_section): Check whether address is valid. * script.cc (Symbol_assignment::set_if_absolute): Defer assignment if evaluation failed due to address that is not yet valid. * script.h: (Expression::eval_maybe_dot): Add is_valid_pointer parameter.
This commit is contained in:
parent
3ac0a36c29
commit
1757d35c8a
@ -1,3 +1,17 @@
|
||||
2015-08-25 Cary Coutant <ccoutant@gmail.com>
|
||||
|
||||
PR gold/14746
|
||||
* expression.cc (Expression::Expression_eval_info): Add
|
||||
is_valid_pointer field.
|
||||
(Expression::eval_maybe_dot): Add is_valid_pointer parameter.
|
||||
Adjust all callers.
|
||||
(Addr_expression::value_from_output_section): Check whether address
|
||||
is valid.
|
||||
* script.cc (Symbol_assignment::set_if_absolute): Defer assignment
|
||||
if evaluation failed due to address that is not yet valid.
|
||||
* script.h: (Expression::eval_maybe_dot): Add is_valid_pointer
|
||||
parameter.
|
||||
|
||||
2015-08-25 Cary Coutant <ccoutant@gmail.com>
|
||||
|
||||
PR gold/18866
|
||||
|
@ -74,6 +74,10 @@ struct Expression::Expression_eval_info
|
||||
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.
|
||||
@ -83,7 +87,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, NULL, NULL, NULL, false);
|
||||
NULL, NULL, NULL, NULL, NULL, NULL, false, NULL);
|
||||
}
|
||||
|
||||
// Evaluate an expression which may refer to the dot symbol.
|
||||
@ -99,7 +103,7 @@ Expression::eval_with_dot(const Symbol_table* symtab, const Layout* layout,
|
||||
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);
|
||||
is_section_dot_assignment, NULL);
|
||||
}
|
||||
|
||||
// Evaluate an expression which may or may not refer to the dot
|
||||
@ -114,7 +118,8 @@ Expression::eval_maybe_dot(const Symbol_table* symtab, const Layout* layout,
|
||||
elfcpp::STT* type_pointer,
|
||||
elfcpp::STV* vis_pointer,
|
||||
unsigned char* nonvis_pointer,
|
||||
bool is_section_dot_assignment)
|
||||
bool is_section_dot_assignment,
|
||||
bool* is_valid_pointer)
|
||||
{
|
||||
Expression_eval_info eei;
|
||||
eei.symtab = symtab;
|
||||
@ -138,8 +143,18 @@ Expression::eval_maybe_dot(const Symbol_table* symtab, const Layout* layout,
|
||||
|
||||
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)
|
||||
@ -295,7 +310,8 @@ class Unary_expression : public Expression
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
false);
|
||||
false,
|
||||
eei->is_valid_pointer);
|
||||
}
|
||||
|
||||
void
|
||||
@ -378,7 +394,8 @@ class Binary_expression : public Expression
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
false);
|
||||
false,
|
||||
eei->is_valid_pointer);
|
||||
}
|
||||
|
||||
uint64_t
|
||||
@ -396,7 +413,8 @@ class Binary_expression : public Expression
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
false);
|
||||
false,
|
||||
eei->is_valid_pointer);
|
||||
}
|
||||
|
||||
void
|
||||
@ -550,7 +568,8 @@ class Trinary_expression : public Expression
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
false);
|
||||
false,
|
||||
eei->is_valid_pointer);
|
||||
}
|
||||
|
||||
uint64_t
|
||||
@ -568,7 +587,8 @@ class Trinary_expression : public Expression
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
false);
|
||||
false,
|
||||
eei->is_valid_pointer);
|
||||
}
|
||||
|
||||
uint64_t
|
||||
@ -586,7 +606,8 @@ class Trinary_expression : public Expression
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
false);
|
||||
false,
|
||||
eei->is_valid_pointer);
|
||||
}
|
||||
|
||||
void
|
||||
@ -945,7 +966,10 @@ class Addr_expression : public Section_expression
|
||||
{
|
||||
if (eei->result_section_pointer != NULL)
|
||||
*eei->result_section_pointer = os;
|
||||
return os->address();
|
||||
if (os->is_address_valid())
|
||||
return os->address();
|
||||
*eei->is_valid_pointer = false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint64_t
|
||||
|
@ -987,7 +987,7 @@ Symbol_assignment::sized_finalize(Symbol_table* symtab, const Layout* layout,
|
||||
is_dot_available,
|
||||
dot_value, dot_section,
|
||||
§ion, NULL, &type,
|
||||
&vis, &nonvis, false);
|
||||
&vis, &nonvis, false, NULL);
|
||||
Sized_symbol<size>* ssym = symtab->get_sized_symbol<size>(this->sym_);
|
||||
ssym->set_value(final_val);
|
||||
ssym->set_type(type);
|
||||
@ -1009,11 +1009,12 @@ Symbol_assignment::set_if_absolute(Symbol_table* symtab, const Layout* layout,
|
||||
return;
|
||||
|
||||
Output_section* val_section;
|
||||
bool is_valid;
|
||||
uint64_t val = this->val_->eval_maybe_dot(symtab, layout, false,
|
||||
is_dot_available, dot_value,
|
||||
dot_section, &val_section, NULL,
|
||||
NULL, NULL, NULL, false);
|
||||
if (val_section != NULL && val_section != dot_section)
|
||||
NULL, NULL, NULL, false, &is_valid);
|
||||
if (!is_valid || (val_section != NULL && val_section != dot_section))
|
||||
return;
|
||||
|
||||
if (parameters->target().get_size() == 32)
|
||||
|
@ -113,7 +113,7 @@ class Expression
|
||||
Output_section* dot_section,
|
||||
Output_section** result_section, uint64_t* result_alignment,
|
||||
elfcpp::STT* type, elfcpp::STV* vis, unsigned char* nonvis,
|
||||
bool is_section_dot_assignment);
|
||||
bool is_section_dot_assignment, bool* is_valid_pointer);
|
||||
|
||||
// Print the expression to the FILE. This is for debugging.
|
||||
virtual void
|
||||
|
Loading…
Reference in New Issue
Block a user