diff options
-rw-r--r-- | gold/ChangeLog | 16 | ||||
-rw-r--r-- | gold/testsuite/Makefile.am | 91 | ||||
-rwxr-xr-x | gold/testsuite/x86_64_mov_to_lea.sh | 42 | ||||
-rw-r--r-- | gold/testsuite/x86_64_mov_to_lea1.s | 11 | ||||
-rw-r--r-- | gold/testsuite/x86_64_mov_to_lea2.s | 6 | ||||
-rw-r--r-- | gold/testsuite/x86_64_mov_to_lea3.s | 10 | ||||
-rw-r--r-- | gold/testsuite/x86_64_mov_to_lea4.s | 12 | ||||
-rw-r--r-- | gold/x86_64.cc | 93 |
8 files changed, 275 insertions, 6 deletions
diff --git a/gold/ChangeLog b/gold/ChangeLog index ea4390e..a838b05 100644 --- a/gold/ChangeLog +++ b/gold/ChangeLog @@ -1,3 +1,19 @@ +2015-04-06 Ilya Tocar <ilya.tocar@intel.com> + + PR gold/17641 + * x86_64.cc (Target_x86_64::can_convert_mov_to_lea): New. + (Target_x86_64::Scan::local): Don't create GOT entry, when we + can convert mov to lea. + (Target_x86_64::Scan::global): Ditto. + (Target_x86_64::Relocate::relocate): Convert mov foo@GOTPCREL(%rip), + %reg to lea foo(%rip), %reg if possible. + * testsuite/Makefile.am (x86_64_mov_to_lea): New test. + * testsuite/x86_64_mov_to_lea1.s: New. + * testsuite/x86_64_mov_to_lea2.s: Ditto. + * testsuite/x86_64_mov_to_lea3.s: Ditto. + * testsuite/x86_64_mov_to_lea4.s: Ditto. + * testsuite/x86_64_mov_to_lea.sh: Ditto. + 2015-04-02 H.J. Lu <hongjiu.lu@intel.com> * configure: Regenerated. diff --git a/gold/testsuite/Makefile.am b/gold/testsuite/Makefile.am index d64547e..1ffeb50 100644 --- a/gold/testsuite/Makefile.am +++ b/gold/testsuite/Makefile.am @@ -962,6 +962,97 @@ endif FN_PTRS_IN_SO_WITHOUT_PIC endif TLS +if DEFAULT_TARGET_X86_64 + +check_SCRIPTS += x86_64_mov_to_lea.sh +check_DATA += x86_64_mov_to_lea1.stdout x86_64_mov_to_lea2.stdout \ + x86_64_mov_to_lea3.stdout x86_64_mov_to_lea4.stdout \ + x86_64_mov_to_lea5.stdout x86_64_mov_to_lea6.stdout \ + x86_64_mov_to_lea7.stdout x86_64_mov_to_lea8.stdout \ + x86_64_mov_to_lea9.stdout x86_64_mov_to_lea10.stdout \ + x86_64_mov_to_lea11.stdout x86_64_mov_to_lea12.stdout \ + x86_64_mov_to_lea13.stdout x86_64_mov_to_lea14.stdout +MOSTLYCLEANFILES += x86_64_mov_to_lea1 x86_64_mov_to_lea2 \ + x86_64_mov_to_lea3 x86_64_mov_to_lea4 x86_64_mov_to_lea5 \ + x86_64_mov_to_lea6 x86_64_mov_to_lea7 x86_64_mov_to_lea8 \ + x86_64_mov_to_lea9 x86_64_mov_to_lea10 x86_64_mov_to_lea11 \ + x86_64_mov_to_lea12 x86_64_mov_to_lea13 x86_64_mov_to_lea14 + +x86_64_mov_to_lea1.o: x86_64_mov_to_lea1.s + $(TEST_AS) --64 -o $@ $< +x86_64_mov_to_lea2.o: x86_64_mov_to_lea1.s + $(TEST_AS) --x32 -o $@ $< +x86_64_mov_to_lea3.o: x86_64_mov_to_lea2.s + $(TEST_AS) --x32 -o $@ $< +x86_64_mov_to_lea4.o: x86_64_mov_to_lea2.s + $(TEST_AS) --64 -o $@ $< +x86_64_mov_to_lea5.o: x86_64_mov_to_lea3.s + $(TEST_AS) --x32 -o $@ $< +x86_64_mov_to_lea6.o: x86_64_mov_to_lea3.s + $(TEST_AS) --64 -o $@ $< +x86_64_mov_to_lea7.o: x86_64_mov_to_lea4.s + $(TEST_AS) --x32 -o $@ $< +x86_64_mov_to_lea8.o: x86_64_mov_to_lea4.s + $(TEST_AS) --64 -o $@ $< +x86_64_mov_to_lea1: x86_64_mov_to_lea1.o + ../ld-new -Bsymbolic -shared -melf_x86_64 -o $@ $< +x86_64_mov_to_lea2: x86_64_mov_to_lea1.o + ../ld-new -pie -melf_x86_64 -o $@ $< +x86_64_mov_to_lea3: x86_64_mov_to_lea1.o + ../ld-new -melf_x86_64 -o $@ $< +x86_64_mov_to_lea4: x86_64_mov_to_lea2.o + ../ld-new -Bsymbolic -shared -melf32_x86_64 -o $@ $< +x86_64_mov_to_lea5: x86_64_mov_to_lea2.o + ../ld-new -pie -melf32_x86_64 -o $@ $< +x86_64_mov_to_lea6: x86_64_mov_to_lea2.o + ../ld-new -melf32_x86_64 -o $@ $< +x86_64_mov_to_lea7: x86_64_mov_to_lea3.o + ../ld-new -melf32_x86_64 -pie -o $@ $< +x86_64_mov_to_lea8: x86_64_mov_to_lea4.o + ../ld-new -melf_x86_64 -pie -o $@ $< +x86_64_mov_to_lea9: x86_64_mov_to_lea5.o + ../ld-new -melf32_x86_64 -o $@ $< +x86_64_mov_to_lea10: x86_64_mov_to_lea6.o + ../ld-new -melf_x86_64 -o $@ $< +x86_64_mov_to_lea11: x86_64_mov_to_lea1.o + ../ld-new -melf32_x86_64 -shared -o $@ $< +x86_64_mov_to_lea12: x86_64_mov_to_lea2.o + ../ld-new -melf_x86_64 -shared -o $@ $< +x86_64_mov_to_lea13: x86_64_mov_to_lea7.o + ../ld-new -melf32_x86_64 -shared -o $@ $< +x86_64_mov_to_lea14: x86_64_mov_to_lea8.o + ../ld-new -melf_x86_64 -shared -o $@ $< +x86_64_mov_to_lea1.stdout: x86_64_mov_to_lea1 + $(TEST_OBJDUMP) -dw $< > $@ +x86_64_mov_to_lea2.stdout: x86_64_mov_to_lea2 + $(TEST_OBJDUMP) -dw $< > $@ +x86_64_mov_to_lea3.stdout: x86_64_mov_to_lea3 + $(TEST_OBJDUMP) -dw $< > $@ +x86_64_mov_to_lea4.stdout: x86_64_mov_to_lea4 + $(TEST_OBJDUMP) -dw $< > $@ +x86_64_mov_to_lea5.stdout: x86_64_mov_to_lea5 + $(TEST_OBJDUMP) -dw $< > $@ +x86_64_mov_to_lea6.stdout: x86_64_mov_to_lea6 + $(TEST_OBJDUMP) -dw $< > $@ +x86_64_mov_to_lea7.stdout: x86_64_mov_to_lea7 + $(TEST_OBJDUMP) -dw $< > $@ +x86_64_mov_to_lea8.stdout: x86_64_mov_to_lea8 + $(TEST_OBJDUMP) -dw $< > $@ +x86_64_mov_to_lea9.stdout: x86_64_mov_to_lea9 + $(TEST_OBJDUMP) -dw $< > $@ +x86_64_mov_to_lea10.stdout: x86_64_mov_to_lea10 + $(TEST_OBJDUMP) -dw $< > $@ +x86_64_mov_to_lea11.stdout: x86_64_mov_to_lea11 + $(TEST_OBJDUMP) -dw $< > $@ +x86_64_mov_to_lea12.stdout: x86_64_mov_to_lea12 + $(TEST_OBJDUMP) -dw $< > $@ +x86_64_mov_to_lea13.stdout: x86_64_mov_to_lea13 + $(TEST_OBJDUMP) -dw $< > $@ +x86_64_mov_to_lea14.stdout: x86_64_mov_to_lea14 + $(TEST_OBJDUMP) -dw $< > $@ + +endif DEFAULT_TARGET_X86_64 + if DEFAULT_TARGET_I386 check_SCRIPTS += i386_mov_to_lea.sh diff --git a/gold/testsuite/x86_64_mov_to_lea.sh b/gold/testsuite/x86_64_mov_to_lea.sh new file mode 100755 index 0000000..ee24a41 --- /dev/null +++ b/gold/testsuite/x86_64_mov_to_lea.sh @@ -0,0 +1,42 @@ +#!/bin/sh + +# x86_64_mov_to_lea.sh -- a test for mov2lea conversion. + +# Copyright (C) 2010-2015 Free Software Foundation, Inc. +# Written by Tocar Ilya <ilya.tocar@intel.com> + +# This file is part of gold. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, +# MA 02110-1301, USA. + +set -e + +grep -q "lea -0x[a-f0-9]\+(%rip),%rax" x86_64_mov_to_lea1.stdout +grep -q "lea -0x[a-f0-9]\+(%rip),%rax" x86_64_mov_to_lea2.stdout +grep -q "lea -0x[a-f0-9]\+(%rip),%rax" x86_64_mov_to_lea3.stdout +grep -q "lea -0x[a-f0-9]\+(%rip),%rax" x86_64_mov_to_lea4.stdout +grep -q "lea -0x[a-f0-9]\+(%rip),%rax" x86_64_mov_to_lea5.stdout +grep -q "lea -0x[a-f0-9]\+(%rip),%rax" x86_64_mov_to_lea6.stdout +grep -q "mov 0x[a-f0-9]\+(%rip),%rax" x86_64_mov_to_lea7.stdout +grep -q "mov 0x[a-f0-9]\+(%rip),%rax" x86_64_mov_to_lea8.stdout +grep -q "lea -0x[a-f0-9]\+(%rip),%rax" x86_64_mov_to_lea9.stdout +grep -q "lea -0x[a-f0-9]\+(%rip),%rax" x86_64_mov_to_lea10.stdout +grep -q "mov 0x[a-f0-9]\+(%rip),%rax" x86_64_mov_to_lea11.stdout +grep -q "mov 0x[a-f0-9]\+(%rip),%rax" x86_64_mov_to_lea12.stdout +grep -q "lea -0x[a-f0-9]\+(%rip),%rax" x86_64_mov_to_lea13.stdout +grep -q "lea -0x[a-f0-9]\+(%rip),%rax" x86_64_mov_to_lea14.stdout + +exit 0 diff --git a/gold/testsuite/x86_64_mov_to_lea1.s b/gold/testsuite/x86_64_mov_to_lea1.s new file mode 100644 index 0000000..4dce487 --- /dev/null +++ b/gold/testsuite/x86_64_mov_to_lea1.s @@ -0,0 +1,11 @@ + .text + .globl foo + .type foo, @function +foo: + ret + .size foo, .-foo + .globl _start + .type _start, @function +_start: + movq foo@GOTPCREL(%rip), %rax + .size _start, .-_start diff --git a/gold/testsuite/x86_64_mov_to_lea2.s b/gold/testsuite/x86_64_mov_to_lea2.s new file mode 100644 index 0000000..2a11b7a --- /dev/null +++ b/gold/testsuite/x86_64_mov_to_lea2.s @@ -0,0 +1,6 @@ + .text + .globl _start + .type _start, @function +_start: + movq _DYNAMIC@GOTPCREL(%rip), %rax + .size _start, .-_start diff --git a/gold/testsuite/x86_64_mov_to_lea3.s b/gold/testsuite/x86_64_mov_to_lea3.s new file mode 100644 index 0000000..ac43b78 --- /dev/null +++ b/gold/testsuite/x86_64_mov_to_lea3.s @@ -0,0 +1,10 @@ + .text + .type foo, @function +foo: + ret + .size foo, .-foo + .globl _start + .type _start, @function +_start: + movq foo@GOTPCREL(%rip), %rax + .size _start, .-_start diff --git a/gold/testsuite/x86_64_mov_to_lea4.s b/gold/testsuite/x86_64_mov_to_lea4.s new file mode 100644 index 0000000..37bee32 --- /dev/null +++ b/gold/testsuite/x86_64_mov_to_lea4.s @@ -0,0 +1,12 @@ + .text + .globl foo + .hidden foo + .type foo, @function +foo: + ret + .size foo, .-foo + .globl _start + .type _start, @function +_start: + movq foo@GOTPCREL(%rip), %rax + .size _start, .-_start diff --git a/gold/x86_64.cc b/gold/x86_64.cc index 4543c8a..007af1d 100644 --- a/gold/x86_64.cc +++ b/gold/x86_64.cc @@ -865,6 +865,25 @@ class Target_x86_64 : public Sized_target<size, false> get_size_for_reloc(unsigned int, Relobj*); }; + // Check if relocation against this symbol is a candidate for + // conversion from + // mov foo@GOTPCREL(%rip), %reg + // to lea foo(%rip), %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); + } + // Adjust TLS relocation type based on the options and whether this // is a local symbol. static tls::Tls_optimization @@ -2458,8 +2477,27 @@ Target_x86_64<size>::Scan::local(Symbol_table* symtab, case elfcpp::R_X86_64_GOTPCREL: case elfcpp::R_X86_64_GOTPLT64: { - // The symbol requires a GOT entry. + // The symbol requires a GOT section. Output_data_got<64, false>* got = target->got_section(symtab, layout); + + // If the relocation symbol isn't IFUNC, + // and is local, then we will convert + // mov foo@GOTPCREL(%rip), %reg + // to lea foo(%rip), %reg. + // in Relocate::relocate. + if (r_type == elfcpp::R_X86_64_GOTPCREL + && reloc.get_r_offset() >= 2 + && !is_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; + } + + + // The symbol requires a GOT entry. unsigned int r_sym = elfcpp::elf_r_sym<size>(reloc.get_r_info()); // For a STT_GNU_IFUNC symbol we want the PLT offset. That @@ -2867,6 +2905,22 @@ Target_x86_64<size>::Scan::global(Symbol_table* symtab, { // The symbol requires a GOT entry. Output_data_got<64, false>* got = target->got_section(symtab, layout); + + // If we convert this from + // mov foo@GOTPCREL(%rip), %reg + // to lea foo(%rip), %reg. + // in Relocate::relocate, then there is nothing to do here. + if (r_type == elfcpp::R_X86_64_GOTPCREL + && reloc.get_r_offset() >= 2 + && Target_x86_64<size>::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. @@ -3340,7 +3394,6 @@ Target_x86_64<size>::Relocate::relocate( case elfcpp::R_X86_64_GOT32: case elfcpp::R_X86_64_GOT64: case elfcpp::R_X86_64_GOTPLT64: - case elfcpp::R_X86_64_GOTPCREL: case elfcpp::R_X86_64_GOTPCREL64: if (gsym != NULL) { @@ -3486,10 +3539,38 @@ Target_x86_64<size>::Relocate::relocate( case elfcpp::R_X86_64_GOTPCREL: { - gold_assert(have_got_offset); - typename elfcpp::Elf_types<size>::Elf_Addr value; - value = target->got_plt_section()->address() + got_offset; - Relocate_functions<size, false>::pcrela32(view, value, addend, address); + // Convert + // mov foo@GOTPCREL(%rip), %reg + // to lea foo(%rip), %reg. + // if possible. + if (rela.get_r_offset() >= 2 + && view[-2] == 0x8b + && ((gsym == NULL && !psymval->is_ifunc_symbol()) + || (gsym != NULL + && Target_x86_64<size>::can_convert_mov_to_lea(gsym)))) + { + view[-2] = 0x8d; + Relocate_functions<size, false>::pcrela32(view, object, psymval, addend, + address); + } + else + { + 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<size>(rela.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()); + } + typename elfcpp::Elf_types<size>::Elf_Addr value; + value = target->got_plt_section()->address() + got_offset; + Relocate_functions<size, false>::pcrela32(view, value, addend, address); + } } break; |