[binutils-gdb] gold: x86-64: Fix TLSDESC relaxation for x32

H.J. Lu hjl@sourceware.org
Fri May 1 17:12:17 GMT 2020


https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=ccf20d460f73c48f3334e1401558df342c77ac8a

commit ccf20d460f73c48f3334e1401558df342c77ac8a
Author: H.J. Lu <hjl.tools@gmail.com>
Date:   Fri May 1 10:11:06 2020 -0700

    gold: x86-64: Fix TLSDESC relaxation for x32
    
    X32 TLSDESC sequences can be:
    
    40 8d 05 00 00 00 00    rex lea foo@TLSDESC(%rip), %reg
    ...
    67 ff 10                call    *foo@TLSCALL(%eax)
    
    or the same sequence as LP64:
    
    48 8d 05 00 00 00 00    lea     foo@TLSDESC(%rip), %reg
    ...
    ff 10                   call    *foo@TLSCALL(%rax)
    
    We need to support both sequences for x32.  For both GDesc -> IE/LE
    transitions,
    
    67 ff 10                call    *foo@TLSCALL(%eax)
    
    should relaxed to
    
    0f 1f 00                nopl    (%rax)
    
    For GDesc -> LE transition,
    
    40 8d 05 00 00 00 00    rex lea foo@TLSDESC(%rip), %reg
    
    should relaxed to
    
    40 c7 c0 fc ff ff ff    rex movl $foo@tpoff, %reg
    
    For GDesc -> IE transition,
    
    40 8d 05 00 00 00 00    rex lea foo@TLSDESC(%rip), %reg
    
    should relaxed to
    
    40 8b 05 00 00 00 00    rex movl foo@gottpoff(%rip), %eax
    
            PR gold/25426
            * x86_64.cc (Target_x86_64<size>::Relocate::tls_desc_gd_to_ie):
            For x32, relax "rex leal foo@tlsdesc(%rip), %reg" to
            "rex movl foo@gottpoff(%rip), %eax" and relax ""call *(%eax)"
            to "nopl (%rax)".
            (Target_x86_64<size>::Relocate::tls_desc_gd_to_le): For x32,
            relax "rex leal foo@tlsdesc(%rip), %reg" to
            "rex movl foo@tpoff, %eax" and relax "call *foo@tlscall(%eax)"
            to "nopl (%rax)".
            * testsuite/Makefile.am (tls_test_gnu2.o): Depend on
            gcctestdir/as.
            (tls_test_file2_gnu2.o): Likewise.
            (tls_test_c_gnu2.o): Likewise.
            * testsuite/Makefile.in: Regenerated.

Diff:
---
 gold/ChangeLog             | 17 +++++++++++
 gold/testsuite/Makefile.am |  6 ++--
 gold/testsuite/Makefile.in |  6 ++--
 gold/x86_64.cc             | 76 +++++++++++++++++++++++++++++++++++-----------
 4 files changed, 82 insertions(+), 23 deletions(-)

diff --git a/gold/ChangeLog b/gold/ChangeLog
index 0b7cb07fddf..23fb0709806 100644
--- a/gold/ChangeLog
+++ b/gold/ChangeLog
@@ -1,3 +1,20 @@
+2020-05-01  H.J. Lu  <hongjiu.lu@intel.com>
+
+	PR gold/25426
+	* x86_64.cc (Target_x86_64<size>::Relocate::tls_desc_gd_to_ie):
+	For x32, relax "rex leal foo@tlsdesc(%rip), %reg" to
+	"rex movl foo@gottpoff(%rip), %eax" and relax ""call *(%eax)"
+	to "nopl (%rax)".
+	(Target_x86_64<size>::Relocate::tls_desc_gd_to_le): For x32,
+	relax "rex leal foo@tlsdesc(%rip), %reg" to
+	"rex movl foo@tpoff, %eax" and relax "call *foo@tlscall(%eax)"
+	to "nopl (%rax)".
+	* testsuite/Makefile.am (tls_test_gnu2.o): Depend on
+	gcctestdir/as.
+	(tls_test_file2_gnu2.o): Likewise.
+	(tls_test_c_gnu2.o): Likewise.
+	* testsuite/Makefile.in: Regenerated.
+
 2020-05-01  H.J. Lu  <hongjiu.lu@intel.com>
 
 	PR gold/25473
diff --git a/gold/testsuite/Makefile.am b/gold/testsuite/Makefile.am
index 6187554c325..ceba00243ea 100644
--- a/gold/testsuite/Makefile.am
+++ b/gold/testsuite/Makefile.am
@@ -1032,11 +1032,11 @@ if TLS_GNU2_DIALECT
 
 check_PROGRAMS += tls_shared_gnu2_gd_to_ie_test
 
