diff options
author | Alan Modra <amodra@gmail.com> | 2017-08-29 15:55:33 +0930 |
---|---|---|
committer | Alan Modra <amodra@gmail.com> | 2017-08-29 21:29:37 +0930 |
commit | 34e0882b83aedc6fb9c7532c89afaf8e0043b7ce (patch) | |
tree | 639ddded69114a9e5e971bdc0e983698035d7cf6 /gold/resolve.cc | |
parent | 34ca2bd7ace5e208d46fea6e7a56a5376de0abfe (diff) | |
download | gdb-34e0882b83aedc6fb9c7532c89afaf8e0043b7ce.zip gdb-34e0882b83aedc6fb9c7532c89afaf8e0043b7ce.tar.gz gdb-34e0882b83aedc6fb9c7532c89afaf8e0043b7ce.tar.bz2 |
[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.
Diffstat (limited to 'gold/resolve.cc')
-rw-r--r-- | gold/resolve.cc | 62 |
1 files changed, 62 insertions, 0 deletions
diff --git a/gold/resolve.cc b/gold/resolve.cc index 042d032..b85bbc8 100644 --- a/gold/resolve.cc +++ b/gold/resolve.cc @@ -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. |