+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.
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
--- /dev/null
+#!/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
--- /dev/null
+ .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
--- /dev/null
+ .text
+ .globl _start
+ .type _start, @function
+_start:
+ movq _DYNAMIC@GOTPCREL(%rip), %rax
+ .size _start, .-_start
--- /dev/null
+ .text
+ .type foo, @function
+foo:
+ ret
+ .size foo, .-foo
+ .globl _start
+ .type _start, @function
+_start:
+ movq foo@GOTPCREL(%rip), %rax
+ .size _start, .-_start
--- /dev/null
+ .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
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
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
{
// 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.
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)
{
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;