forked from Imagelibrary/binutils-gdb
[GOLD] PowerPC recreate eh_frame for stubs on each relax pass
There is a very small but non-zero probability that a stub group contains stubs on one relax pass, but does not on the next. In that case we would get an FDE covering a zero length address range. (Actually, it's even worse. Alignment padding for stubs can mean the address for the non-existent stubs is past the end of the original section to which stubs are attached, and due to the way do_plt_fde_location calculates the length we can get a negative length.) Fixing this properly requires removing the FDE. Also, I have been implementing the __tls_get_addr_opt support for gold, and that stub needs something other than the default FDE. The necessary FDE will depend on the offset to the __tls_get_addr_opt stub, which of course can change during relaxation. That means at the very least, rewriting the FDE on each pass, possibly changing the FDE size. I think that is better done by completely recreating PLT eh_frame FDEs. * ehframe.cc (Fde::operator==): New. (Cie::remove_fde, Eh_frame::remove_ehframe_for_plt): New. * ehframe.h (Fde::operator==): Declare. (Cie::remove_fde, Eh_frame::remove_ehframe_for_plt): Likewise. * layout.cc (Layout::remove_eh_frame_for_plt): New. * layout.h (Layout::remove_eh_frame_for_plt): Declare. * powerpc.cc (Target_powerpc::do_relax): Remove old eh_frame FDEs. (Stub_table::add_eh_frame): Delete eh_frame_added_ condition. Don't add eh_frame for empty stub section. (Stub_table::remove_eh_frame): New.
This commit is contained in:
@@ -3333,6 +3333,16 @@ Target_powerpc<size, big_endian>::do_relax(int pass,
|
||||
if (size == 64 && again)
|
||||
this->brlt_section_->set_current_size(num_huge_branches);
|
||||
|
||||
for (typename Stub_tables::reverse_iterator p = this->stub_tables_.rbegin();
|
||||
p != this->stub_tables_.rend();
|
||||
++p)
|
||||
(*p)->remove_eh_frame(layout);
|
||||
|
||||
for (typename Stub_tables::iterator p = this->stub_tables_.begin();
|
||||
p != this->stub_tables_.end();
|
||||
++p)
|
||||
(*p)->add_eh_frame(layout);
|
||||
|
||||
typedef Unordered_set<Output_section*> Output_sections;
|
||||
Output_sections os_need_update;
|
||||
for (typename Stub_tables::iterator p = this->stub_tables_.begin();
|
||||
@@ -3342,7 +3352,6 @@ Target_powerpc<size, big_endian>::do_relax(int pass,
|
||||
if ((*p)->size_update())
|
||||
{
|
||||
again = true;
|
||||
(*p)->add_eh_frame(layout);
|
||||
os_need_update.insert((*p)->output_section());
|
||||
}
|
||||
}
|
||||
@@ -4244,25 +4253,39 @@ class Stub_table : public Output_relaxed_input_section
|
||||
void
|
||||
add_eh_frame(Layout* layout)
|
||||
{
|
||||
if (!this->eh_frame_added_)
|
||||
if (!parameters->options().ld_generated_unwind_info())
|
||||
return;
|
||||
|
||||
// Since we add stub .eh_frame info late, it must be placed
|
||||
// after all other linker generated .eh_frame info so that
|
||||
// merge mapping need not be updated for input sections.
|
||||
// There is no provision to use a different CIE to that used
|
||||
// by .glink.
|
||||
if (!this->targ_->has_glink())
|
||||
return;
|
||||
|
||||
if (this->plt_size_ + this->branch_size_ + this->need_save_res_ == 0)
|
||||
return;
|
||||
|
||||
layout->add_eh_frame_for_plt(this,
|
||||
Eh_cie<size>::eh_frame_cie,
|
||||
sizeof (Eh_cie<size>::eh_frame_cie),
|
||||
default_fde,
|
||||
sizeof (default_fde));
|
||||
this->eh_frame_added_ = true;
|
||||
}
|
||||
|
||||
void
|
||||
remove_eh_frame(Layout* layout)
|
||||
{
|
||||
if (this->eh_frame_added_)
|
||||
{
|
||||
if (!parameters->options().ld_generated_unwind_info())
|
||||
return;
|
||||
|
||||
// Since we add stub .eh_frame info late, it must be placed
|
||||
// after all other linker generated .eh_frame info so that
|
||||
// merge mapping need not be updated for input sections.
|
||||
// There is no provision to use a different CIE to that used
|
||||
// by .glink.
|
||||
if (!this->targ_->has_glink())
|
||||
return;
|
||||
|
||||
layout->add_eh_frame_for_plt(this,
|
||||
Eh_cie<size>::eh_frame_cie,
|
||||
sizeof (Eh_cie<size>::eh_frame_cie),
|
||||
default_fde,
|
||||
sizeof (default_fde));
|
||||
this->eh_frame_added_ = true;
|
||||
layout->remove_eh_frame_for_plt(this,
|
||||
Eh_cie<size>::eh_frame_cie,
|
||||
sizeof (Eh_cie<size>::eh_frame_cie),
|
||||
default_fde,
|
||||
sizeof (default_fde));
|
||||
this->eh_frame_added_ = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user