// 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.
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
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);
}
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();
"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;
}
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
// 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, -)
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
};
// Handle binary operators. We use a preprocessor macro as a hack to
-// capture the C operator.
-
-#define BINARY_EXPRESSION(NAME, 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, KEEP_LEFT, KEEP_RIGHT, IS_DIV, WARN) \
class Binary_ ## NAME : public Binary_expression \
{ \
public: \
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 \
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.
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
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
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
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
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;
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;
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();
}
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
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
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;
private:
// The output section for this section.
- const Output_section* output_section_;
+ Output_section* output_section_;
// The required alignment.
uint64_t addralign_;
};
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
// 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
// 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
// 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
// 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.
// 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.
// 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.
// 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.
// 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.
// 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
// 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.
// 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
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)
Script_assertion assertion_;
};
-// A data item in an output section.
+// 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_section_element_data : public Output_section_element
+class Output_data_expression : public Output_section_data
{
public:
- Output_section_element_data(int size, bool is_signed, Expression* val)
- : size_(size), is_signed_(is_signed), val_(val)
+ 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)
{ }
- // Finalize symbols--we just need to update dot.
- void
- finalize_symbols(Symbol_table*, const Layout*, bool*, uint64_t* dot_value)
- { *dot_value += this->size_; }
-
- // Store the value in the section.
+ protected:
+ // Write the data to the output file.
void
- set_section_addresses(Symbol_table*, Layout*, Output_section*, uint64_t,
- uint64_t* dot_value, std::string*,
- Input_section_list*);
+ do_write(Output_file*);
- // Print for debugging.
+ // Write the data to a buffer.
void
- print(FILE*) const;
+ do_write_to_buffer(unsigned char*);
private:
template<bool big_endian>
- std::string
- set_fill_string(uint64_t);
+ void
+ endian_write_to_buffer(uint64_t, unsigned char*);
- // The size in bytes.
- int size_;
- // Whether the value is signed.
bool is_signed_;
- // The value.
Expression* val_;
+ const Symbol_table* symtab_;
+ const Layout* layout_;
+ uint64_t dot_value_;
+ Output_section* dot_section_;
};
-// Store the value in the section.
+// Write the data element to the output file.
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_data_expression::do_write(Output_file* of)
{
- gold_assert(os != NULL);
+ 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);
+}
- 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"));
+// 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);
- std::string fill;
if (parameters->is_big_endian())
- fill = this->set_fill_string<true>(val);
+ this->endian_write_to_buffer<true>(val, buf);
else
- fill = this->set_fill_string<false>(val);
-
- os->add_output_section_data(new Output_data_const(fill, 0));
-
- *dot_value += this->size_;
+ this->endian_write_to_buffer<false>(val, buf);
}
-// 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)
+void
+Output_data_expression::endian_write_to_buffer(uint64_t val,
+ unsigned char* buf)
{
- std::string ret;
- unsigned char buf[8];
- switch (this->size_)
+ switch (this->data_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 |= 0xffffffff00000000LL;
}
elfcpp::Swap_unaligned<64, big_endian>::writeval(buf, val);
- ret.assign(reinterpret_cast<char*>(buf), 8);
break;
default:
gold_unreachable();
}
- return ret;
+}
+
+// A data item in an output section.
+
+class Output_section_element_data : public Output_section_element
+{
+ public:
+ Output_section_element_data(int size, bool is_signed, Expression* val)
+ : size_(size), is_signed_(is_signed), val_(val)
+ { }
+
+ // Finalize symbols--we just need to update dot.
+ void
+ 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, Output_section**, std::string*,
+ Input_section_list*);
+
+ // Print for debugging.
+ void
+ print(FILE*) const;
+
+ private:
+ // The size in bytes.
+ int size_;
+ // Whether the value is signed.
+ bool is_signed_;
+ // The value.
+ Expression* val_;
+};
+
+// 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,
+ Output_section** dot_section,
+ std::string*,
+ Input_section_list*)
+{
+ gold_assert(os != NULL);
+ 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_;
}
// Print for debugging.
// 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);
// 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
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
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
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.
Output_section* output_section,
uint64_t subalign,
uint64_t* dot_value,
+ Output_section** dot_section,
std::string* fill,
Input_section_list* input_sections)
{
}
this->final_dot_value_ = *dot_value;
+ this->final_dot_section_ = *dot_section;
}
// Print for debugging.
// 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.
// 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,
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)
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.
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;
}
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);
}
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.
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);
}
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;
{
// 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);
*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());
}
// 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
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());
{
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
}
}
- 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)
{
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.
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.
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.
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
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
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)
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);
}
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
// 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
// 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_;
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();
}
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.