[PATCH] gold: x86-64: Fix TLSDESC relaxation for x32
H.J. Lu
hjl.tools@gmail.com
Fri May 1 15:55:59 GMT 2020
On Mon, Jan 20, 2020 at 8:08 PM H.J. Lu <hjl.tools@gmail.com> wrote:
>
> 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
>
> Tested with GCC 10 20200121 on Linux/x32. OK for master?
>
> Thanks.
>
> H.J.
> --
> 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/testsuite/Makefile.am | 6 +--
> gold/testsuite/Makefile.in | 6 +--
> gold/x86_64.cc | 78 ++++++++++++++++++++++++++++++--------
> 3 files changed, 68 insertions(+), 22 deletions(-)
>
> diff --git a/gold/testsuite/Makefile.am b/gold/testsuite/Makefile.am
> index ed1ea1755ac..397bf694000 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 9533b0e20b2..d02311564e7 100644
> --- a/gold/testsuite/Makefile.in
> +++ b/gold/testsuite/Makefile.in
> @@ -8213,11 +8213,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 a65e2c55e9e..ee6c0c08572 100644
> --- a/gold/x86_64.cc
> +++ b/gold/x86_64.cc
> @@ -5474,26 +5474,49 @@ 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] == 0x48 && view[-2] == 0x8d && view[-1] == 0x05);
> + ((view[-3] == 0x48
> + || (size == 32 && view[-3] == 0x40))
> + && view[-2] == 0x8d
> + && view[-1] == 0x05));
> view[-2] = 0x8b;
> const elfcpp::Elf_Xword addend = rela.get_r_addend();
> Relocate_functions<size, false>::pcrela32(view, value, addend, address);
> }
> 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,12 +5536,17 @@ 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] == 0x48 && view[-2] == 0x8d && view[-1] == 0x05);
> + ((view[-3] == 0x48
> + || (size == 32 && view[-3] == 0x40))
> + && view[-2] == 0x8d
> + && view[-1] == 0x05));
> view[-2] = 0xc7;
> view[-1] = 0xc0;
> value -= tls_segment->memsz();
> @@ -5526,14 +5554,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;
> + }
> }
> }
>
> --
> 2.24.1
>
I am checking in this patch.
--
H.J.
More information about the Binutils
mailing list