Track sections for expressions.
This commit is contained in:
parent
333eff6027
commit
77e655378d
7 changed files with 517 additions and 320 deletions
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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<bool big_endian>
|
||||
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<true>(val, buf);
|
||||
else
|
||||
this->endian_write_to_buffer<false>(val, buf);
|
||||
}
|
||||
|
||||
template<bool big_endian>
|
||||
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<bool big_endian>
|
||||
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<true>(val);
|
||||
else
|
||||
fill = this->set_fill_string<false>(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<bool big_endian>
|
||||
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<char*>(buf), 1);
|
||||
break;
|
||||
case 2:
|
||||
elfcpp::Swap_unaligned<16, big_endian>::writeval(buf, val);
|
||||
ret.assign(reinterpret_cast<char*>(buf), 2);
|
||||
break;
|
||||
case 4:
|
||||
elfcpp::Swap_unaligned<32, big_endian>::writeval(buf, val);
|
||||
ret.assign(reinterpret_cast<char*>(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<char*>(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<char*>(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<std::pair<Relobj*, unsigned int> > 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)
|
||||
{
|
||||
|
|
|
@ -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<int size>
|
||||
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<size>* ssym = symtab->get_sized_symbol<size>(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);
|
||||
}
|
||||
|
|
|
@ -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<int size>
|
||||
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_;
|
||||
|
|
|
@ -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<Relobj*>(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();
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
|
|
Loading…
Reference in a new issue