-tls_test_gnu2.o: tls_test.cc
+tls_test_gnu2.o: tls_test.cc gcctestdir/as
 	$(CXXCOMPILE) -c -fpic -mtls-dialect=gnu2 -o $@ $<
-tls_test_file2_gnu2.o: tls_test_file2.cc
+tls_test_file2_gnu2.o: tls_test_file2.cc gcctestdir/as
 	$(CXXCOMPILE) -c -fpic -mtls-dialect=gnu2 -o $@ $<
-tls_test_c_gnu2.o: tls_test_c.c
+tls_test_c_gnu2.o: tls_test_c.c gcctestdir/as
 	$(COMPILE) -c -fpic -mtls-dialect=gnu2 $(TLS_TEST_C_CFLAGS) -o $@ $<
 tls_test_gnu2_shared2.so: tls_test_file2_gnu2.o gcctestdir/ld
 	$(CXXLINK) -shared tls_test_file2_gnu2.o
diff --git a/gold/testsuite/Makefile.in b/gold/testsuite/Makefile.in
index 8d2f142a6f7..5fed355247c 100644
--- a/gold/testsuite/Makefile.in
+++ b/gold/testsuite/Makefile.in
@@ -8275,11 +8275,11 @@ uninstall-am:
 @GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@		tls_test_c_pic.o gcctestdir/ld
 @GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@	$(CXXLINK) $(THREADFLAGS) -pie tls_test_main_pie.o tls_test_pic.o tls_test_file2_pic.o tls_test_c_pic.o $(THREADLIBS)
 
-@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_GNU2_DIALECT_TRUE@@TLS_TRUE@tls_test_gnu2.o: tls_test.cc
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_GNU2_DIALECT_TRUE@@TLS_TRUE@tls_test_gnu2.o: tls_test.cc gcctestdir/as
 @GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_GNU2_DIALECT_TRUE@@TLS_TRUE@	$(CXXCOMPILE) -c -fpic -mtls-dialect=gnu2 -o $@ $<
-@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_GNU2_DIALECT_TRUE@@TLS_TRUE@tls_test_file2_gnu2.o: tls_test_file2.cc
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_GNU2_DIALECT_TRUE@@TLS_TRUE@tls_test_file2_gnu2.o: tls_test_file2.cc gcctestdir/as
 @GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_GNU2_DIALECT_TRUE@@TLS_TRUE@	$(CXXCOMPILE) -c -fpic -mtls-dialect=gnu2 -o $@ $<
-@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_GNU2_DIALECT_TRUE@@TLS_TRUE@tls_test_c_gnu2.o: tls_test_c.c
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_GNU2_DIALECT_TRUE@@TLS_TRUE@tls_test_c_gnu2.o: tls_test_c.c gcctestdir/as
 @GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_GNU2_DIALECT_TRUE@@TLS_TRUE@	$(COMPILE) -c -fpic -mtls-dialect=gnu2 $(TLS_TEST_C_CFLAGS) -o $@ $<
 @GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_GNU2_DIALECT_TRUE@@TLS_TRUE@tls_test_gnu2_shared2.so: tls_test_file2_gnu2.o gcctestdir/ld
 @GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_GNU2_DIALECT_TRUE@@TLS_TRUE@	$(CXXLINK) -shared tls_test_file2_gnu2.o
diff --git a/gold/x86_64.cc b/gold/x86_64.cc
index d4f1d6b2324..1d9d9209bf3 100644
--- a/gold/x86_64.cc
+++ b/gold/x86_64.cc
@@ -5472,12 +5472,15 @@ Target_x86_64<size>::Relocate::tls_desc_gd_to_ie(
 {
   if (r_type == elfcpp::R_X86_64_GOTPC32_TLSDESC)
     {
-      // leaq foo@tlsdesc(%rip), %rax
-      // ==> movq foo@gottpoff(%rip), %rax
+      // LP64: leaq foo@tlsdesc(%rip), %rax
+      //       ==> movq foo@gottpoff(%rip), %rax
+      // X32:  rex leal foo@tlsdesc(%rip), %eax
+      //       ==> rex movl foo@gottpoff(%rip), %eax
       tls::check_range(relinfo, relnum, rela.get_r_offset(), view_size, -3);
       tls::check_range(relinfo, relnum, rela.get_r_offset(), view_size, 4);
       tls::check_tls(relinfo, relnum, rela.get_r_offset(),
-		     ((view[-3] & 0xfb) == 0x48
+		     (((view[-3] & 0xfb) == 0x48
+		       || (size == 32 && (view[-3] & 0xfb) == 0x40))
 		      && view[-2] == 0x8d
 		      && (view[-1] & 0xc7) == 0x05));
       view[-2] = 0x8b;
@@ -5486,14 +5489,32 @@ Target_x86_64<size>::Relocate::tls_desc_gd_to_ie(
     }
   else
     {
-      // call *foo@tlscall(%rax)
-      // ==> nop; nop
+      // LP64: call *foo@tlscall(%rax)
+      //       ==> xchg %ax, %ax
+      // X32:  call *foo@tlscall(%eax)
+      //       ==> nopl (%rax)
       gold_assert(r_type == elfcpp::R_X86_64_TLSDESC_CALL);
       tls::check_range(relinfo, relnum, rela.get_r_offset(), view_size, 2);
+      int prefix = 0;
+      if (size == 32 && view[0] == 0x67)
+	{
+	  tls::check_range(relinfo, relnum, rela.get_r_offset(),
+			   view_size, 3);
+	  prefix = 1;
+	}
       tls::check_tls(relinfo, relnum, rela.get_r_offset(),
-		     view[0] == 0xff && view[1] == 0x10);
-      view[0] = 0x66;
-      view[1] = 0x90;
+		     view[prefix] == 0xff && view[prefix + 1] == 0x10);
+      if (prefix)
+	{
+	  view[0] = 0x0f;
+	  view[1] = 0x1f;
+	  view[2] = 0x00;
+	}
+      else
+	{
+	  view[0] = 0x66;
+	  view[1] = 0x90;
+	}
     }
 }
 
@@ -5513,15 +5534,18 @@ Target_x86_64<size>::Relocate::tls_desc_gd_to_le(
 {
   if (r_type == elfcpp::R_X86_64_GOTPC32_TLSDESC)
     {
-      // leaq foo@tlsdesc(%rip), %rax
-      // ==> movq foo@tpoff, %rax
+      // LP64: leaq foo@tlsdesc(%rip), %rax
+      //       ==> movq foo@tpoff, %rax
+      // X32:  rex leal foo@tlsdesc(%rip), %eax
+      //       ==> rex movl foo@tpoff, %eax
       tls::check_range(relinfo, relnum, rela.get_r_offset(), view_size, -3);
       tls::check_range(relinfo, relnum, rela.get_r_offset(), view_size, 4);
       tls::check_tls(relinfo, relnum, rela.get_r_offset(),
-		     ((view[-3] & 0xfb) == 0x48
+		     (((view[-3] & 0xfb) == 0x48
+		       || (size == 32 && (view[-3] & 0xfb) == 0x40))
 		      && view[-2] == 0x8d
 		      && (view[-1] & 0xc7) == 0x05));
-      view[-3] = 0x48 | ((view[-3] >> 2) & 1);
+      view[-3] = (view[-3] & 0x48) | ((view[-3] >> 2) & 1);
       view[-2] = 0xc7;
       view[-1] = 0xc0 | ((view[-1] >> 3) & 7);
       value -= tls_segment->memsz();
@@ -5529,14 +5553,32 @@ Target_x86_64<size>::Relocate::tls_desc_gd_to_le(
     }
   else
     {
-      // call *foo@tlscall(%rax)
-      // ==> nop; nop
+      // LP64: call *foo@tlscall(%rax)
+      //       ==> xchg %ax, %ax
+      // X32:  call *foo@tlscall(%eax)
+      //       ==> nopl (%rax)
       gold_assert(r_type == elfcpp::R_X86_64_TLSDESC_CALL);
       tls::check_range(relinfo, relnum, rela.get_r_offset(), view_size, 2);
+      int prefix = 0;
+      if (size == 32 && view[0] == 0x67)
+	{
+	  tls::check_range(relinfo, relnum, rela.get_r_offset(),
+			   view_size, 3);
+	  prefix = 1;
+	}
       tls::check_tls(relinfo, relnum, rela.get_r_offset(),
-		     view[0] == 0xff && view[1] == 0x10);
-      view[0] = 0x66;
-      view[1] = 0x90;
+		     view[prefix] == 0xff && view[prefix + 1] == 0x10);
+      if (prefix)
+	{
+	  view[0] = 0x0f;
+	  view[1] = 0x1f;
+	  view[2] = 0x00;
+	}
+      else
+	{
+	  view[0] = 0x66;
+	  view[1] = 0x90;
+	}
     }
 }


More information about the Binutils-cvs mailing list