[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