[Gold,x86_64] Convert mov foo@GOTPCREL(%rip), %reg to lea foo(%rip), %reg
authorIlya Tocar <ilya.tocar@intel.com>
Mon, 6 Apr 2015 09:37:34 +0000 (12:37 +0300)
committerIlya Tocar <ilya.tocar@intel.com>
Mon, 6 Apr 2015 09:37:34 +0000 (12:37 +0300)
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.
---

gold/ChangeLog
gold/testsuite/Makefile.am
gold/testsuite/x86_64_mov_to_lea.sh [new file with mode: 0755]
gold/testsuite/x86_64_mov_to_lea1.s [new file with mode: 0644]
gold/testsuite/x86_64_mov_to_lea2.s [new file with mode: 0644]
gold/testsuite/x86_64_mov_to_lea3.s [new file with mode: 0644]
gold/testsuite/x86_64_mov_to_lea4.s [new file with mode: 0644]
gold/x86_64.cc

index ea4390eeb8c525f1ce4b53ad0d1b26e2afa7519b..a838b05ae5a0e9e9b8f11cfa0912d939d41c2d56 100644 (file)
@@ -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.
index d64547e906d325235348d6a4315ebbb794f1c072..1ffeb50b326d8c9e6decf1ee7a9379a3e2ddf332 100644 (file)
@@ -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 (executable)
index 0000000..ee24a41
--- /dev/null
@@ -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 (file)
index 0000000..4dce487
--- /dev/null
@@ -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 (file)
index 0000000..2a11b7a
--- /dev/null
@@ -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 (file)
index 0000000..ac43b78
--- /dev/null
@@ -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 (file)
index 0000000..37bee32
--- /dev/null
@@ -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
index 4543c8a8abc25f1ba7fea916f676badae0abdf98..007af1d4c42a0d862474f442b3a916d1a8762b9a 100644 (file)
@@ -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;