Fix problem where script specified both address and region for a section.

If a script specifies both address and region for an output section
declaration, gold ignores the region specification. This can lead to
bogus "moves backward" errors. This patch fixes gold so that if a
section specifies both address and region, it will place the section
at the specified address in the region, and update the location counter
within the region.

gold/
	PR gold/18847
	* script-sections.cc (Memory_region::set_address): New method.
	(Script_sections::find_memory_region): Add explicit_only parameter.
	(Output_section_definition::set_section_addresses): Handle case where
	script specifies both address and vma region.
	* script-sections.h (Script_sections::find_memory_region): Add
	explicit_only parameter.
This commit is contained in:
Cary Coutant 2015-08-26 00:03:04 -07:00
parent 4bfacfd359
commit 7c61d651fd
3 changed files with 54 additions and 19 deletions

@ -1,3 +1,13 @@
2015-08-25 Cary Coutant <ccoutant@gmail.com>
PR gold/18847
* script-sections.cc (Memory_region::set_address): New method.
(Script_sections::find_memory_region): Add explicit_only parameter.
(Output_section_definition::set_section_addresses): Handle case where
script specifies both address and vma region.
* script-sections.h (Script_sections::find_memory_region): Add
explicit_only parameter.
2015-08-25 Cary Coutant <ccoutant@gmail.com> 2015-08-25 Cary Coutant <ccoutant@gmail.com>
PR gold/18859 PR gold/18859

@ -93,7 +93,23 @@ class Memory_region
script_exp_binary_add(this->start_, script_exp_binary_add(this->start_,
script_exp_integer(this->current_offset_)); script_exp_integer(this->current_offset_));
} }
void
set_address(uint64_t addr, const Symbol_table* symtab, const Layout* layout)
{
uint64_t start = this->start_->eval(symtab, layout, false);
uint64_t len = this->length_->eval(symtab, layout, false);
if (addr < start || addr >= start + len)
gold_error(_("address 0x%llx is not within region %s"),
static_cast<unsigned long long>(addr),
this->name_.c_str());
else if (addr < start + this->current_offset_)
gold_error(_("address 0x%llx moves dot backwards in region %s"),
static_cast<unsigned long long>(addr),
this->name_.c_str());
this->current_offset_ = addr - start;
}
void void
increment_offset(std::string section_name, uint64_t amount, increment_offset(std::string section_name, uint64_t amount,
const Symbol_table* symtab, const Layout* layout) const Symbol_table* symtab, const Layout* layout)
@ -105,7 +121,7 @@ class Memory_region
gold_error(_("section %s overflows end of region %s"), gold_error(_("section %s overflows end of region %s"),
section_name.c_str(), this->name_.c_str()); section_name.c_str(), this->name_.c_str());
} }
// Returns true iff there is room left in this region // Returns true iff there is room left in this region
// for AMOUNT more bytes of data. // for AMOUNT more bytes of data.
bool bool
@ -120,7 +136,7 @@ class Memory_region
// are compatible with this region's attributes. // are compatible with this region's attributes.
bool bool
attributes_compatible(elfcpp::Elf_Xword flags, elfcpp::Elf_Xword type) const; attributes_compatible(elfcpp::Elf_Xword flags, elfcpp::Elf_Xword type) const;
void void
add_section(Output_section_definition* sec, bool vma) add_section(Output_section_definition* sec, bool vma)
{ {
@ -2237,6 +2253,7 @@ Memory_region*
Script_sections::find_memory_region( Script_sections::find_memory_region(
Output_section_definition* section, Output_section_definition* section,
bool find_vma_region, bool find_vma_region,
bool explicit_only,
Output_section_definition** previous_section_return) Output_section_definition** previous_section_return)
{ {
if (previous_section_return != NULL) if (previous_section_return != NULL)
@ -2282,15 +2299,18 @@ Script_sections::find_memory_region(
} }
} }
// Make a note of the first memory region whose attributes if (!explicit_only)
// are compatible with the section. If we do not find an {
// explicit region assignment, then we will return this region. // Make a note of the first memory region whose attributes
Output_section* out_sec = section->get_output_section(); // are compatible with the section. If we do not find an
if (first_match == NULL // explicit region assignment, then we will return this region.
&& out_sec != NULL Output_section* out_sec = section->get_output_section();
&& (*mr)->attributes_compatible(out_sec->flags(), if (first_match == NULL
out_sec->type())) && out_sec != NULL
first_match = *mr; && (*mr)->attributes_compatible(out_sec->flags(),
out_sec->type()))
first_match = *mr;
}
} }
// With LMA computations, if an explicit region has not been specified then // With LMA computations, if an explicit region has not been specified then
@ -2350,8 +2370,7 @@ Output_section_definition::set_section_addresses(Symbol_table* symtab,
; ;
else if (this->address_ == NULL) else if (this->address_ == NULL)
{ {
vma_region = script_sections->find_memory_region(this, true, NULL); vma_region = script_sections->find_memory_region(this, true, false, NULL);
if (vma_region != NULL) if (vma_region != NULL)
address = vma_region->get_current_address()->eval(symtab, layout, address = vma_region->get_current_address()->eval(symtab, layout,
false); false);
@ -2359,9 +2378,15 @@ Output_section_definition::set_section_addresses(Symbol_table* symtab,
address = *dot_value; address = *dot_value;
} }
else else
address = this->address_->eval_with_dot(symtab, layout, true, {
*dot_value, NULL, NULL, vma_region = script_sections->find_memory_region(this, true, true, NULL);
dot_alignment, false); address = this->address_->eval_with_dot(symtab, layout, true,
*dot_value, NULL, NULL,
dot_alignment, false);
if (vma_region != NULL)
vma_region->set_address(address, symtab, layout);
}
uint64_t align; uint64_t align;
if (this->align_ == NULL) if (this->align_ == NULL)
{ {
@ -2405,7 +2430,7 @@ Output_section_definition::set_section_addresses(Symbol_table* symtab,
Output_section_definition* previous_section; Output_section_definition* previous_section;
// Determine if an LMA region has been set for this section. // Determine if an LMA region has been set for this section.
lma_region = script_sections->find_memory_region(this, false, lma_region = script_sections->find_memory_region(this, false, false,
&previous_section); &previous_section);
if (lma_region != NULL) if (lma_region != NULL)

@ -240,7 +240,7 @@ class Script_sections
// Find a memory region that should be used by a given output section. // Find a memory region that should be used by a given output section.
Memory_region* Memory_region*
find_memory_region(Output_section_definition*, bool, find_memory_region(Output_section_definition*, bool, bool,
Output_section_definition**); Output_section_definition**);
// Returns true if the provide block of memory is contained // Returns true if the provide block of memory is contained