From c9b8abb7af46c9da4b50ad8495ab2824c4125962 Mon Sep 17 00:00:00 2001 From: Alan Modra Date: Wed, 26 Jun 2019 22:08:54 +0930 Subject: [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. --- gold/ChangeLog | 7 ++++ gold/powerpc.cc | 108 ++++++++++++++++++++++++++++++++++++++++++++++++++------ 2 files changed, 104 insertions(+), 11 deletions(-) (limited to 'gold') 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 + * 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 + * 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* target, Address* value); + bool + make_got_relative(Target_powerpc* target, + const Symbol_value* 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::make_toc_relative( return true; } +template +bool +Powerpc_relobj::make_got_relative( + Target_powerpc* target, + const Symbol_value* 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::symval_for_branch( return true; } +template +static bool +relative_value_is_known(const Sized_symbol* 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 +static bool +relative_value_is_known(const Symbol_value* 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 @@ -10446,7 +10502,10 @@ Target_powerpc::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::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::Relocate::relocate( { Insn* iview = reinterpret_cast(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::Relocate::relocate( Insn* iview = reinterpret_cast(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::Relocate::relocate( } break; + case elfcpp::R_PPC64_GOT_PCREL34: + if (parameters->options().toc_optimize()) + { + Insn* iview = reinterpret_cast(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) { -- cgit v1.1