[GOLD] PowerPC notoc eh_frame
When generating notoc call and branch stubs without the benefit of
pc-relative insns, the stubs need to use LR to access the run time PC.
All LR changes must be described in .eh_frame if we're to support
unwinding through asynchronous exceptions. That's what this patch
does.
The patch has gone through way too many iterations. At first I
attempted to add multiple FDEs, one for each stub. That ran into
difficulties with do_plt_fde_location which is only capable of setting
the address of a single FDE per Output_data section, and with removing
any FDEs added on a previous do_relax pass. Removing FDEs (git commit
be897fb774
) went overboard in matching the FDE contents. That means
either stashing the contents created for add_eh_frame_for_plt to use
when calling remove_eh_frame_for_plt, or recreating contents on the
fly (*) just to remove FDEs. In fact, FDE content matching is quite
unnecesary. FDEs added by a previous do_relax pass are those with
u_.from_linker.post_map set. So they can easily be recognised just by
looking at that flag. This patch keeps that part of the multiple FDE
changes.
In the end I went for just one FDE per stub group to describe the call
stubs. That's reasonably efficient for the common case of only
needing to describe the __tls_get_addr_opt call stub. We don't expect
to be making many calls using notoc stubs without pc-relative insns.
*) Which has it's own set of problems. The contents must be recreated
using the old stub layout, but .eh_frame size can affect stub
requirements so you need to temporarily keep the old .eh_frame size
when creating new stubs, then reset .eh_frame size before adding new
FDEs.
* ehframe.cc (Fde::operator==): Delete.
(Cie::remove_fde): Delete.
(Eh_frame::remove_ehframe_for_plt): Delete fde_data and fde_length
parameters. Remove all post-map plt FDEs.
* ehframe.h (Fde:post_map): Make const, add variant to compare plt.
(Fde::operator==): Delete.
(Cie::remove_fde): Implement here.
(Cie::last_fde): New accessor.
(Eh_frame::remove_ehframe_for_plt): Update prototype.
* layout.cc (Layout::remove_eh_frame_for_plt): Delete fde_data and
fde_length parameters.
* layout.h (Layout::remove_eh_frame_for_plt): Update prototype.
* powerpc.cc (Stub_table::tls_get_addr_opt_bctrl_): Delete.
(Stub_table::plt_fde_len_, plt_fde_, init_plt_fde): Delete.
(Stub_table::add_plt_call_entry): Don't set tls_get_addr_opt_bctrl_.
(eh_advance): New function.
(stub_sort): New function.
(Stub_table::add_eh_frame): Emit eh_frame for notoc plt calls and
branches as well as __tls_get_addr_opt plt call stub.
(Stub_table::remove_eh_frame): Update to suit.
This commit is contained in:
parent
32f5984419
commit
220f99066d
@ -1,3 +1,26 @@
|
||||
2019-07-13 Alan Modra <amodra@gmail.com>
|
||||
|
||||
* ehframe.cc (Fde::operator==): Delete.
|
||||
(Cie::remove_fde): Delete.
|
||||
(Eh_frame::remove_ehframe_for_plt): Delete fde_data and fde_length
|
||||
parameters. Remove all post-map plt FDEs.
|
||||
* ehframe.h (Fde:post_map): Make const, add variant to compare plt.
|
||||
(Fde::operator==): Delete.
|
||||
(Cie::remove_fde): Implement here.
|
||||
(Cie::last_fde): New accessor.
|
||||
(Eh_frame::remove_ehframe_for_plt): Update prototype.
|
||||
* layout.cc (Layout::remove_eh_frame_for_plt): Delete fde_data and
|
||||
fde_length parameters.
|
||||
* layout.h (Layout::remove_eh_frame_for_plt): Update prototype.
|
||||
* powerpc.cc (Stub_table::tls_get_addr_opt_bctrl_): Delete.
|
||||
(Stub_table::plt_fde_len_, plt_fde_, init_plt_fde): Delete.
|
||||
(Stub_table::add_plt_call_entry): Don't set tls_get_addr_opt_bctrl_.
|
||||
(eh_advance): New function.
|
||||
(stub_sort): New function.
|
||||
(Stub_table::add_eh_frame): Emit eh_frame for notoc plt calls and
|
||||
branches as well as __tls_get_addr_opt plt call stub.
|
||||
(Stub_table::remove_eh_frame): Update to suit.
|
||||
|
||||
2019-07-13 Alan Modra <amodra@gmail.com>
|
||||
|
||||
* powerpc.cc (Target_powerpc::maybe_skip_tls_get_addr_call): Handle
|
||||
|
@ -325,21 +325,6 @@ Eh_frame_hdr::get_fde_addresses(Output_file* of,
|
||||
|
||||
// Class Fde.
|
||||
|
||||
bool
|
||||
Fde::operator==(const Fde& that) const
|
||||
{
|
||||
if (this->object_ != that.object_
|
||||
|| this->contents_ != that.contents_)
|
||||
return false;
|
||||
if (this->object_ == NULL)
|
||||
return (this->u_.from_linker.plt == that.u_.from_linker.plt
|
||||
&& this->u_.from_linker.post_map == that.u_.from_linker.post_map);
|
||||
else
|
||||
return (this->u_.from_object.shndx == that.u_.from_object.shndx
|
||||
&& (this->u_.from_object.input_offset
|
||||
== that.u_.from_object.input_offset));
|
||||
}
|
||||
|
||||
// Write the FDE to OVIEW starting at OFFSET. CIE_OFFSET is the
|
||||
// offset of the CIE in OVIEW. OUTPUT_OFFSET is the offset of the
|
||||
// Eh_frame section within the output section. FDE_ENCODING is the
|
||||
@ -458,15 +443,6 @@ Cie::set_output_offset(section_offset_type output_offset,
|
||||
return output_offset + length;
|
||||
}
|
||||
|
||||
// Remove FDE. Only the last FDE using this CIE may be removed.
|
||||
|
||||
void
|
||||
Cie::remove_fde(const Fde* fde)
|
||||
{
|
||||
gold_assert(*fde == *this->fdes_.back());
|
||||
this->fdes_.pop_back();
|
||||
}
|
||||
|
||||
// Write the CIE to OVIEW starting at OFFSET. OUTPUT_OFFSET is the
|
||||
// offset of the Eh_frame section within the output section. Round up
|
||||
// the bytes to ADDRALIGN. ADDRESS is the virtual address of OVIEW.
|
||||
@ -1167,26 +1143,31 @@ Eh_frame::add_ehframe_for_plt(Output_data* plt, const unsigned char* cie_data,
|
||||
this->final_data_size_ += align_address(fde_length + 8, this->addralign());
|
||||
}
|
||||
|
||||
// Remove unwind information for a PLT. Only the last FDE added may be removed.
|
||||
// Remove all post-map unwind information for a PLT.
|
||||
|
||||
void
|
||||
Eh_frame::remove_ehframe_for_plt(Output_data* plt,
|
||||
const unsigned char* cie_data,
|
||||
size_t cie_length,
|
||||
const unsigned char* fde_data,
|
||||
size_t fde_length)
|
||||
size_t cie_length)
|
||||
{
|
||||
if (!this->mappings_are_done_)
|
||||
return;
|
||||
|
||||
Cie cie(NULL, 0, 0, elfcpp::DW_EH_PE_pcrel | elfcpp::DW_EH_PE_sdata4, "",
|
||||
cie_data, cie_length);
|
||||
Cie_offsets::iterator find_cie = this->cie_offsets_.find(&cie);
|
||||
gold_assert (find_cie != this->cie_offsets_.end());
|
||||
Cie* pcie = *find_cie;
|
||||
|
||||
Fde* fde = new Fde(plt, fde_data, fde_length, this->mappings_are_done_);
|
||||
pcie->remove_fde(fde);
|
||||
|
||||
if (this->mappings_are_done_)
|
||||
this->final_data_size_ -= align_address(fde_length + 8, this->addralign());
|
||||
while (pcie->fde_count() != 0)
|
||||
{
|
||||
const Fde* fde = pcie->last_fde();
|
||||
if (!fde->post_map(plt))
|
||||
break;
|
||||
size_t length = fde->length();
|
||||
this->final_data_size_ -= align_address(length + 8, this->addralign());
|
||||
pcie->remove_fde();
|
||||
}
|
||||
}
|
||||
|
||||
// Return the number of FDEs.
|
||||
|
@ -203,9 +203,14 @@ class Fde
|
||||
|
||||
// Return whether this FDE was added after merge mapping.
|
||||
bool
|
||||
post_map()
|
||||
post_map() const
|
||||
{ return this->object_ == NULL && this->u_.from_linker.post_map; }
|
||||
|
||||
// Return whether this FDE was added for the PLT after merge mapping.
|
||||
bool
|
||||
post_map(const Output_data* plt) const
|
||||
{ return this->post_map() && this->u_.from_linker.plt == plt; }
|
||||
|
||||
// Write the FDE to OVIEW starting at OFFSET. FDE_ENCODING is the
|
||||
// encoding, from the CIE. Round up the bytes to ADDRALIGN if
|
||||
// necessary. ADDRESS is the virtual address of OVIEW. Record the
|
||||
@ -217,8 +222,6 @@ class Fde
|
||||
section_offset_type cie_offset, unsigned char fde_encoding,
|
||||
Eh_frame_hdr* eh_frame_hdr);
|
||||
|
||||
bool operator==(const Fde&) const;
|
||||
|
||||
private:
|
||||
// The object in which this FDE was seen. This will be NULL for a
|
||||
// linker generated FDE.
|
||||
@ -300,9 +303,15 @@ class Cie
|
||||
add_fde(Fde* fde)
|
||||
{ this->fdes_.push_back(fde); }
|
||||
|
||||
// Remove an FDE associated with this CIE. Only the last FDE may be removed.
|
||||
// Remove the last FDE associated with this CIE.
|
||||
void
|
||||
remove_fde(const Fde*);
|
||||
remove_fde()
|
||||
{ this->fdes_.pop_back(); }
|
||||
|
||||
// Access the last FDE associated with this CIE.
|
||||
const Fde*
|
||||
last_fde() const
|
||||
{ return this->fdes_.back(); }
|
||||
|
||||
// Return the number of FDEs.
|
||||
unsigned int
|
||||
@ -411,12 +420,10 @@ class Eh_frame : public Output_section_data
|
||||
size_t cie_length, const unsigned char* fde_data,
|
||||
size_t fde_length);
|
||||
|
||||
// Remove unwind information for a PLT. Only the last FDE added may
|
||||
// be removed.
|
||||
// Remove all post-map unwind information for a PLT.
|
||||
void
|
||||
remove_ehframe_for_plt(Output_data* plt, const unsigned char* cie_data,
|
||||
size_t cie_length, const unsigned char* fde_data,
|
||||
size_t fde_length);
|
||||
size_t cie_length);
|
||||
|
||||
// Return the number of FDEs.
|
||||
unsigned int
|
||||
|
@ -1604,21 +1604,18 @@ Layout::add_eh_frame_for_plt(Output_data* plt, const unsigned char* cie_data,
|
||||
}
|
||||
}
|
||||
|
||||
// Remove .eh_frame information for a PLT. FDEs using the CIE must
|
||||
// be removed in reverse order to the order they were added.
|
||||
// Remove all post-map .eh_frame information for a PLT.
|
||||
|
||||
void
|
||||
Layout::remove_eh_frame_for_plt(Output_data* plt, const unsigned char* cie_data,
|
||||
size_t cie_length, const unsigned char* fde_data,
|
||||
size_t fde_length)
|
||||
size_t cie_length)
|
||||
{
|
||||
if (parameters->incremental())
|
||||
{
|
||||
// FIXME: Maybe this could work some day....
|
||||
return;
|
||||
}
|
||||
this->eh_frame_data_->remove_ehframe_for_plt(plt, cie_data, cie_length,
|
||||
fde_data, fde_length);
|
||||
this->eh_frame_data_->remove_ehframe_for_plt(plt, cie_data, cie_length);
|
||||
}
|
||||
|
||||
// Scan a .debug_info or .debug_types section, and add summary
|
||||
|
@ -666,12 +666,10 @@ class Layout
|
||||
size_t cie_length, const unsigned char* fde_data,
|
||||
size_t fde_length);
|
||||
|
||||
// Remove .eh_frame information for a PLT. FDEs using the CIE must
|
||||
// be removed in reverse order to the order they were added.
|
||||
// Remove all post-map .eh_frame information for a PLT.
|
||||
void
|
||||
remove_eh_frame_for_plt(Output_data* plt, const unsigned char* cie_data,
|
||||
size_t cie_length, const unsigned char* fde_data,
|
||||
size_t fde_length);
|
||||
size_t cie_length);
|
||||
|
||||
// Scan a .debug_info or .debug_types section, and add summary
|
||||
// information to the .gdb_index section.
|
||||
|
197
gold/powerpc.cc
197
gold/powerpc.cc
@ -4542,7 +4542,7 @@ class Stub_table : public Output_relaxed_input_section
|
||||
plt_size_(0), last_plt_size_(0),
|
||||
branch_size_(0), last_branch_size_(0), min_size_threshold_(0),
|
||||
need_save_res_(false), need_resize_(false), resizing_(false),
|
||||
uniq_(id), tls_get_addr_opt_bctrl_(-1u), plt_fde_len_(0)
|
||||
uniq_(id)
|
||||
{
|
||||
this->set_output_section(output_section);
|
||||
|
||||
@ -4724,10 +4724,6 @@ class Stub_table : public Output_relaxed_input_section
|
||||
return false;
|
||||
}
|
||||
|
||||
// Generate a suitable FDE to describe code in this stub group.
|
||||
void
|
||||
init_plt_fde();
|
||||
|
||||
// Add .eh_frame info for this stub section.
|
||||
void
|
||||
add_eh_frame(Layout* layout);
|
||||
@ -4932,11 +4928,6 @@ class Stub_table : public Output_relaxed_input_section
|
||||
bool resizing_;
|
||||
// Per stub table unique identifier.
|
||||
uint32_t uniq_;
|
||||
// The bctrl in the __tls_get_addr_opt stub, if present.
|
||||
unsigned int tls_get_addr_opt_bctrl_;
|
||||
// FDE unwind info for this stub group.
|
||||
unsigned int plt_fde_len_;
|
||||
unsigned char plt_fde_[20];
|
||||
};
|
||||
|
||||
// Add a plt call stub, if we do not already have one for this
|
||||
@ -4986,10 +4977,7 @@ Stub_table<size, big_endian>::add_plt_call_entry(
|
||||
}
|
||||
this->plt_size_ += this->plt_call_size(p.first);
|
||||
if (this->targ_->is_tls_get_addr_opt(gsym))
|
||||
{
|
||||
this->targ_->set_has_tls_get_addr_opt();
|
||||
this->tls_get_addr_opt_bctrl_ = this->plt_size_ - 5 * 4;
|
||||
}
|
||||
this->targ_->set_has_tls_get_addr_opt();
|
||||
this->plt_size_ = this->plt_call_align(this->plt_size_);
|
||||
}
|
||||
return this->can_reach_stub(from, p.first->second.off_, r_type);
|
||||
@ -5159,48 +5147,39 @@ Stub_table<size, big_endian>::find_long_branch_entry(
|
||||
return &p->second;
|
||||
}
|
||||
|
||||
// Generate a suitable FDE to describe code in this stub group.
|
||||
// The __tls_get_addr_opt call stub needs to describe where it saves
|
||||
// LR, to support exceptions that might be thrown from __tls_get_addr.
|
||||
|
||||
template<int size, bool big_endian>
|
||||
void
|
||||
Stub_table<size, big_endian>::init_plt_fde()
|
||||
template<bool big_endian>
|
||||
static void
|
||||
eh_advance (std::vector<unsigned char>& fde, unsigned int delta)
|
||||
{
|
||||
unsigned char* p = this->plt_fde_;
|
||||
// offset pcrel sdata4, size udata4, and augmentation size byte.
|
||||
memset (p, 0, 9);
|
||||
p += 9;
|
||||
if (this->tls_get_addr_opt_bctrl_ != -1u)
|
||||
delta /= 4;
|
||||
if (delta < 64)
|
||||
fde.push_back(elfcpp::DW_CFA_advance_loc + delta);
|
||||
else if (delta < 256)
|
||||
{
|
||||
unsigned int to_bctrl = this->tls_get_addr_opt_bctrl_ / 4;
|
||||
if (to_bctrl < 64)
|
||||
*p++ = elfcpp::DW_CFA_advance_loc + to_bctrl;
|
||||
else if (to_bctrl < 256)
|
||||
{
|
||||
*p++ = elfcpp::DW_CFA_advance_loc1;
|
||||
*p++ = to_bctrl;
|
||||
}
|
||||
else if (to_bctrl < 65536)
|
||||
{
|
||||
*p++ = elfcpp::DW_CFA_advance_loc2;
|
||||
elfcpp::Swap<16, big_endian>::writeval(p, to_bctrl);
|
||||
p += 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
*p++ = elfcpp::DW_CFA_advance_loc4;
|
||||
elfcpp::Swap<32, big_endian>::writeval(p, to_bctrl);
|
||||
p += 4;
|
||||
}
|
||||
*p++ = elfcpp::DW_CFA_offset_extended_sf;
|
||||
*p++ = 65;
|
||||
*p++ = -(this->targ_->stk_linker() / 8) & 0x7f;
|
||||
*p++ = elfcpp::DW_CFA_advance_loc + 4;
|
||||
*p++ = elfcpp::DW_CFA_restore_extended;
|
||||
*p++ = 65;
|
||||
fde.push_back(elfcpp::DW_CFA_advance_loc1);
|
||||
fde.push_back(delta);
|
||||
}
|
||||
this->plt_fde_len_ = p - this->plt_fde_;
|
||||
else if (delta < 65536)
|
||||
{
|
||||
fde.resize(fde.size() + 3);
|
||||
unsigned char *p = &*fde.end() - 3;
|
||||
*p++ = elfcpp::DW_CFA_advance_loc2;
|
||||
elfcpp::Swap<16, big_endian>::writeval(p, delta);
|
||||
}
|
||||
else
|
||||
{
|
||||
fde.resize(fde.size() + 5);
|
||||
unsigned char *p = &*fde.end() - 5;
|
||||
*p++ = elfcpp::DW_CFA_advance_loc4;
|
||||
elfcpp::Swap<32, big_endian>::writeval(p, delta);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static bool
|
||||
stub_sort(T s1, T s2)
|
||||
{
|
||||
return s1->second.off_ < s2->second.off_;
|
||||
}
|
||||
|
||||
// Add .eh_frame info for this stub section. Unlike other linker
|
||||
@ -5212,7 +5191,8 @@ template<int size, bool big_endian>
|
||||
void
|
||||
Stub_table<size, big_endian>::add_eh_frame(Layout* layout)
|
||||
{
|
||||
if (!parameters->options().ld_generated_unwind_info())
|
||||
if (size != 64
|
||||
|| !parameters->options().ld_generated_unwind_info())
|
||||
return;
|
||||
|
||||
// Since we add stub .eh_frame info late, it must be placed
|
||||
@ -5223,28 +5203,115 @@ Stub_table<size, big_endian>::add_eh_frame(Layout* layout)
|
||||
if (!this->targ_->has_glink())
|
||||
return;
|
||||
|
||||
if (this->plt_size_ + this->branch_size_ + this->need_save_res_ == 0)
|
||||
typedef typename Plt_stub_entries::const_iterator plt_iter;
|
||||
std::vector<plt_iter> calls;
|
||||
if (!this->plt_call_stubs_.empty())
|
||||
for (plt_iter cs = this->plt_call_stubs_.begin();
|
||||
cs != this->plt_call_stubs_.end();
|
||||
++cs)
|
||||
if ((this->targ_->is_tls_get_addr_opt(cs->first.sym_)
|
||||
&& cs->second.r2save_
|
||||
&& !cs->second.localentry0_)
|
||||
|| cs->second.notoc_)
|
||||
calls.push_back(cs);
|
||||
if (calls.size() > 1)
|
||||
std::stable_sort(calls.begin(), calls.end(),
|
||||
stub_sort<plt_iter>);
|
||||
|
||||
typedef typename Branch_stub_entries::const_iterator branch_iter;
|
||||
std::vector<branch_iter> branches;
|
||||
if (!this->long_branch_stubs_.empty())
|
||||
for (branch_iter bs = this->long_branch_stubs_.begin();
|
||||
bs != this->long_branch_stubs_.end();
|
||||
++bs)
|
||||
if (bs->second.notoc_)
|
||||
branches.push_back(bs);
|
||||
if (branches.size() > 1)
|
||||
std::stable_sort(branches.begin(), branches.end(),
|
||||
stub_sort<branch_iter>);
|
||||
|
||||
if (calls.empty() && branches.empty())
|
||||
return;
|
||||
|
||||
this->init_plt_fde();
|
||||
unsigned int last_eh_loc = 0;
|
||||
// offset pcrel sdata4, size udata4, and augmentation size byte.
|
||||
std::vector<unsigned char> fde(9, 0);
|
||||
|
||||
for (unsigned int i = 0; i < calls.size(); i++)
|
||||
{
|
||||
plt_iter cs = calls[i];
|
||||
unsigned int off = cs->second.off_;
|
||||
// The __tls_get_addr_opt call stub needs to describe where
|
||||
// it saves LR, to support exceptions that might be thrown
|
||||
// from __tls_get_addr, and to support asynchronous exceptions.
|
||||
if (this->targ_->is_tls_get_addr_opt(cs->first.sym_))
|
||||
{
|
||||
off += 7 * 4;
|
||||
if (cs->second.r2save_
|
||||
&& !cs->second.localentry0_)
|
||||
{
|
||||
off += 2 * 4;
|
||||
eh_advance<big_endian>(fde, off - last_eh_loc);
|
||||
fde.resize(fde.size() + 6);
|
||||
unsigned char* p = &*fde.end() - 6;
|
||||
*p++ = elfcpp::DW_CFA_offset_extended_sf;
|
||||
*p++ = 65;
|
||||
*p++ = -(this->targ_->stk_linker() / 8) & 0x7f;
|
||||
unsigned int delta = this->plt_call_size(cs) - 4 - 9 * 4;
|
||||
*p++ = elfcpp::DW_CFA_advance_loc + delta / 4;
|
||||
*p++ = elfcpp::DW_CFA_restore_extended;
|
||||
*p++ = 65;
|
||||
last_eh_loc = off + delta;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
// notoc stubs also should describe LR changes, to support
|
||||
// asynchronous exceptions.
|
||||
off += (cs->second.r2save_ ? 4 : 0) + 8;
|
||||
eh_advance<big_endian>(fde, off - last_eh_loc);
|
||||
fde.resize(fde.size() + 6);
|
||||
unsigned char* p = &*fde.end() - 6;
|
||||
*p++ = elfcpp::DW_CFA_register;
|
||||
*p++ = 65;
|
||||
*p++ = 12;
|
||||
*p++ = elfcpp::DW_CFA_advance_loc + 8 / 4;
|
||||
*p++ = elfcpp::DW_CFA_restore_extended;
|
||||
*p++ = 65;
|
||||
last_eh_loc = off + 8;
|
||||
}
|
||||
|
||||
for (unsigned int i = 0; i < branches.size(); i++)
|
||||
{
|
||||
branch_iter bs = branches[i];
|
||||
unsigned int off = bs->second.off_ + 8;
|
||||
eh_advance<big_endian>(fde, off - last_eh_loc);
|
||||
fde.resize(fde.size() + 6);
|
||||
unsigned char* p = &*fde.end() - 6;
|
||||
*p++ = elfcpp::DW_CFA_register;
|
||||
*p++ = 65;
|
||||
*p++ = 12;
|
||||
*p++ = elfcpp::DW_CFA_advance_loc + 8 / 4;
|
||||
*p++ = elfcpp::DW_CFA_restore_extended;
|
||||
*p++ = 65;
|
||||
last_eh_loc = off + 8;
|
||||
}
|
||||
|
||||
layout->add_eh_frame_for_plt(this,
|
||||
Eh_cie<size>::eh_frame_cie,
|
||||
sizeof (Eh_cie<size>::eh_frame_cie),
|
||||
this->plt_fde_, this->plt_fde_len_);
|
||||
&*fde.begin(), fde.size());
|
||||
}
|
||||
|
||||
template<int size, bool big_endian>
|
||||
void
|
||||
Stub_table<size, big_endian>::remove_eh_frame(Layout* layout)
|
||||
{
|
||||
if (this->plt_fde_len_ != 0)
|
||||
{
|
||||
layout->remove_eh_frame_for_plt(this,
|
||||
Eh_cie<size>::eh_frame_cie,
|
||||
sizeof (Eh_cie<size>::eh_frame_cie),
|
||||
this->plt_fde_, this->plt_fde_len_);
|
||||
this->plt_fde_len_ = 0;
|
||||
}
|
||||
if (size == 64
|
||||
&& parameters->options().ld_generated_unwind_info()
|
||||
&& this->targ_->has_glink())
|
||||
layout->remove_eh_frame_for_plt(this,
|
||||
Eh_cie<size>::eh_frame_cie,
|
||||
sizeof (Eh_cie<size>::eh_frame_cie));
|
||||
}
|
||||
|
||||
// A class to handle .glink.
|
||||
|
Loading…
Reference in New Issue
Block a user