From 0cfdc76718f8314663016322c94c67afe6bb8f12 Mon Sep 17 00:00:00 2001 From: Alan Modra Date: Sat, 13 Apr 2013 10:12:30 +0000 Subject: [PATCH] * 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. --- gold/ChangeLog | 9 ++++++++ gold/powerpc.cc | 56 ++++++++++++++++++++++++++++++++++++++----------- 2 files changed, 53 insertions(+), 12 deletions(-) diff --git a/gold/ChangeLog b/gold/ChangeLog index 8f154a2d1bb..26058749ab9 100644 --- a/gold/ChangeLog +++ b/gold/ChangeLog @@ -1,3 +1,12 @@ +2013-04-13 Alan Modra + + * 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 PR gold/15354 diff --git a/gold/powerpc.cc b/gold/powerpc.cc index 53bc39345d5..fdb68a1cb4d 100644 --- a/gold/powerpc.cc +++ b/gold/powerpc.cc @@ -1085,7 +1085,7 @@ class Target_powerpc : public Sized_target 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::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* ppcobj = static_cast + *>(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::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* target = + static_cast*>( + parameters->sized_target()); + 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::Relocate::relocate( { Stub_table* 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); + } } } -- 2.30.2