Track sections for expressions.

This commit is contained in:
Ian Lance Taylor 2008-02-09 01:22:17 +00:00
parent 333eff6027
commit 77e655378d
7 changed files with 517 additions and 320 deletions

View File

@ -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();
}

View File

@ -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

View File

@ -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)
{

View File

@ -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,
&section);
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);
}

View File

@ -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_;

View File

@ -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();
}

View File

@ -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.