From c4fc4724a6afd605692b24c0af24c7e234dc5ace Mon Sep 17 00:00:00 2001 From: Ilya Tocar Date: Wed, 1 Apr 2015 16:48:38 +0300 Subject: [PATCH] Convert mov foo@GOT(%reg), %reg to lea foo@GOTOFF(%reg), %reg 2015-04-01 Ilya Tocar 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. --- gold/ChangeLog | 17 ++++ gold/i386.cc | 127 ++++++++++++++++++++++-------- gold/testsuite/Makefile.am | 56 +++++++++++++ gold/testsuite/i386_mov_to_lea.sh | 36 +++++++++ gold/testsuite/i386_mov_to_lea1.s | 11 +++ gold/testsuite/i386_mov_to_lea2.s | 10 +++ gold/testsuite/i386_mov_to_lea3.s | 4 + gold/testsuite/i386_mov_to_lea4.s | 12 +++ gold/testsuite/i386_mov_to_lea5.s | 12 +++ 9 files changed, 252 insertions(+), 33 deletions(-) create mode 100755 gold/testsuite/i386_mov_to_lea.sh create mode 100644 gold/testsuite/i386_mov_to_lea1.s create mode 100644 gold/testsuite/i386_mov_to_lea2.s create mode 100644 gold/testsuite/i386_mov_to_lea3.s create mode 100644 gold/testsuite/i386_mov_to_lea4.s create mode 100644 gold/testsuite/i386_mov_to_lea5.s diff --git a/gold/ChangeLog b/gold/ChangeLog index be6eb9f144..6a8435553a 100644 --- a/gold/ChangeLog +++ b/gold/ChangeLog @@ -1,3 +1,20 @@ +2015-04-01 Ilya Tocar + + 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. + 2015-04-01 H.J. Lu * Makefile.am (ZLIB): New. diff --git a/gold/i386.cc b/gold/i386.cc index 3bc3d9461c..086314ee80 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: diff --git a/gold/testsuite/Makefile.am b/gold/testsuite/Makefile.am index e68c025120..d64547e906 100644 --- a/gold/testsuite/Makefile.am +++ b/gold/testsuite/Makefile.am @@ -962,6 +962,62 @@ endif FN_PTRS_IN_SO_WITHOUT_PIC endif TLS +if DEFAULT_TARGET_I386 + +check_SCRIPTS += i386_mov_to_lea.sh +check_DATA += i386_mov_to_lea1.stdout i386_mov_to_lea2.stdout \ + i386_mov_to_lea3.stdout i386_mov_to_lea4.stdout \ + i386_mov_to_lea5.stdout i386_mov_to_lea6.stdout \ + i386_mov_to_lea7.stdout i386_mov_to_lea8.stdout +MOSTLYCLEANFILES += i386_mov_to_lea1 i386_mov_to_lea2 i386_mov_to_lea3 \ + i386_mov_to_lea4 i386_mov_to_lea5 i386_mov_to_lea6 \ + i386_mov_to_lea7 i386_mov_to_lea8 + +i386_mov_to_lea1.o: i386_mov_to_lea1.s + $(TEST_AS) --32 -o $@ $< +i386_mov_to_lea2.o: i386_mov_to_lea2.s + $(TEST_AS) --32 -o $@ $< +i386_mov_to_lea3.o: i386_mov_to_lea3.s + $(TEST_AS) --32 -o $@ $< +i386_mov_to_lea4.o: i386_mov_to_lea4.s + $(TEST_AS) --32 -o $@ $< +i386_mov_to_lea5.o: i386_mov_to_lea5.s + $(TEST_AS) --32 -o $@ $< +i386_mov_to_lea1: i386_mov_to_lea1.o + ../ld-new -Bsymbolic -shared -melf_i386 -o $@ $< +i386_mov_to_lea2: i386_mov_to_lea1.o + ../ld-new -pie -melf_i386 -o $@ $< +i386_mov_to_lea3: i386_mov_to_lea1.o + ../ld-new -melf_i386 -o $@ $< +i386_mov_to_lea4: i386_mov_to_lea1.o + ../ld-new -melf_i386 -shared -o $@ $< +i386_mov_to_lea5: i386_mov_to_lea2.o + ../ld-new -melf_i386 -shared -o $@ $< +i386_mov_to_lea6: i386_mov_to_lea3.o + ../ld-new -melf_i386 -shared -o $@ $< +i386_mov_to_lea7: i386_mov_to_lea4.o + ../ld-new -melf_i386 -shared -o $@ $< +i386_mov_to_lea8: i386_mov_to_lea5.o + ../ld-new -melf_i386 -shared -o $@ $< +i386_mov_to_lea1.stdout: i386_mov_to_lea1 + $(TEST_OBJDUMP) -dw $< > $@ +i386_mov_to_lea2.stdout: i386_mov_to_lea2 + $(TEST_OBJDUMP) -dw $< > $@ +i386_mov_to_lea3.stdout: i386_mov_to_lea3 + $(TEST_OBJDUMP) -dw $< > $@ +i386_mov_to_lea4.stdout: i386_mov_to_lea4 + $(TEST_OBJDUMP) -dw $< > $@ +i386_mov_to_lea5.stdout: i386_mov_to_lea5 + $(TEST_OBJDUMP) -dw $< > $@ +i386_mov_to_lea6.stdout: i386_mov_to_lea6 + $(TEST_OBJDUMP) -dw $< > $@ +i386_mov_to_lea7.stdout: i386_mov_to_lea7 + $(TEST_OBJDUMP) -dw $< > $@ +i386_mov_to_lea8.stdout: i386_mov_to_lea8 + $(TEST_OBJDUMP) -dw $< > $@ + +endif DEFAULT_TARGET_I386 + check_PROGRAMS += many_sections_test many_sections_test_SOURCES = many_sections_test.cc many_sections_test_DEPENDENCIES = gcctestdir/ld diff --git a/gold/testsuite/i386_mov_to_lea.sh b/gold/testsuite/i386_mov_to_lea.sh new file mode 100755 index 0000000000..03703729d6 --- /dev/null +++ b/gold/testsuite/i386_mov_to_lea.sh @@ -0,0 +1,36 @@ +#!/bin/sh + +# i386_mov_to_lea.sh -- a test for mov2lea conversion. + +# Copyright (C) 2010-2015 Free Software Foundation, Inc. +# Written by Tocar Ilya + +# 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]\+(%ecx),%eax" i386_mov_to_lea1.stdout +grep -q "lea -0x[a-f0-9]\+(%ecx),%eax" i386_mov_to_lea2.stdout +grep -q "lea -0x[a-f0-9]\+(%ecx),%eax" i386_mov_to_lea3.stdout +grep -q "mov -0x[a-f0-9]\+(%ecx),%eax" i386_mov_to_lea4.stdout +grep -q "lea -0x[a-f0-9]\+(%ecx),%eax" i386_mov_to_lea5.stdout +grep -q "mov -0x[a-f0-9]\+(%ecx),%eax" i386_mov_to_lea6.stdout +grep -q "lea -0x[a-f0-9]\+(%ecx),%eax" i386_mov_to_lea7.stdout +grep -q "mov -0x[a-f0-9]\+(%ecx),%eax" i386_mov_to_lea8.stdout + +exit 0 diff --git a/gold/testsuite/i386_mov_to_lea1.s b/gold/testsuite/i386_mov_to_lea1.s new file mode 100644 index 0000000000..6d0f436ee1 --- /dev/null +++ b/gold/testsuite/i386_mov_to_lea1.s @@ -0,0 +1,11 @@ + .text + .globl foo + .type foo, @function +foo: + ret + .size foo, .-foo + .globl bar + .type bar, @function +bar: + movl foo@GOT(%ecx), %eax + .size bar, .-bar diff --git a/gold/testsuite/i386_mov_to_lea2.s b/gold/testsuite/i386_mov_to_lea2.s new file mode 100644 index 0000000000..65f1bfd722 --- /dev/null +++ b/gold/testsuite/i386_mov_to_lea2.s @@ -0,0 +1,10 @@ + .text + .type foo, @function +foo: + ret + .size foo, .-foo + .globl bar + .type bar, @function +bar: + movl foo@GOT(%ecx), %eax + .size bar, .-bar diff --git a/gold/testsuite/i386_mov_to_lea3.s b/gold/testsuite/i386_mov_to_lea3.s new file mode 100644 index 0000000000..6785e71c79 --- /dev/null +++ b/gold/testsuite/i386_mov_to_lea3.s @@ -0,0 +1,4 @@ + .type bar, @function +bar: + movl _DYNAMIC@GOT(%ecx), %eax + .size bar, .-bar diff --git a/gold/testsuite/i386_mov_to_lea4.s b/gold/testsuite/i386_mov_to_lea4.s new file mode 100644 index 0000000000..7e4c4db6ec --- /dev/null +++ b/gold/testsuite/i386_mov_to_lea4.s @@ -0,0 +1,12 @@ + .text + .globl foo + .hidden foo + .type foo, @function +foo: + ret + .size foo, .-foo + .globl bar + .type bar, @function +bar: + movl foo@GOT(%ecx), %eax + .size bar, .-bar diff --git a/gold/testsuite/i386_mov_to_lea5.s b/gold/testsuite/i386_mov_to_lea5.s new file mode 100644 index 0000000000..6999aae23e --- /dev/null +++ b/gold/testsuite/i386_mov_to_lea5.s @@ -0,0 +1,12 @@ + .text + .globl foo + .protected foo + .type foo, @function +foo: + ret + .size foo, .-foo + .globl bar + .type bar, @function +bar: + movl foo@GOT(%ecx), %eax + .size bar, .-bar