From ccf20d460f73c48f3334e1401558df342c77ac8a Mon Sep 17 00:00:00 2001 From: "H.J. Lu" Date: Fri, 1 May 2020 10:11:06 -0700 Subject: 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::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::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 | 17 +++++++++++ gold/testsuite/Makefile.am | 6 ++-- gold/testsuite/Makefile.in | 6 ++-- gold/x86_64.cc | 76 +++++++++++++++++++++++++++++++++++----------- 4 files changed, 82 insertions(+), 23 deletions(-) (limited to 'gold') diff --git a/gold/ChangeLog b/gold/ChangeLog index 0b7cb07..23fb070 100644 --- a/gold/ChangeLog +++ b/gold/ChangeLog @@ -1,5 +1,22 @@ 2020-05-01 H.J. Lu + PR gold/25426 + * x86_64.cc (Target_x86_64::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::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 + PR gold/25473 * x86_64.cc (Target_x86_64::Relocate::tls_desc_gd_to_ie): Properly check r8 - r15 in "lea foo@TLSDESC(%rip), %reg". diff --git a/gold/testsuite/Makefile.am b/gold/testsuite/Makefile.am index 6187554..ceba002 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 8d2f142..5fed355 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 d4f1d6b..1d9d920 100644 --- a/gold/x86_64.cc +++ b/gold/x86_64.cc @@ -5472,12 +5472,15 @@ Target_x86_64::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::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::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::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; + } } } -- cgit v1.1