Output_section* dot_section;
// Points to where the section of the result should be stored.
Output_section** result_section_pointer;
+ // Pointer to where the alignment of the result should be stored.
+ uint64_t* result_alignment_pointer;
};
// Evaluate an expression.
{
Output_section* dummy;
return this->eval_maybe_dot(symtab, layout, check_assertions,
- false, 0, NULL, &dummy);
+ false, 0, NULL, &dummy, NULL);
}
// Evaluate an expression which may refer to the dot symbol.
Expression::eval_with_dot(const Symbol_table* symtab, const Layout* layout,
bool check_assertions, uint64_t dot_value,
Output_section* dot_section,
- Output_section** result_section_pointer)
+ Output_section** result_section_pointer,
+ uint64_t* result_alignment_pointer)
{
return this->eval_maybe_dot(symtab, layout, check_assertions, true,
- dot_value, dot_section, result_section_pointer);
+ dot_value, dot_section, result_section_pointer,
+ result_alignment_pointer);
}
// Evaluate an expression which may or may not refer to the dot
Expression::eval_maybe_dot(const Symbol_table* symtab, const Layout* layout,
bool check_assertions, bool is_dot_available,
uint64_t dot_value, Output_section* dot_section,
- Output_section** result_section_pointer)
+ Output_section** result_section_pointer,
+ uint64_t* result_alignment_pointer)
{
Expression_eval_info eei;
eei.symtab = symtab;
*result_section_pointer = NULL;
eei.result_section_pointer = result_section_pointer;
+ eei.result_alignment_pointer = result_alignment_pointer;
+
return this->value(&eei);
}
eei->is_dot_available,
eei->dot_value,
eei->dot_section,
- arg_section_pointer);
+ arg_section_pointer,
+ eei->result_alignment_pointer);
}
void
protected:
uint64_t
left_value(const Expression_eval_info* eei,
- Output_section** section_pointer) const
+ Output_section** section_pointer,
+ uint64_t* alignment_pointer) const
{
return this->left_->eval_maybe_dot(eei->symtab, eei->layout,
eei->check_assertions,
eei->is_dot_available,
eei->dot_value,
eei->dot_section,
- section_pointer);
+ section_pointer,
+ alignment_pointer);
}
uint64_t
right_value(const Expression_eval_info* eei,
- Output_section** section_pointer) const
+ Output_section** section_pointer,
+ uint64_t* alignment_pointer) const
{
return this->right_->eval_maybe_dot(eei->symtab, eei->layout,
eei->check_assertions,
eei->is_dot_available,
eei->dot_value,
eei->dot_section,
- section_pointer);
+ section_pointer,
+ alignment_pointer);
}
void
value(const Expression_eval_info* eei) \
{ \
Output_section* left_section; \
- uint64_t left = this->left_value(eei, &left_section); \
+ uint64_t left_alignment; \
+ uint64_t left = this->left_value(eei, &left_section, \
+ &left_alignment); \
Output_section* right_section; \
- uint64_t right = this->right_value(eei, &right_section); \
+ uint64_t right_alignment; \
+ uint64_t right = this->right_value(eei, &right_section, \
+ &right_alignment); \
if (KEEP_RIGHT && left_section == NULL && right_section != NULL) \
- *eei->result_section_pointer = right_section; \
+ { \
+ *eei->result_section_pointer = right_section; \
+ if (eei->result_alignment_pointer != NULL) \
+ *eei->result_alignment_pointer = right_alignment; \
+ } \
else if (KEEP_LEFT \
&& left_section != NULL \
&& right_section == NULL) \
- *eei->result_section_pointer = left_section; \
+ { \
+ *eei->result_section_pointer = left_section; \
+ if (eei->result_alignment_pointer != NULL) \
+ *eei->result_alignment_pointer = right_alignment; \
+ } \
else if ((WARN || left_section != right_section) \
&& (left_section != NULL || right_section != NULL) \
&& parameters->options().relocatable()) \
eei->is_dot_available,
eei->dot_value,
eei->dot_section,
- section_pointer);
+ section_pointer,
+ NULL);
}
uint64_t
arg2_value(const Expression_eval_info* eei,
- Output_section** section_pointer) const
+ Output_section** section_pointer,
+ uint64_t* alignment_pointer) const
{
return this->arg1_->eval_maybe_dot(eei->symtab, eei->layout,
eei->check_assertions,
eei->is_dot_available,
eei->dot_value,
eei->dot_section,
- section_pointer);
+ section_pointer,
+ alignment_pointer);
}
uint64_t
arg3_value(const Expression_eval_info* eei,
- Output_section** section_pointer) const
+ Output_section** section_pointer,
+ uint64_t* alignment_pointer) const
{
return this->arg1_->eval_maybe_dot(eei->symtab, eei->layout,
eei->check_assertions,
eei->is_dot_available,
eei->dot_value,
eei->dot_section,
- section_pointer);
+ section_pointer,
+ alignment_pointer);
}
void
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));
+ ? this->arg2_value(eei, eei->result_section_pointer,
+ eei->result_alignment_pointer)
+ : this->arg3_value(eei, eei->result_section_pointer,
+ eei->result_alignment_pointer));
}
void
value(const Expression_eval_info* eei)
{
Output_section* left_section;
- uint64_t left = this->left_value(eei, &left_section);
+ uint64_t left_alignment;
+ uint64_t left = this->left_value(eei, &left_section, &left_alignment);
Output_section* right_section;
- uint64_t right = this->right_value(eei, &right_section);
+ uint64_t right_alignment;
+ uint64_t right = this->right_value(eei, &right_section, &right_alignment);
if (left_section == right_section)
*eei->result_section_pointer = left_section;
else if ((left_section != NULL || right_section != NULL)
&& parameters->options().relocatable())
gold_warning(_("max applied to section relative value"));
+ if (eei->result_alignment_pointer != NULL)
+ {
+ uint64_t ra = *eei->result_alignment_pointer;
+ if (left > right)
+ ra = std::max(ra, left_alignment);
+ else if (right > left)
+ ra = std::max(ra, right_alignment);
+ else
+ ra = std::max(ra, std::max(left_alignment, right_alignment));
+ *eei->result_alignment_pointer = ra;
+ }
return std::max(left, right);
}
value(const Expression_eval_info* eei)
{
Output_section* left_section;
- uint64_t left = this->left_value(eei, &left_section);
+ uint64_t left_alignment;
+ uint64_t left = this->left_value(eei, &left_section, &left_alignment);
Output_section* right_section;
- uint64_t right = this->right_value(eei, &right_section);
+ uint64_t right_alignment;
+ uint64_t right = this->right_value(eei, &right_section, &right_alignment);
if (left_section == right_section)
*eei->result_section_pointer = left_section;
else if ((left_section != NULL || right_section != NULL)
&& parameters->options().relocatable())
gold_warning(_("min applied to section relative value"));
+ if (eei->result_alignment_pointer != NULL)
+ {
+ uint64_t ra = *eei->result_alignment_pointer;
+ if (left < right)
+ ra = std::max(ra, left_alignment);
+ else if (right < left)
+ ra = std::max(ra, right_alignment);
+ else
+ ra = std::max(ra, std::max(left_alignment, right_alignment));
+ *eei->result_alignment_pointer = ra;
+ }
return std::min(left, right);
}
value(const Expression_eval_info* eei)
{
Output_section* align_section;
- uint64_t align = this->right_value(eei, &align_section);
+ uint64_t align = this->right_value(eei, &align_section, NULL);
if (align_section != NULL
&& parameters->options().relocatable())
gold_warning(_("aligning to section relative value"));
- uint64_t value = this->left_value(eei, eei->result_section_pointer);
+ if (eei->result_alignment_pointer != NULL
+ && align > *eei->result_alignment_pointer)
+ {
+ uint64_t a = align;
+ while ((a & (a - 1)) != 0)
+ a &= a - 1;
+ *eei->result_alignment_pointer = a;
+ }
+
+ uint64_t value = this->left_value(eei, eei->result_section_pointer, NULL);
if (align <= 1)
return value;
return ((value + align - 1) / align) * align;
return new Sizeof_headers_expression();
}
-// In the GNU linker SEGMENT_START basically returns the value for
-// -Ttext, -Tdata, or -Tbss. We could implement this by copying the
-// values from General_options to Parameters. But I doubt that
-// anybody actually uses it. The point of it for the GNU linker was
-// because -Ttext set the address of the .text section rather than the
-// text segment. In gold -Ttext sets the text segment address anyhow.
+// SEGMENT_START.
+
+class Segment_start_expression : public Unary_expression
+{
+ public:
+ Segment_start_expression(const char* segment_name, size_t segment_name_len,
+ Expression* default_value)
+ : Unary_expression(default_value),
+ segment_name_(segment_name, segment_name_len)
+ { }
+
+ uint64_t
+ value(const Expression_eval_info*);
+
+ void
+ print(FILE* f) const
+ {
+ fprintf(f, "SEGMENT_START(\"%s\", ", this->segment_name_.c_str());
+ this->arg_print(f);
+ fprintf(f, ")");
+ }
+
+ private:
+ std::string segment_name_;
+};
+
+uint64_t
+Segment_start_expression::value(const Expression_eval_info* eei)
+{
+ // Check for command line overrides.
+ if (parameters->options().user_set_Ttext()
+ && this->segment_name_ == ".text")
+ return parameters->options().Ttext();
+ else if (parameters->options().user_set_Tdata()
+ && this->segment_name_ == ".data")
+ return parameters->options().Tdata();
+ else if (parameters->options().user_set_Tbss()
+ && this->segment_name_ == ".bss")
+ return parameters->options().Tbss();
+ else
+ {
+ Output_section* dummy;
+ uint64_t ret = this->arg_value(eei, &dummy);
+ // Force the value to be absolute.
+ *eei->result_section_pointer = NULL;
+ return ret;
+ }
+}
extern "C" Expression*
-script_exp_function_segment_start(const char*, size_t, Expression*)
+script_exp_function_segment_start(const char* segment_name,
+ size_t segment_name_len,
+ Expression* default_value)
{
- gold_fatal(_("SEGMENT_START not implemented"));
+ return new Segment_start_expression(segment_name, segment_name_len,
+ default_value);
}
// Functions for memory regions. These can not be implemented unless