* powerpc.cc (Stub_control::can_add_to_stub_group): Don't set

owner when sections are not adjacent and exceed group size.
	(Target_powerpc::group_sections): Handle corner case.
	(Target_powerpc::Branch_info::make_stub): Handle case where
	stub table doesn't exist due to branches in non-exec sections.
	(Target_powerpc::Relocate::relocate): Likewise.
This commit is contained in:
Alan Modra 2013-04-13 10:12:30 +00:00
parent 6a11bac307
commit 0cfdc76718
2 changed files with 53 additions and 12 deletions

View File

@ -1,3 +1,12 @@
2013-04-13 Alan Modra <amodra@gmail.com>
* powerpc.cc (Stub_control::can_add_to_stub_group): Don't set
owner when sections are not adjacent and exceed group size.
(Target_powerpc::group_sections): Handle corner case.
(Target_powerpc::Branch_info::make_stub): Handle case where
stub table doesn't exist due to branches in non-exec sections.
(Target_powerpc::Relocate::relocate): Likewise.
2013-04-11 Alan Modra <amodra@gmail.com>
PR gold/15354

View File

@ -1085,7 +1085,7 @@ class Target_powerpc : public Sized_target<size, big_endian>
reloc, this->rela_dyn_section(layout));
}
// Look over all the input sections, deciding where to place stub.
// Look over all the input sections, deciding where to place stubs.
void
group_sections(Layout*, const Task*);
@ -2226,7 +2226,7 @@ class Stub_control
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.
bool
@ -2258,7 +2258,9 @@ Stub_control::can_add_to_stub_group(Output_section* o,
i->relobj()->section_name(i->shndx()).c_str());
if (this->state_ != HAS_STUB_SECTION
&& (!whole_sec || this->output_section_ != o))
&& (!whole_sec || this->output_section_ != o)
&& (this->state_ == NO_GROUP
|| this->group_end_addr_ - end_addr < group_size))
{
this->owner_ = i;
this->output_section_ = o;
@ -2331,7 +2333,25 @@ Target_powerpc<size, big_endian>::group_sections(Layout* layout,
}
}
if (stub_table != NULL)
stub_table->init(stub_control.owner(), stub_control.output_section());
{
const Output_section::Input_section* i = stub_control.owner();
if (!i->is_input_section())
{
// 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.
gold_assert(this->stub_tables_.size() >= 2);
this->stub_tables_.pop_back();
delete stub_table;
Powerpc_relobj<size, big_endian>* ppcobj = static_cast
<Powerpc_relobj<size, big_endian>*>(i->relobj());
ppcobj->set_stub_table(i->shndx(), this->stub_tables_.back());
}
else
stub_table->init(i, stub_control.output_section());
}
}
// If this branch needs a plt call stub, or a long branch stub, make one.
@ -2429,17 +2449,26 @@ Target_powerpc<size, big_endian>::Branch_info::make_stub(
to += this->addend_;
if (stub_table == NULL)
stub_table = this->object_->stub_table(this->shndx_);
gold_assert(stub_table != NULL);
if (size == 64 && is_branch_reloc(this->r_type_))
{
unsigned int dest_shndx;
to = stub_table->targ()->symval_for_branch(symtab, to, gsym,
this->object_,
&dest_shndx);
Target_powerpc<size, big_endian>* target =
static_cast<Target_powerpc<size, big_endian>*>(
parameters->sized_target<size, big_endian>());
to = target->symval_for_branch(symtab, to, gsym,
this->object_, &dest_shndx);
}
Address delta = to - from;
if (delta + max_branch_offset >= 2 * max_branch_offset)
{
if (stub_table == NULL)
{
gold_warning(_("%s:%s: branch in non-executable section,"
" no long branch stub for you"),
this->object_->name().c_str(),
this->object_->section_name(this->shndx_).c_str());
return;
}
stub_table->add_long_branch_entry(this->object_, to);
}
}
@ -6590,10 +6619,13 @@ Target_powerpc<size, big_endian>::Relocate::relocate(
{
Stub_table<size, big_endian>* stub_table
= object->stub_table(relinfo->data_shndx);
gold_assert(stub_table != NULL);
Address off = stub_table->find_long_branch_entry(object, value);
if (off != invalid_address)
value = stub_table->stub_address() + stub_table->plt_size() + off;
if (stub_table != NULL)
{
Address off = stub_table->find_long_branch_entry(object, value);
if (off != invalid_address)
value = (stub_table->stub_address() + stub_table->plt_size()
+ off);
}
}
}