aboutsummaryrefslogtreecommitdiff
path: root/gold/powerpc.cc
diff options
context:
space:
mode:
Diffstat (limited to 'gold/powerpc.cc')
-rw-r--r--gold/powerpc.cc56
1 files changed, 44 insertions, 12 deletions
diff --git a/gold/powerpc.cc b/gold/powerpc.cc
index 53bc393..fdb68a1 100644
--- a/gold/powerpc.cc
+++ b/gold/powerpc.cc
@@ -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);
+ }
}
}