[GOLD] correct grouping of stubs
This patch rewrites the rather obscure can_add_to_stub_group, fixing a problem with the handling of sections containing conditional external branches. When a section group contains any such section, the group size needs to be limited to a much smaller size than groups with only non-conditional external branches. PR 20523 * powerpc.cc (class Stub_control): Add has14_. Comment owner_. (Stub_control::can_add_to_stub_group): Correct grouping of sections containing 14-bit external branches. When returning false, set state_ to reflect the fact that we have one section for the next group. Rewrite most of function for clarity. Add and expand comments. (Target_powerpc::do_relax): Print stub group size retry in hex.
This commit is contained in:
parent
7229b687db
commit
57f6d32dea
@ -1,3 +1,14 @@
|
|||||||
|
2016-08-30 Alan Modra <amodra@gmail.com>
|
||||||
|
|
||||||
|
PR 20523
|
||||||
|
* powerpc.cc (class Stub_control): Add has14_. Comment owner_.
|
||||||
|
(Stub_control::can_add_to_stub_group): Correct grouping of
|
||||||
|
sections containing 14-bit external branches. When returning
|
||||||
|
false, set state_ to reflect the fact that we have one section
|
||||||
|
for the next group. Rewrite most of function for clarity.
|
||||||
|
Add and expand comments.
|
||||||
|
(Target_powerpc::do_relax): Print stub group size retry in hex.
|
||||||
|
|
||||||
2016-08-26 Han Shen <shenhan@google.com>
|
2016-08-26 Han Shen <shenhan@google.com>
|
||||||
|
|
||||||
PR gold/20529 - relaxing loop never ends.
|
PR gold/20529 - relaxing loop never ends.
|
||||||
|
|||||||
105
gold/powerpc.cc
105
gold/powerpc.cc
@ -2441,7 +2441,7 @@ class Stub_control
|
|||||||
: state_(NO_GROUP), stub_group_size_(abs(size)),
|
: state_(NO_GROUP), stub_group_size_(abs(size)),
|
||||||
stub14_group_size_(abs(size) >> 10),
|
stub14_group_size_(abs(size) >> 10),
|
||||||
stubs_always_before_branch_(size < 0),
|
stubs_always_before_branch_(size < 0),
|
||||||
suppress_size_errors_(no_size_errors),
|
suppress_size_errors_(no_size_errors), has14_(false),
|
||||||
group_end_addr_(0), owner_(NULL), output_section_(NULL)
|
group_end_addr_(0), owner_(NULL), output_section_(NULL)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@ -2482,21 +2482,23 @@ class Stub_control
|
|||||||
uint32_t stub14_group_size_;
|
uint32_t stub14_group_size_;
|
||||||
bool stubs_always_before_branch_;
|
bool stubs_always_before_branch_;
|
||||||
bool suppress_size_errors_;
|
bool suppress_size_errors_;
|
||||||
|
bool has14_;
|
||||||
uint64_t group_end_addr_;
|
uint64_t group_end_addr_;
|
||||||
|
// owner_ and output_section_ specify the section to which stubs are
|
||||||
|
// attached. The stubs are placed at the end of this section.
|
||||||
const Output_section::Input_section* owner_;
|
const Output_section::Input_section* owner_;
|
||||||
Output_section* output_section_;
|
Output_section* output_section_;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Return true iff input section can be handled by current stub
|
// Return true iff input section can be handled by current stub
|
||||||
// group.
|
// group. Sections are presented to this function in reverse order,
|
||||||
|
// so the first section is the tail of the group.
|
||||||
|
|
||||||
bool
|
bool
|
||||||
Stub_control::can_add_to_stub_group(Output_section* o,
|
Stub_control::can_add_to_stub_group(Output_section* o,
|
||||||
const Output_section::Input_section* i,
|
const Output_section::Input_section* i,
|
||||||
bool has14)
|
bool has14)
|
||||||
{
|
{
|
||||||
uint32_t group_size
|
|
||||||
= has14 ? this->stub14_group_size_ : this->stub_group_size_;
|
|
||||||
bool whole_sec = o->order() == ORDER_INIT || o->order() == ORDER_FINI;
|
bool whole_sec = o->order() == ORDER_INIT || o->order() == ORDER_FINI;
|
||||||
uint64_t this_size;
|
uint64_t this_size;
|
||||||
uint64_t start_addr = o->address();
|
uint64_t start_addr = o->address();
|
||||||
@ -2510,46 +2512,81 @@ Stub_control::can_add_to_stub_group(Output_section* o,
|
|||||||
start_addr += i->relobj()->output_section_offset(i->shndx());
|
start_addr += i->relobj()->output_section_offset(i->shndx());
|
||||||
this_size = i->data_size();
|
this_size = i->data_size();
|
||||||
}
|
}
|
||||||
uint64_t end_addr = start_addr + this_size;
|
|
||||||
bool toobig = this_size > group_size;
|
|
||||||
|
|
||||||
if (toobig && !this->suppress_size_errors_)
|
uint32_t group_size
|
||||||
|
= has14 ? this->stub14_group_size_ : this->stub_group_size_;
|
||||||
|
uint64_t end_addr = start_addr + this_size;
|
||||||
|
|
||||||
|
if (this_size > group_size && !this->suppress_size_errors_)
|
||||||
gold_warning(_("%s:%s exceeds group size"),
|
gold_warning(_("%s:%s exceeds group size"),
|
||||||
i->relobj()->name().c_str(),
|
i->relobj()->name().c_str(),
|
||||||
i->relobj()->section_name(i->shndx()).c_str());
|
i->relobj()->section_name(i->shndx()).c_str());
|
||||||
|
|
||||||
if (this->state_ != HAS_STUB_SECTION
|
this->has14_ = this->has14_ || has14;
|
||||||
&& (!whole_sec || this->output_section_ != o)
|
group_size = this->has14_ ? this->stub14_group_size_ : this->stub_group_size_;
|
||||||
&& (this->state_ == NO_GROUP
|
|
||||||
|| this->group_end_addr_ - end_addr < group_size))
|
|
||||||
{
|
|
||||||
this->owner_ = i;
|
|
||||||
this->output_section_ = o;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this->state_ == NO_GROUP)
|
if (this->state_ == HAS_STUB_SECTION)
|
||||||
{
|
{
|
||||||
this->state_ = FINDING_STUB_SECTION;
|
// Can we add this section, which is before the stubs, to the
|
||||||
this->group_end_addr_ = end_addr;
|
// group?
|
||||||
}
|
if (this->group_end_addr_ - start_addr <= group_size)
|
||||||
else if (this->group_end_addr_ - start_addr < group_size)
|
return true;
|
||||||
;
|
|
||||||
// Adding this section would make the group larger than GROUP_SIZE.
|
|
||||||
else if (this->state_ == FINDING_STUB_SECTION
|
|
||||||
&& !this->stubs_always_before_branch_
|
|
||||||
&& !toobig)
|
|
||||||
{
|
|
||||||
// But wait, there's more! Input sections up to GROUP_SIZE
|
|
||||||
// bytes before the stub table can be handled by it too.
|
|
||||||
this->state_ = HAS_STUB_SECTION;
|
|
||||||
this->group_end_addr_ = end_addr;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
this->state_ = NO_GROUP;
|
// Stubs are added at the end of "owner_".
|
||||||
return false;
|
// The current section can always be the stub owner, except when
|
||||||
|
// whole_sec is true and the current section isn't the last of
|
||||||
|
// the pasted sections. (This restriction for the whole_sec
|
||||||
|
// case is just to simplify the corner case mentioned in
|
||||||
|
// group_sections.)
|
||||||
|
// Note that "owner_" itself is not necessarily part of the
|
||||||
|
// group of sections served by these stubs!
|
||||||
|
if (!whole_sec || this->output_section_ != o)
|
||||||
|
{
|
||||||
|
this->owner_ = i;
|
||||||
|
this->output_section_ = o;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this->state_ == FINDING_STUB_SECTION)
|
||||||
|
{
|
||||||
|
if (this->group_end_addr_ - start_addr <= group_size)
|
||||||
|
return true;
|
||||||
|
// The group after the stubs has reached maximum size.
|
||||||
|
// Now see about adding sections before the stubs to the
|
||||||
|
// group. If the current section has a 14-bit branch and
|
||||||
|
// the group after the stubs exceeds stub14_group_size_
|
||||||
|
// (because they didn't have 14-bit branches), don't add
|
||||||
|
// sections before the stubs: The size of stubs for such a
|
||||||
|
// large group may exceed the reach of a 14-bit branch.
|
||||||
|
if (!this->stubs_always_before_branch_
|
||||||
|
&& this_size <= group_size
|
||||||
|
&& this->group_end_addr_ - end_addr <= group_size)
|
||||||
|
{
|
||||||
|
this->state_ = HAS_STUB_SECTION;
|
||||||
|
this->group_end_addr_ = end_addr;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (this->state_ == NO_GROUP)
|
||||||
|
{
|
||||||
|
// Only here on very first use of Stub_control
|
||||||
|
this->state_ = FINDING_STUB_SECTION;
|
||||||
|
this->group_end_addr_ = end_addr;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
gold_unreachable();
|
||||||
}
|
}
|
||||||
return true;
|
|
||||||
|
// The section fails to fit in the current group. Set up a few
|
||||||
|
// things for the next group. owner_ and output_section_ will be
|
||||||
|
// set later after we've retrieved those values for the current
|
||||||
|
// group.
|
||||||
|
this->state_ = FINDING_STUB_SECTION;
|
||||||
|
this->has14_ = has14;
|
||||||
|
this->group_end_addr_ = end_addr;
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Look over all the input sections, deciding where to place stubs.
|
// Look over all the input sections, deciding where to place stubs.
|
||||||
@ -2887,7 +2924,7 @@ Target_powerpc<size, big_endian>::do_relax(int pass,
|
|||||||
}
|
}
|
||||||
this->stub_tables_.clear();
|
this->stub_tables_.clear();
|
||||||
this->stub_group_size_ = this->stub_group_size_ / 4 * 3;
|
this->stub_group_size_ = this->stub_group_size_ / 4 * 3;
|
||||||
gold_info(_("%s: stub group size is too large; retrying with %d"),
|
gold_info(_("%s: stub group size is too large; retrying with %#x"),
|
||||||
program_name, this->stub_group_size_);
|
program_name, this->stub_group_size_);
|
||||||
this->group_sections(layout, task, true);
|
this->group_sections(layout, task, true);
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user