This is the mail archive of the
binutils@sourceware.org
mailing list for the binutils project.
PowerPC gold failures building linux kernel
- From: Alan Modra <amodra at gmail dot com>
- To: binutils at sourceware dot org
- Date: Sat, 13 Apr 2013 19:30:34 +0930
- Subject: PowerPC gold failures building linux kernel
This fixes some gold failures found when building a recent powerpc64
linux kernel. head_64.o has some "interesting" ftr (feature?) code
sections without exec permission set, containing branches.
[ 7] __ftr_alt_97 PROGBITS 0000000000000000 00b1e0 00016c 00 A 0 0 4
[ 8] .rela__ftr_alt_97 RELA 0000000000000000 014498 000060 18 21 7 8
[ 9] __ftr_fixup PROGBITS 0000000000000000 00b350 003900 00 A 0 0 8
[10] .rela__ftr_fixup RELA 0000000000000000 0144f8 007200 18 21 9 8
[11] .toc PROGBITS 0000000000000000 00ec50 000008 00 WA 0 0 8
[12] __ftr_alt_66 PROGBITS 0000000000000000 00ec58 0002c4 00 A 0 0 4
[13] __mmu_ftr_fixup PROGBITS 0000000000000000 00ef20 000060 00 A 0 0 8
[14] .rela__mmu_ftr_fixup RELA 0000000000000000 01b6f8 0000c0 18 21 13 8
[15] __ftr_alt_96 PROGBITS 0000000000000000 00ef80 000000 00 A 0 0 4
[16] __fw_ftr_fixup PROGBITS 0000000000000000 00ef80 000540 00 A 0 0 8
[17] .rela__fw_ftr_fixup RELA 0000000000000000 01b7b8 000a80 18 21 16 8
These sections are not considered when setting up stub groups, but the
branches are later examined to see whether they might need long branch
stubs, and hit assertions. Fixed by the make_stub() and relocate()
changes. If the branches actually need a stub, gold will warn about
the non-exec code section, and give a relocation overflow.
Another gold failure occurred due to trying to use the same section as
owner for two stub tables. See the "Corner case" comment below.
Lastly, I failed to consider the possibility of non-exec sections and
padding between exec sections when setting up stub groups. Either of
those could lead to stub groups being too large for branches to reach
the stubs. Fixed by the change to can_add_to_stub_group().
* 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.
Index: gold/powerpc.cc
===================================================================
RCS file: /cvs/src/src/gold/powerpc.cc,v
retrieving revision 1.89
diff -u -p -r1.89 powerpc.cc
--- gold/powerpc.cc 11 Apr 2013 01:28:27 -0000 1.89
+++ gold/powerpc.cc 12 Apr 2013 05:02:30 -0000
@@ -1085,7 +1085,7 @@ class Target_powerpc : public Sized_targ
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(Outp
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_
}
}
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
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>::Reloca
{
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);
+ }
}
}
--
Alan Modra
Australia Development Lab, IBM