[GOLD] PowerPC tls_get_addr_optimize
This implements the special __tls_get_addr_opt call stub for powerpc gold that returns __thread variable addresses without actually making a call to __tls_get_addr in most cases. Shared libraries that are loaded at program load time (ie. dlopen is not used) have a known layout for their __thread variables, and thus DTPMOD64/DPTREL64 pairs describing those variables can be set up by ld.so for the __tls_get_addr_opt call stub fast exit. Ref https://sourceware.org/ml/libc-alpha/2015-03/msg00626.html I really, really wish I'd used a differently versioned __tls_get_addr symbol than the base symbol to indicate glibc support for the optimized call, rather than having glibc export __tls_get_addr_opt. A lot of the messing around here, flipping symbols from __tls_get_addr to __tls_get_addr_opt, is caused by that decision. About the only benefit is that a user can see at a glance that their disassembled code is calling __tls_get_addr via the fancy call stub.. Anyway, we need references to __tls_get_addr to seem like they were to __tls_get_addr_opt, and in cases like the tsan interceptor, a definition of __tls_get_addr to seem like one of __tls_get_addr_opt as well. That's the reason for Symbol::clear_in_reg and Symbol_table::clone, and why symbols are substituted in Scan::global and other places dealing with dynamic linking. elfcpp/ * elfcpp.h (DT_PPC_OPT): Define. * powerpc.h (PPC_OPT_TLS): Define. gold/ * options.h (tls_get_addr_optimize): New option. * symtab.h (Symbol::clear_in_reg, clone): New functions. (Sized_symbol::clone): New function. (Symbol_table::clone): New function. * resolve.cc (Symbol::clone, Sized_symbol::clone): New functions. * powerpc.cc (Target_powerpc::has_tls_get_addr_opt_, tls_get_addr_, tls_get_addr_opt_): New vars. (Target_powerpc::tls_get_addr_opt, tls_get_addr, is_tls_get_addr_opt, replace_tls_get_addr, set_has_tls_get_addr_opt, stk_linker): New functions. (Target_powerpc::Track_tls::maybe_skip_tls_get_addr_call): Add target param. Update callers. Compare symbols rather than names. (Target_powerpc::do_define_standard_symbols): Init tls_get_addr_ and tls_get_addr_opt_. (Target_powerpc::Branch_info::mark_pltcall): Translate tls_get_addr sym to tls_get_addr_opt. (Target_powerpc::Branch_info::make_stub): Likewise. (Stub_table::define_stub_syms): Likewise. (Target_powerpc::Scan::global): Likewise. (Target_powerpc::Relocate::relocate): Likewise. (add_3_12_2, add_3_12_13, bctrl, beqlr, cmpdi_11_0, cmpwi_11_0, ld_11_1, ld_11_3, ld_12_3, lwz_11_3, lwz_12_3, mr_0_3, mr_3_0, mtlr_11, std_11_1): New constants. (Stub_table::eh_frame_added_): Delete. (Stub_table::tls_get_addr_opt_bctrl_, plt_fde_len_, plt_fde_): New vars. (Stub_table::init_plt_fde): New functions. (Stub_table::add_eh_frame, replace_eh_frame): Move definition out of line. Init and use plt_fde_. (Stub_table::plt_call_size): Return size for tls_get_addr stub. Extract alignment code to.. (Stub_table::plt_call_align): ..this new function. Adjust all callers. (Stub_table::add_plt_call_entry): Set has_tls_get_addr_opt and tls_get_addr_opt_bctrl, and align after that. (Stub_table::do_write): Write out tls_get_addr stub. (Target_powerpc::do_finalize_sections): Emit DT_PPC_OPT PPC_OPT_TLS/PPC64_OPT_TLS bit. (Target_powerpc::Relocate::relocate): Don't check for or modify nop following bl for tls_get_addr stub.
This commit is contained in:
parent
34ca2bd7ac
commit
34e0882b83
8 changed files with 455 additions and 58 deletions
|
@ -329,6 +329,11 @@ class Symbol
|
|||
set_in_reg()
|
||||
{ this->in_reg_ = true; }
|
||||
|
||||
// Forget this symbol was seen in a regular object.
|
||||
void
|
||||
clear_in_reg()
|
||||
{ this->in_reg_ = false; }
|
||||
|
||||
// Return whether this symbol has been seen in a dynamic object.
|
||||
bool
|
||||
in_dyn() const
|
||||
|
@ -893,6 +898,13 @@ class Symbol
|
|||
set_non_zero_localentry()
|
||||
{ this->non_zero_localentry_ = true; }
|
||||
|
||||
// Completely override existing symbol. Everything bar name_,
|
||||
// version_, and is_forced_local_ flag are copied. version_ is
|
||||
// cleared if from->version_ is clear. Returns true if this symbol
|
||||
// should be forced local.
|
||||
bool
|
||||
clone(const Symbol* from);
|
||||
|
||||
protected:
|
||||
// Instances of this class should always be created at a specific
|
||||
// size.
|
||||
|
@ -1182,6 +1194,13 @@ class Sized_symbol : public Symbol
|
|||
void
|
||||
allocate_common(Output_data*, Value_type value);
|
||||
|
||||
// Completely override existing symbol. Everything bar name_,
|
||||
// version_, and is_forced_local_ flag are copied. version_ is
|
||||
// cleared if from->version_ is clear. Returns true if this symbol
|
||||
// should be forced local.
|
||||
bool
|
||||
clone(const Sized_symbol<size>* from);
|
||||
|
||||
private:
|
||||
Sized_symbol(const Sized_symbol&);
|
||||
Sized_symbol& operator=(const Sized_symbol&);
|
||||
|
@ -1687,6 +1706,15 @@ class Symbol_table
|
|||
version_script() const
|
||||
{ return version_script_; }
|
||||
|
||||
// Completely override existing symbol.
|
||||
template<int size>
|
||||
void
|
||||
clone(Sized_symbol<size>* to, const Sized_symbol<size>* from)
|
||||
{
|
||||
if (to->clone(from))
|
||||
this->force_local(to);
|
||||
}
|
||||
|
||||
private:
|
||||
Symbol_table(const Symbol_table&);
|
||||
Symbol_table& operator=(const Symbol_table&);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue