diff options
author | Ilya Tocar <ilya.tocar@intel.com> | 2015-04-01 16:48:38 +0300 |
---|---|---|
committer | Ilya Tocar <ilya.tocar@intel.com> | 2015-04-01 16:52:09 +0300 |
commit | c4fc4724a6afd605692b24c0af24c7e234dc5ace (patch) | |
tree | ef7b18e27f5dcaffe75a1d7bf68dc0ec0349d88a /gold/i386.cc | |
parent | 918357b9556c9eaf81129ea6691bb6e461e80f86 (diff) | |
download | gdb-c4fc4724a6afd605692b24c0af24c7e234dc5ace.zip gdb-c4fc4724a6afd605692b24c0af24c7e234dc5ace.tar.gz gdb-c4fc4724a6afd605692b24c0af24c7e234dc5ace.tar.bz2 |
Convert mov foo@GOT(%reg), %reg to lea foo@GOTOFF(%reg), %reg
2015-04-01 Ilya Tocar <ilya.tocar@intel.com>
PR gold/17640
* i386.cc (Target_i386::can_convert_mov_to_lea): New.
(Target_i386::Scan::local): Don't create GOT entry, when we
can convert GOT to GOTOFF.
(Target_i386::Scan::global): Ditto.
(Target_i386::Relocate::relocate): Convert mov foo@GOT(%reg), %reg to
lea foo@GOTOFF(%reg), %reg if possible.
* testsuite/Makefile.am (i386_mov_to_lea): New test.
* testsuite/i386_mov_to_lea1.s: New.
* testsuite/i386_mov_to_lea2.s: Ditto.
* testsuite/i386_mov_to_lea3.s: Ditto.
* testsuite/i386_mov_to_lea4.s: Ditto.
* testsuite/i386_mov_to_lea5.s: Ditto.
* testsuite/i386_mov_to_lea.sh: Ditto.
Diffstat (limited to 'gold/i386.cc')
-rw-r--r-- | gold/i386.cc | 127 |
1 files changed, 94 insertions, 33 deletions
diff --git a/gold/i386.cc b/gold/i386.cc index 3bc3d94..086314e 100644 --- a/gold/i386.cc +++ b/gold/i386.cc @@ -738,6 +738,26 @@ class Target_i386 : public Sized_target<32, false> static tls::Tls_optimization optimize_tls_reloc(bool is_final, int r_type); + // Check if relocation against this symbol is a candidate for + // conversion from + // mov foo@GOT(%reg), %reg + // to + // lea foo@GOTOFF(%reg), %reg. + static bool + can_convert_mov_to_lea(const Symbol* gsym) + { + gold_assert(gsym != NULL); + return (gsym->type() != elfcpp::STT_GNU_IFUNC + && !gsym->is_undefined () + && !gsym->is_from_dynobj() + && !gsym->is_preemptible() + && (!parameters->options().shared() + || (gsym->visibility() != elfcpp::STV_DEFAULT + && gsym->visibility() != elfcpp::STV_PROTECTED) + || parameters->options().Bsymbolic()) + && strcmp(gsym->name(), "_DYNAMIC") != 0); + } + // Get the GOT section, creating it if necessary. Output_data_got<32, false>* got_section(Symbol_table*, Layout*); @@ -1835,8 +1855,26 @@ Target_i386::Scan::local(Symbol_table* symtab, case elfcpp::R_386_GOT32: { - // The symbol requires a GOT entry. + // We need GOT section. Output_data_got<32, false>* got = target->got_section(symtab, layout); + + // If the relocation symbol isn't IFUNC, + // and is local, then we will convert + // mov foo@GOT(%reg), %reg + // to + // lea foo@GOTOFF(%reg), %reg + // in Relocate::relocate. + if (reloc.get_r_offset() >= 2 + && lsym.get_st_type() != elfcpp::STT_GNU_IFUNC) + { + section_size_type stype; + const unsigned char* view = object->section_contents(data_shndx, + &stype, true); + if (view[reloc.get_r_offset() - 2] == 0x8b) + break; + } + + // Otherwise, the symbol requires a GOT entry. unsigned int r_sym = elfcpp::elf_r_sym<32>(reloc.get_r_info()); // For a STT_GNU_IFUNC symbol we want the PLT offset. That @@ -2229,8 +2267,24 @@ Target_i386::Scan::global(Symbol_table* symtab, case elfcpp::R_386_GOT32: { - // The symbol requires a GOT entry. + // The symbol requires a GOT section. Output_data_got<32, false>* got = target->got_section(symtab, layout); + + // If we convert this from + // mov foo@GOT(%reg), %reg + // to + // lea foo@GOTOFF(%reg), %reg + // in Relocate::relocate, then there is nothing to do here. + if (reloc.get_r_offset() >= 2 + && Target_i386::can_convert_mov_to_lea(gsym)) + { + section_size_type stype; + const unsigned char* view = object->section_contents(data_shndx, + &stype, true); + if (view[reloc.get_r_offset() - 2] == 0x8b) + break; + } + if (gsym->final_value_is_known()) { // For a STT_GNU_IFUNC symbol we want the PLT address. @@ -2732,35 +2786,6 @@ Target_i386::Relocate::relocate(const Relocate_info<32, false>* relinfo, } } - // Get the GOT offset if needed. - // The GOT pointer points to the end of the GOT section. - // We need to subtract the size of the GOT section to get - // the actual offset to use in the relocation. - bool have_got_offset = false; - unsigned int got_offset = 0; - switch (r_type) - { - case elfcpp::R_386_GOT32: - if (gsym != NULL) - { - gold_assert(gsym->has_got_offset(GOT_TYPE_STANDARD)); - got_offset = (gsym->got_offset(GOT_TYPE_STANDARD) - - target->got_size()); - } - else - { - unsigned int r_sym = elfcpp::elf_r_sym<32>(rel.get_r_info()); - gold_assert(object->local_has_got_offset(r_sym, GOT_TYPE_STANDARD)); - got_offset = (object->local_got_offset(r_sym, GOT_TYPE_STANDARD) - - target->got_size()); - } - have_got_offset = true; - break; - - default: - break; - } - switch (r_type) { case elfcpp::R_386_NONE: @@ -2809,8 +2834,44 @@ Target_i386::Relocate::relocate(const Relocate_info<32, false>* relinfo, break; case elfcpp::R_386_GOT32: - gold_assert(have_got_offset); - Relocate_functions<32, false>::rel32(view, got_offset); + // Convert + // mov foo@GOT(%reg), %reg + // to + // lea foo@GOTOFF(%reg), %reg + // if possible. + if (rel.get_r_offset() >= 2 + && view[-2] == 0x8b + && ((gsym == NULL && !psymval->is_ifunc_symbol()) + || (gsym != NULL + && Target_i386::can_convert_mov_to_lea(gsym)))) + { + view[-2] = 0x8d; + elfcpp::Elf_types<32>::Elf_Addr value; + value = (psymval->value(object, 0) + - target->got_plt_section()->address()); + Relocate_functions<32, false>::rel32(view, value); + } + else + { + // The GOT pointer points to the end of the GOT section. + // We need to subtract the size of the GOT section to get + // the actual offset to use in the relocation. + unsigned int got_offset = 0; + if (gsym != NULL) + { + gold_assert(gsym->has_got_offset(GOT_TYPE_STANDARD)); + got_offset = (gsym->got_offset(GOT_TYPE_STANDARD) + - target->got_size()); + } + else + { + unsigned int r_sym = elfcpp::elf_r_sym<32>(rel.get_r_info()); + gold_assert(object->local_has_got_offset(r_sym, GOT_TYPE_STANDARD)); + got_offset = (object->local_got_offset(r_sym, GOT_TYPE_STANDARD) + - target->got_size()); + } + Relocate_functions<32, false>::rel32(view, got_offset); + } break; case elfcpp::R_386_GOTOFF: |