[GOLD] PowerPC64 huge branch dynamic relocs
PowerPC64 gold and ld.bfd implement an indirect branch trampoline, used when the destination of a branch exceeds a bounce through another "b" instruction. When generating PIEs or shared libraries, the addresses need dynamic relocations. This was implemented in gold using a dedicated relocation section, but this means the relative relocations for these addresses are not sorted properly with other dynamic relative relocations: gold doesn't support merging relocation sections, then sorting. Instead we need to use a single .rela.dyn section. This is done by increasing the size of rela_dyn_ during do_relax to account for needed dynamic relocations, delaying adding the actual relocations until the end of relaxation once the layout has stabilised. * powerpc.cc (Target_powerpc): Add rela_dyn_size_; (update_current_size): New function. (Target_powerpc::do_relax): Capture the size of rela_dyn_ at the start of relaxation. Artifically increase its size during relaxation to account for needed indirect branches, and add those relocations at the end. (Output_data_brlt_powerpc::rel_, reset_brlt_sizes), (finalize_brlt_sizes, add_reloc, set_current_size): Delete. (Target_powerpc::make_brlt_section): Don't make reloc section.
This commit is contained in:
parent
bdad2ad579
commit
5a97377e55
1 changed files with 38 additions and 61 deletions
|
@ -1763,6 +1763,8 @@ class Target_powerpc : public Sized_target<size, big_endian>
|
||||||
Branches branch_info_;
|
Branches branch_info_;
|
||||||
Tocsave_loc tocsave_loc_;
|
Tocsave_loc tocsave_loc_;
|
||||||
|
|
||||||
|
off_t rela_dyn_size_;
|
||||||
|
|
||||||
bool power10_relocs_;
|
bool power10_relocs_;
|
||||||
bool plt_thread_safe_;
|
bool plt_thread_safe_;
|
||||||
bool plt_localentry0_;
|
bool plt_localentry0_;
|
||||||
|
@ -3687,6 +3689,18 @@ Target_powerpc<size, big_endian>::Branch_info::make_stub(
|
||||||
return ok;
|
return ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Helper for do_relax, avoiding checks that size, address and offset
|
||||||
|
// are not set more than once.
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
update_current_size(Output_section_data_build* od, off_t cur_size)
|
||||||
|
{
|
||||||
|
od->reset_address_and_file_offset();
|
||||||
|
od->set_current_data_size(cur_size);
|
||||||
|
od->finalize_data_size();
|
||||||
|
od->output_section()->set_section_offsets_need_adjustment();
|
||||||
|
}
|
||||||
|
|
||||||
// Relaxation hook. This is where we do stub generation.
|
// Relaxation hook. This is where we do stub generation.
|
||||||
|
|
||||||
template<int size, bool big_endian>
|
template<int size, bool big_endian>
|
||||||
|
@ -3752,10 +3766,11 @@ Target_powerpc<size, big_endian>::do_relax(int pass,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this->plt_thread_safe_ = thread_safe;
|
this->plt_thread_safe_ = thread_safe;
|
||||||
}
|
|
||||||
|
|
||||||
if (pass == 1)
|
if (parameters->options().output_is_position_independent())
|
||||||
{
|
this->rela_dyn_size_
|
||||||
|
= this->rela_dyn_section(layout)->current_data_size();
|
||||||
|
|
||||||
this->stub_group_size_ = parameters->options().stub_group_size();
|
this->stub_group_size_ = parameters->options().stub_group_size();
|
||||||
bool no_size_errors = true;
|
bool no_size_errors = true;
|
||||||
if (this->stub_group_size_ == 1)
|
if (this->stub_group_size_ == 1)
|
||||||
|
@ -3868,7 +3883,15 @@ Target_powerpc<size, big_endian>::do_relax(int pass,
|
||||||
if (size == 64 && num_huge_branches != 0)
|
if (size == 64 && num_huge_branches != 0)
|
||||||
this->make_brlt_section(layout);
|
this->make_brlt_section(layout);
|
||||||
if (size == 64 && again)
|
if (size == 64 && again)
|
||||||
this->brlt_section_->set_current_size(num_huge_branches);
|
{
|
||||||
|
update_current_size(this->brlt_section_, num_huge_branches * 16);
|
||||||
|
if (parameters->options().output_is_position_independent())
|
||||||
|
{
|
||||||
|
const unsigned int reloc_size = elfcpp::Elf_sizes<size>::rela_size;
|
||||||
|
off_t cur = this->rela_dyn_size_ + num_huge_branches * reloc_size;
|
||||||
|
update_current_size(this->rela_dyn_, cur);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for (typename Stub_tables::reverse_iterator p = this->stub_tables_.rbegin();
|
for (typename Stub_tables::reverse_iterator p = this->stub_tables_.rbegin();
|
||||||
p != this->stub_tables_.rend();
|
p != this->stub_tables_.rend();
|
||||||
|
@ -3937,15 +3960,21 @@ Target_powerpc<size, big_endian>::do_relax(int pass,
|
||||||
&& parameters->options().output_is_position_independent())
|
&& parameters->options().output_is_position_independent())
|
||||||
{
|
{
|
||||||
// Fill in the BRLT relocs.
|
// Fill in the BRLT relocs.
|
||||||
this->brlt_section_->reset_brlt_sizes();
|
this->rela_dyn_->reset_data_size();
|
||||||
|
this->rela_dyn_->set_current_data_size(this->rela_dyn_size_);
|
||||||
for (typename Branch_lookup_table::const_iterator p
|
for (typename Branch_lookup_table::const_iterator p
|
||||||
= this->branch_lookup_table_.begin();
|
= this->branch_lookup_table_.begin();
|
||||||
p != this->branch_lookup_table_.end();
|
p != this->branch_lookup_table_.end();
|
||||||
++p)
|
++p)
|
||||||
{
|
{
|
||||||
this->brlt_section_->add_reloc(p->first, p->second);
|
this->rela_dyn_->add_relative(elfcpp::R_POWERPC_RELATIVE,
|
||||||
|
this->brlt_section_, p->second,
|
||||||
|
p->first);
|
||||||
}
|
}
|
||||||
this->brlt_section_->finalize_brlt_sizes();
|
this->rela_dyn_->finalize_data_size();
|
||||||
|
const unsigned int reloc_size = elfcpp::Elf_sizes<size>::rela_size;
|
||||||
|
gold_assert(this->rela_dyn_->data_size()
|
||||||
|
== this->rela_dyn_size_ + num_huge_branches * reloc_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!again
|
if (!again
|
||||||
|
@ -4554,52 +4583,11 @@ class Output_data_brlt_powerpc : public Output_section_data_build
|
||||||
typedef Output_data_reloc<elfcpp::SHT_RELA, true,
|
typedef Output_data_reloc<elfcpp::SHT_RELA, true,
|
||||||
size, big_endian> Reloc_section;
|
size, big_endian> Reloc_section;
|
||||||
|
|
||||||
Output_data_brlt_powerpc(Target_powerpc<size, big_endian>* targ,
|
Output_data_brlt_powerpc(Target_powerpc<size, big_endian>* targ)
|
||||||
Reloc_section* brlt_rel)
|
|
||||||
: Output_section_data_build(size == 32 ? 4 : 8),
|
: Output_section_data_build(size == 32 ? 4 : 8),
|
||||||
rel_(brlt_rel),
|
|
||||||
targ_(targ)
|
targ_(targ)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
void
|
|
||||||
reset_brlt_sizes()
|
|
||||||
{
|
|
||||||
this->reset_data_size();
|
|
||||||
this->rel_->reset_data_size();
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
finalize_brlt_sizes()
|
|
||||||
{
|
|
||||||
this->finalize_data_size();
|
|
||||||
this->rel_->finalize_data_size();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add a reloc for an entry in the BRLT.
|
|
||||||
void
|
|
||||||
add_reloc(Address to, unsigned int off)
|
|
||||||
{ this->rel_->add_relative(elfcpp::R_POWERPC_RELATIVE, this, off, to); }
|
|
||||||
|
|
||||||
// Update section and reloc section size.
|
|
||||||
void
|
|
||||||
set_current_size(unsigned int num_branches)
|
|
||||||
{
|
|
||||||
this->reset_address_and_file_offset();
|
|
||||||
this->set_current_data_size(num_branches * 16);
|
|
||||||
this->finalize_data_size();
|
|
||||||
Output_section* os = this->output_section();
|
|
||||||
os->set_section_offsets_need_adjustment();
|
|
||||||
if (this->rel_ != NULL)
|
|
||||||
{
|
|
||||||
const unsigned int reloc_size = elfcpp::Elf_sizes<size>::rela_size;
|
|
||||||
this->rel_->reset_address_and_file_offset();
|
|
||||||
this->rel_->set_current_data_size(num_branches * reloc_size);
|
|
||||||
this->rel_->finalize_data_size();
|
|
||||||
Output_section* os = this->rel_->output_section();
|
|
||||||
os->set_section_offsets_need_adjustment();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void
|
void
|
||||||
do_adjust_output_section(Output_section* os)
|
do_adjust_output_section(Output_section* os)
|
||||||
|
@ -4617,8 +4605,6 @@ class Output_data_brlt_powerpc : public Output_section_data_build
|
||||||
void
|
void
|
||||||
do_write(Output_file*);
|
do_write(Output_file*);
|
||||||
|
|
||||||
// The reloc section.
|
|
||||||
Reloc_section* rel_;
|
|
||||||
Target_powerpc<size, big_endian>* targ_;
|
Target_powerpc<size, big_endian>* targ_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -4630,24 +4616,15 @@ Target_powerpc<size, big_endian>::make_brlt_section(Layout* layout)
|
||||||
{
|
{
|
||||||
if (size == 64 && this->brlt_section_ == NULL)
|
if (size == 64 && this->brlt_section_ == NULL)
|
||||||
{
|
{
|
||||||
Reloc_section* brlt_rel = NULL;
|
|
||||||
bool is_pic = parameters->options().output_is_position_independent();
|
bool is_pic = parameters->options().output_is_position_independent();
|
||||||
if (is_pic)
|
if (is_pic)
|
||||||
{
|
{
|
||||||
// When PIC we can't fill in .branch_lt but must initialise at
|
// When PIC we can't fill in .branch_lt but must initialise at
|
||||||
// runtime via dynamic relocations.
|
// runtime via dynamic relocations.
|
||||||
this->rela_dyn_section(layout);
|
this->rela_dyn_section(layout);
|
||||||
// FIXME: This reloc section won't have its relative relocs
|
|
||||||
// sorted properly among the other relative relocs in rela_dyn_
|
|
||||||
// but it must be a separate section due to needing to call
|
|
||||||
// reset_data_size().
|
|
||||||
brlt_rel = new Reloc_section(false);
|
|
||||||
if (this->rela_dyn_->output_section())
|
|
||||||
this->rela_dyn_->output_section()
|
|
||||||
->add_output_section_data(brlt_rel);
|
|
||||||
}
|
}
|
||||||
this->brlt_section_
|
this->brlt_section_
|
||||||
= new Output_data_brlt_powerpc<size, big_endian>(this, brlt_rel);
|
= new Output_data_brlt_powerpc<size, big_endian>(this);
|
||||||
if (this->plt_ && is_pic && this->plt_->output_section())
|
if (this->plt_ && is_pic && this->plt_->output_section())
|
||||||
this->plt_->output_section()
|
this->plt_->output_section()
|
||||||
->add_output_section_data(this->brlt_section_);
|
->add_output_section_data(this->brlt_section_);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue