gold: x86-64: Fix TLSDESC relaxation for x32
authorH.J. Lu <hjl.tools@gmail.com>
Fri, 1 May 2020 17:11:06 +0000 (10:11 -0700)
committerH.J. Lu <hjl.tools@gmail.com>
Fri, 1 May 2020 17:11:23 +0000 (10:11 -0700)
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.

gold/ChangeLog
gold/testsuite/Makefile.am
gold/testsuite/Makefile.in
gold/x86_64.cc

index 0b7cb07fddf9eec920f916e2212f10726ec6b49f..23fb07098060e0eead32953e434dff045c5e45e1 100644 (file)
@@ -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
index 6187554c3251a1cb2543469be6cb513cb92000b3..ceba00243ea2b32746d5dc2f17b3ef9d889d04e8 100644 (file)
@@ -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
index 8d2f142a6f70aac39ce8b08d33b31c20fce75044..5fed355247c0b5e61f61fbb2c13280d58eeb860e 100644 (file)
@@ -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
index d4f1d6b2324e44e3e1a355adc1ca3c85d6a32812..1d9d9209bf3ac9721b6fbc21e61136d7e831195e 100644 (file)
@@ -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;
+       }
     }
 }