diff options
author | Alan Modra <amodra@gmail.com> | 2019-06-26 22:08:54 +0930 |
---|---|---|
committer | Alan Modra <amodra@gmail.com> | 2019-07-13 09:57:50 +0930 |
commit | c9b8abb7af46c9da4b50ad8495ab2824c4125962 (patch) | |
tree | 94518846635db5adaf8ee371f2bc22e9f892e4fa | |
parent | e4dff7651becba48d805e39655138f7f6ca30485 (diff) | |
download | gdb-c9b8abb7af46c9da4b50ad8495ab2824c4125962.zip gdb-c9b8abb7af46c9da4b50ad8495ab2824c4125962.tar.gz gdb-c9b8abb7af46c9da4b50ad8495ab2824c4125962.tar.bz2 |
[GOLD] PowerPC got reloc optimisation
Note that gold won't remove unused GOT entries, in contrast to ld.bfd
which will.
* powerpc.cc (Powerpc_relobj::make_got_relative): New function.
(relative_value_is_known): New functions.
(Target_powerpc::Relocate::relocate): Edit code using
GOT16_HA, GOT16_LO_DS, and GOT_PCREL34 relocs.
-rw-r--r-- | gold/ChangeLog | 7 | ||||
-rw-r--r-- | gold/powerpc.cc | 108 |
2 files changed, 104 insertions, 11 deletions
diff --git a/gold/ChangeLog b/gold/ChangeLog index d6e2c0c..01fc7bb 100644 --- a/gold/ChangeLog +++ b/gold/ChangeLog @@ -1,5 +1,12 @@ 2019-07-13 Alan Modra <amodra@gmail.com> + * powerpc.cc (Powerpc_relobj::make_got_relative): New function. + (relative_value_is_known): New functions. + (Target_powerpc::Relocate::relocate): Edit code using + GOT16_HA, GOT16_LO_DS, and GOT_PCREL34 relocs. + +2019-07-13 Alan Modra <amodra@gmail.com> + * powerpc.cc (Target_powerpc): Add powerxx_stubs_ and accessor functions. (Target_powerpc::maybe_skip_tls_get_addr_call): Handle PLT_PCREL34 diff --git a/gold/powerpc.cc b/gold/powerpc.cc index c8d4414..3748f11 100644 --- a/gold/powerpc.cc +++ b/gold/powerpc.cc @@ -249,6 +249,12 @@ public: make_toc_relative(Target_powerpc<size, big_endian>* target, Address* value); + bool + make_got_relative(Target_powerpc<size, big_endian>* target, + const Symbol_value<size>* psymval, + Address addend, + Address* value); + // Perform the Sized_relobj_file method, then set up opd info from // .opd relocs. void @@ -2387,6 +2393,25 @@ Powerpc_relobj<size, big_endian>::make_toc_relative( return true; } +template<int size, bool big_endian> +bool +Powerpc_relobj<size, big_endian>::make_got_relative( + Target_powerpc<size, big_endian>* target, + const Symbol_value<size>* psymval, + Address addend, + Address* value) +{ + Address addr = psymval->value(this, addend); + Address got_base = (target->got_section()->output_section()->address() + + this->toc_base_offset()); + addr -= got_base; + if (addr + 0x80008000 > 0xffffffff) + return false; + + *value = addr; + return true; +} + // Perform the Sized_relobj_file method, then set up opd info from // .opd relocs. @@ -9660,6 +9685,37 @@ Target_powerpc<size, big_endian>::symval_for_branch( return true; } +template<int size> +static bool +relative_value_is_known(const Sized_symbol<size>* gsym) +{ + if (gsym->type() == elfcpp::STT_GNU_IFUNC) + return false; + + if (gsym->is_from_dynobj() + || gsym->is_undefined() + || gsym->is_preemptible()) + return false; + + if (gsym->is_absolute()) + return !parameters->options().output_is_position_independent(); + + return true; +} + +template<int size> +static bool +relative_value_is_known(const Symbol_value<size>* psymval) +{ + if (psymval->is_ifunc_symbol()) + return false; + + bool is_ordinary; + unsigned int shndx = psymval->input_shndx(&is_ordinary); + + return is_ordinary && shndx != elfcpp::SHN_UNDEF; +} + // Perform a relocation. template<int size, bool big_endian> @@ -10446,7 +10502,10 @@ Target_powerpc<size, big_endian>::Relocate::relocate( break; } - if (size == 64) + if (size == 64 + && (gsym + ? relative_value_is_known(gsym) + : relative_value_is_known(psymval))) { switch (r_type) { @@ -10460,12 +10519,6 @@ Target_powerpc<size, big_endian>::Relocate::relocate( // and // addis ra,r2,0; addi rb,ra,x@toc@l; // to nop; addi rb,r2,x@toc; - // FIXME: the @got sequence shown above is not yet - // optimized. Note that gcc as of 2017-01-07 doesn't use - // the ELF @got relocs except for TLS, instead using the - // PowerOpen variant of a compiler managed GOT (called TOC). - // The PowerOpen TOC sequence equivalent to the first - // example is optimized. case elfcpp::R_POWERPC_GOT_TLSLD16_HA: case elfcpp::R_POWERPC_GOT_TLSGD16_HA: case elfcpp::R_POWERPC_GOT_TPREL16_HA: @@ -10476,8 +10529,12 @@ Target_powerpc<size, big_endian>::Relocate::relocate( { Insn* iview = reinterpret_cast<Insn*>(view - d_offset); Insn insn = elfcpp::Swap<32, big_endian>::readval(iview); - if (r_type == elfcpp::R_PPC64_TOC16_HA - && object->make_toc_relative(target, &value)) + if ((r_type == elfcpp::R_PPC64_TOC16_HA + && object->make_toc_relative(target, &value)) + || (r_type == elfcpp::R_POWERPC_GOT16_HA + && object->make_got_relative(target, psymval, + rela.get_r_addend(), + &value))) { gold_assert((insn & ((0x3f << 26) | 0x1f << 16)) == ((15u << 26) | (2 << 16))); @@ -10505,8 +10562,12 @@ Target_powerpc<size, big_endian>::Relocate::relocate( Insn* iview = reinterpret_cast<Insn*>(view - d_offset); Insn insn = elfcpp::Swap<32, big_endian>::readval(iview); bool changed = false; - if (r_type == elfcpp::R_PPC64_TOC16_LO_DS - && object->make_toc_relative(target, &value)) + if ((r_type == elfcpp::R_PPC64_TOC16_LO_DS + && object->make_toc_relative(target, &value)) + || (r_type == elfcpp::R_PPC64_GOT16_LO_DS + && object->make_got_relative(target, psymval, + rela.get_r_addend(), + &value))) { gold_assert ((insn & (0x3f << 26)) == 58u << 26 /* ld */); insn ^= (14u << 26) ^ (58u << 26); @@ -10534,6 +10595,31 @@ Target_powerpc<size, big_endian>::Relocate::relocate( } break; + case elfcpp::R_PPC64_GOT_PCREL34: + if (parameters->options().toc_optimize()) + { + Insn* iview = reinterpret_cast<Insn*>(view); + uint64_t insn = elfcpp::Swap<32, big_endian>::readval(iview); + insn <<= 32; + insn |= elfcpp::Swap<32, big_endian>::readval(iview + 1); + if ((insn & ((-1ULL << 50) | (63ULL << 26))) + != ((1ULL << 58) | (1ULL << 52) | (57ULL << 26) /* pld */)) + break; + + Address relval = psymval->value(object, rela.get_r_addend()); + relval -= address; + if (relval + (1ULL << 33) < 1ULL << 34) + { + value = relval; + // Replace with paddi + insn += (2ULL << 56) + (14ULL << 26) - (57ULL << 26); + elfcpp::Swap<32, big_endian>::writeval(iview, insn >> 32); + elfcpp::Swap<32, big_endian>::writeval(iview + 1, + insn & 0xffffffff); + } + } + break; + case elfcpp::R_POWERPC_TPREL16_HA: if (parameters->options().tls_optimize() && value + 0x8000 < 0x10000) { |