[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:
Alan Modra
2017-08-29 15:55:33 +09:30
parent 34ca2bd7ac
commit 34e0882b83
8 changed files with 455 additions and 58 deletions

View File

@@ -917,6 +917,61 @@ Symbol_table::report_resolve_problem(bool is_error, const char* msg,
gold_info("%s: %s: previous definition here", program_name, objname);
}
// 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
Symbol::clone(const Symbol* from)
{
// Don't allow cloning after dynamic linking info is attached to symbols.
// We aren't prepared to merge such.
gold_assert(!this->has_symtab_index() && !from->has_symtab_index());
gold_assert(!this->has_dynsym_index() && !from->has_dynsym_index());
gold_assert(this->got_offset_list()->get_list() == NULL
&& from->got_offset_list()->get_list() == NULL);
gold_assert(!this->has_plt_offset() && !from->has_plt_offset());
if (!from->version_)
this->version_ = from->version_;
this->u1_ = from->u1_;
this->u2_ = from->u2_;
this->type_ = from->type_;
this->binding_ = from->binding_;
this->visibility_ = from->visibility_;
this->nonvis_ = from->nonvis_;
this->source_ = from->source_;
this->is_def_ = from->is_def_;
this->is_forwarder_ = from->is_forwarder_;
this->has_alias_ = from->has_alias_;
this->needs_dynsym_entry_ = from->needs_dynsym_entry_;
this->in_reg_ = from->in_reg_;
this->in_dyn_ = from->in_dyn_;
this->needs_dynsym_value_ = from->needs_dynsym_value_;
this->has_warning_ = from->has_warning_;
this->is_copied_from_dynobj_ = from->is_copied_from_dynobj_;
this->is_ordinary_shndx_ = from->is_ordinary_shndx_;
this->in_real_elf_ = from->in_real_elf_;
this->is_defined_in_discarded_section_
= from->is_defined_in_discarded_section_;
this->undef_binding_set_ = from->undef_binding_set_;
this->undef_binding_weak_ = from->undef_binding_weak_;
this->is_predefined_ = from->is_predefined_;
this->is_protected_ = from->is_protected_;
this->non_zero_localentry_ = from->non_zero_localentry_;
return !this->is_forced_local_ && from->is_forced_local_;
}
template <int size>
bool
Sized_symbol<size>::clone(const Sized_symbol<size>* from)
{
this->value_ = from->value_;
this->symsize_ = from->symsize_;
return Symbol::clone(from);
}
// A special case of should_override which is only called for a strong
// defined symbol from a regular object file. This is used when
// defining special symbols.
@@ -1116,4 +1171,11 @@ Symbol_table::override_with_special<64>(Sized_symbol<64>*,
const Sized_symbol<64>*);
#endif
template
bool
Sized_symbol<32>::clone(const Sized_symbol<32>*);
template
bool
Sized_symbol<64>::clone(const Sized_symbol<64>*);
} // End namespace gold.