[GOLD] powerpc64le-linux fails to link large Linux kernel
Gold attaches stubs to an existing section in contrast to ld.bfd which inserts a new section for stubs. If we want stubs before branches, then the stubs must be added to the previous section. Adding to the previous section is a disaster if there is a large gap between the previous section and the group. PR gold/20878 * powerpc.cc (Stub_control): Replace stubs_always_before_branch_ with stubs_always_after_branch_, group_end_addr_ with group_start_addr_. (Stub_control::can_add_to_stub_group): Rewrite to suit scanning sections by increasing address. (Target_powerpc::group_sections): Scan that way. Delete corner case. * options.h (--stub-group-size): Update help string.
This commit is contained in:
parent
dc60b26d98
commit
a5018ae555
@ -1,3 +1,15 @@
|
||||
2016-12-07 Alan Modra <amodra@gmail.com>
|
||||
|
||||
PR gold/20878
|
||||
* powerpc.cc (Stub_control): Replace stubs_always_before_branch_
|
||||
with stubs_always_after_branch_, group_end_addr_ with
|
||||
group_start_addr_.
|
||||
(Stub_control::can_add_to_stub_group): Rewrite to suit scanning
|
||||
sections by increasing address.
|
||||
(Target_powerpc::group_sections): Scan that way. Delete corner
|
||||
case.
|
||||
* options.h (--stub-group-size): Update help string.
|
||||
|
||||
2016-12-07 Alan Modra <amodra@gmail.com>
|
||||
|
||||
* powerpc.cc (Stub_table_owner): Provide constructor.
|
||||
|
@ -1216,8 +1216,7 @@ class General_options
|
||||
DEFINE_int(stub_group_size, options::TWO_DASHES , '\0', 1,
|
||||
N_("(ARM, PowerPC only) The maximum distance from instructions "
|
||||
"in a group of sections to their stubs. Negative values mean "
|
||||
"stubs are always after (PowerPC before) the group. 1 means "
|
||||
"use default size"),
|
||||
"stubs are always after the group. 1 means use default size"),
|
||||
N_("SIZE"));
|
||||
|
||||
DEFINE_uint(split_stack_adjust_size, options::TWO_DASHES, '\0', 0x4000,
|
||||
|
131
gold/powerpc.cc
131
gold/powerpc.cc
@ -2439,13 +2439,13 @@ class Stub_control
|
||||
public:
|
||||
// Determine the stub group size. The group size is the absolute
|
||||
// value of the parameter --stub-group-size. If --stub-group-size
|
||||
// is passed a negative value, we restrict stubs to be always before
|
||||
// is passed a negative value, we restrict stubs to be always after
|
||||
// the stubbed branches.
|
||||
Stub_control(int32_t size, bool no_size_errors)
|
||||
: state_(NO_GROUP), stub_group_size_(abs(size)),
|
||||
stubs_always_before_branch_(size < 0),
|
||||
stubs_always_after_branch_(size < 0),
|
||||
suppress_size_errors_(no_size_errors), group_size_(0),
|
||||
group_end_addr_(0), owner_(NULL), output_section_(NULL)
|
||||
group_start_addr_(0), owner_(NULL), output_section_(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
@ -2482,13 +2482,13 @@ class Stub_control
|
||||
|
||||
State state_;
|
||||
uint32_t stub_group_size_;
|
||||
bool stubs_always_before_branch_;
|
||||
bool stubs_always_after_branch_;
|
||||
bool suppress_size_errors_;
|
||||
// Current max size of group. Starts at stub_group_size_ but is
|
||||
// reduced to stub_group_size_/1024 on seeing a section with
|
||||
// external conditional branches.
|
||||
uint32_t group_size_;
|
||||
uint64_t group_end_addr_;
|
||||
uint64_t group_start_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_;
|
||||
@ -2496,8 +2496,8 @@ class Stub_control
|
||||
};
|
||||
|
||||
// Return true iff input section can be handled by current stub
|
||||
// group. Sections are presented to this function in reverse order,
|
||||
// so the first section is the tail of the group.
|
||||
// group. Sections are presented to this function in order,
|
||||
// so the first section is the head of the group.
|
||||
|
||||
bool
|
||||
Stub_control::can_add_to_stub_group(Output_section* o,
|
||||
@ -2518,6 +2518,7 @@ Stub_control::can_add_to_stub_group(Output_section* o,
|
||||
this_size = i->data_size();
|
||||
}
|
||||
|
||||
uint64_t end_addr = start_addr + this_size;
|
||||
uint32_t group_size = this->stub_group_size_;
|
||||
if (has14)
|
||||
this->group_size_ = group_size = group_size >> 10;
|
||||
@ -2532,64 +2533,56 @@ Stub_control::can_add_to_stub_group(Output_section* o,
|
||||
i->relobj()->name().c_str(),
|
||||
i->relobj()->section_name(i->shndx()).c_str(),
|
||||
(long long) this_size,
|
||||
(long long) this->group_end_addr_ - start_addr);
|
||||
(this->state_ == NO_GROUP
|
||||
? this_size
|
||||
: (long long) end_addr - this->group_start_addr_));
|
||||
|
||||
uint64_t end_addr = start_addr + this_size;
|
||||
if (this->state_ == HAS_STUB_SECTION)
|
||||
{
|
||||
// Can we add this section, which is before the stubs, to the
|
||||
// Can we add this section, which is after the stubs, to the
|
||||
// group?
|
||||
if (this->group_end_addr_ - start_addr <= this->group_size_)
|
||||
if (end_addr - this->group_start_addr_ <= this->group_size_)
|
||||
return true;
|
||||
}
|
||||
else
|
||||
else if (this->state_ == FINDING_STUB_SECTION)
|
||||
{
|
||||
// Stubs are added at the end of "owner_".
|
||||
// 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)
|
||||
if ((whole_sec && this->output_section_ == o)
|
||||
|| end_addr - this->group_start_addr_ <= this->group_size_)
|
||||
{
|
||||
// Stubs are added at the end of "owner_".
|
||||
this->owner_ = i;
|
||||
this->output_section_ = o;
|
||||
}
|
||||
|
||||
if (this->state_ == FINDING_STUB_SECTION)
|
||||
{
|
||||
if (this->group_end_addr_ - start_addr <= this->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 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 <= this->group_size_
|
||||
&& this->group_end_addr_ - end_addr <= this->group_size_)
|
||||
{
|
||||
gold_debug(DEBUG_TARGET, "adding before stubs");
|
||||
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_size_ = group_size;
|
||||
this->group_end_addr_ = end_addr;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
gold_unreachable();
|
||||
// The group before the stubs has reached maximum size.
|
||||
// Now see about adding sections after the stubs to the
|
||||
// group. If the current section has a 14-bit branch and
|
||||
// the group before the stubs exceeds group_size_ (because
|
||||
// they didn't have 14-bit branches), don't add sections
|
||||
// after the stubs: The size of stubs for such a large
|
||||
// group may exceed the reach of a 14-bit branch.
|
||||
if (!this->stubs_always_after_branch_
|
||||
&& this_size <= this->group_size_
|
||||
&& start_addr - this->group_start_addr_ <= this->group_size_)
|
||||
{
|
||||
gold_debug(DEBUG_TARGET, "adding after stubs");
|
||||
this->state_ = HAS_STUB_SECTION;
|
||||
this->group_start_addr_ = start_addr;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if (this->state_ == NO_GROUP)
|
||||
{
|
||||
// Only here on very first use of Stub_control
|
||||
this->owner_ = i;
|
||||
this->output_section_ = o;
|
||||
this->state_ = FINDING_STUB_SECTION;
|
||||
this->group_size_ = group_size;
|
||||
this->group_start_addr_ = start_addr;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
gold_unreachable();
|
||||
|
||||
gold_debug(DEBUG_TARGET, "nope, didn't fit\n");
|
||||
|
||||
@ -2599,7 +2592,7 @@ Stub_control::can_add_to_stub_group(Output_section* o,
|
||||
// group.
|
||||
this->state_ = FINDING_STUB_SECTION;
|
||||
this->group_size_ = group_size;
|
||||
this->group_end_addr_ = end_addr;
|
||||
this->group_start_addr_ = start_addr;
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -2619,14 +2612,14 @@ Target_powerpc<size, big_endian>::group_sections(Layout* layout,
|
||||
Layout::Section_list section_list;
|
||||
layout->get_executable_sections(§ion_list);
|
||||
std::stable_sort(section_list.begin(), section_list.end(), Sort_sections());
|
||||
for (Layout::Section_list::reverse_iterator o = section_list.rbegin();
|
||||
o != section_list.rend();
|
||||
for (Layout::Section_list::iterator o = section_list.begin();
|
||||
o != section_list.end();
|
||||
++o)
|
||||
{
|
||||
typedef Output_section::Input_section_list Input_section_list;
|
||||
for (Input_section_list::const_reverse_iterator i
|
||||
= (*o)->input_sections().rbegin();
|
||||
i != (*o)->input_sections().rend();
|
||||
for (Input_section_list::const_iterator i
|
||||
= (*o)->input_sections().begin();
|
||||
i != (*o)->input_sections().end();
|
||||
++i)
|
||||
{
|
||||
if (i->is_input_section()
|
||||
@ -2653,26 +2646,8 @@ Target_powerpc<size, big_endian>::group_sections(Layout* layout,
|
||||
}
|
||||
if (table_owner != NULL)
|
||||
{
|
||||
const Output_section::Input_section* i = stub_control.owner();
|
||||
|
||||
if (tables.size() >= 2 && tables[tables.size() - 2]->owner == i)
|
||||
{
|
||||
// Corner case. A new stub group was made for the first
|
||||
// section (last one looked at here) for some reason, but
|
||||
// the first section is already being used as the owner for
|
||||
// a stub table for following sections. Force it into that
|
||||
// stub group.
|
||||
tables.pop_back();
|
||||
delete table_owner;
|
||||
Powerpc_relobj<size, big_endian>* ppcobj = static_cast
|
||||
<Powerpc_relobj<size, big_endian>*>(i->relobj());
|
||||
ppcobj->set_stub_table(i->shndx(), tables.size() - 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
table_owner->output_section = stub_control.output_section();
|
||||
table_owner->owner = i;
|
||||
}
|
||||
table_owner->output_section = stub_control.output_section();
|
||||
table_owner->owner = stub_control.owner();;
|
||||
}
|
||||
for (typename std::vector<Stub_table_owner*>::iterator t = tables.begin();
|
||||
t != tables.end();
|
||||
|
Loading…
x
Reference in New Issue
Block a user