When using GNU as with Solaris ld, the TLS local dynamic tests (gcc.dg/torture/tls/run-ld.c etc.) FAIL to execute before Solaris 11: the programs crash with an illegal instruction: e.g. in the gcc.dg/lto/20090210 test, we have
0x8050ce0 <main+48>: mov %gs:0x0,%eax 0x8050ce6 <main+54>: call 0x8050ce7 <main+55> 0x8050ce7 <main+55>: cld 0x8050ce8 <main+56>: (bad) The reason is that Solaris ld before Solaris 11 requires the use of the @tlsldmplt relocation documented in the Solaris 10 Linker and Libraries Guide: http://docs.oracle.com/cd/E26505_01/html/E26506/chapter8-20.html#gentextid-23600 Unfortunately, gas doesn't support that relocation. While adding the gas side was easy, I completely failed for gld and didn't propose the incomplete patch to binutils since it would (rightly) have been rejected. Old versions of ld mishandle the TLS LD code sequence emitted by gcc when @tlsldmplt isn't available, causing the crashes observed. So ld cannot handle what gas emits and gas cannot emit what ld requires. The only solution seems to fall back to the GD model in that case, which is ugly but certainly better than having perfectly valid programs crash. The following patch does just that. It carefully restricts its actions to Solaris. I'm falling back to using dis when objdump isn't available to avoid enabling this fallback unnecessarily. Bootstraps on i386-pc-solaris2.{9,10,11} (as/ld, gas/ld, gas/gld, as/gld), amd64-pc-solaris2.{10,11} (as/ld, gas/ld), x86_64-unknown-linux-gnu, and i686-unknown-linux-gnu either completed successfully or still running. Ok for mainline if those pass? Thanks. Rainer 2014-03-04 Rainer Orth <r...@cebitec.uni-bielefeld.de> * configure.ac (TLS_SECTION_ASM_FLAG): Save as tls_section_flag. (LIB_TLS_SPEC): Save as ld_tls_libs. (HAVE_AS_IX86_TLSLDMPLT): Define as 1/0. (HAVE_AS_IX86_TLSLDM): New test. * configure, config.in: Regenerate. * config/i386/i386.c (legitimize_tls_address): Fall back to TLS_MODEL_GLOBAL_DYNAMIC on 32-bit Solaris/x86 if tool chain cannot support TLS_MODEL_LOCAL_DYNAMIC. * config/i386/i386.md (*tls_local_dynamic_base_32_gnu): Use if instead of #ifdef in HAVE_AS_IX86_TLSLDMPLT test.
# HG changeset patch # Parent 7e1c533059af7a5120250c5c055ae22288bd828a Disable local dynamic TLS model on Solaris/x86 if as/ld cannot handle it diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c --- a/gcc/config/i386/i386.c +++ b/gcc/config/i386/i386.c @@ -13396,6 +13396,13 @@ legitimize_tls_address (rtx x, enum tls_ enum machine_mode tp_mode = Pmode; int type; + /* Fall back to global dynamic model if tool chain cannot support local + dynamic. */ + if (TARGET_SUN_TLS && !TARGET_64BIT + && !HAVE_AS_IX86_TLSLDMPLT && !HAVE_AS_IX86_TLSLDM + && model == TLS_MODEL_LOCAL_DYNAMIC) + model = TLS_MODEL_GLOBAL_DYNAMIC; + switch (model) { case TLS_MODEL_GLOBAL_DYNAMIC: diff --git a/gcc/config/i386/i386.md b/gcc/config/i386/i386.md --- a/gcc/config/i386/i386.md +++ b/gcc/config/i386/i386.md @@ -12962,11 +12962,12 @@ output_asm_insn ("lea{l}\t{%&@tlsldm(%1), %0|%0, %&@tlsldm[%1]}", operands); if (TARGET_SUN_TLS) -#ifdef HAVE_AS_IX86_TLSLDMPLT - return "call\t%&@tlsldmplt"; -#else - return "call\t%p2@plt"; -#endif + { + if (HAVE_AS_IX86_TLSLDMPLT) + return "call\t%&@tlsldmplt"; + else + return "call\t%p2@plt"; + } return "call\t%P2"; } [(set_attr "type" "multi") diff --git a/gcc/configure.ac b/gcc/configure.ac --- a/gcc/configure.ac +++ b/gcc/configure.ac @@ -2973,6 +2973,7 @@ foo: .long 25 .section .tdata,"awt",@progbits' tls_first_major=0 tls_first_minor=0 + tls_section_flag=t changequote([,])dnl AC_DEFINE(TLS_SECTION_ASM_FLAG, 't', [Define to the flag used to mark TLS sections if the default (`T') doesn't work.]) @@ -2982,6 +2983,7 @@ changequote(,)dnl .section ".tdata","awT",@progbits' tls_first_major=2 tls_first_minor=14 + tls_section_flag=T tls_as_opt="--fatal-warnings" fi conftest_s="$conftest_s @@ -3012,6 +3014,7 @@ foo: .long 25 movq $foo@TPOFF, %rax' tls_first_major=2 tls_first_minor=14 + tls_section_flag=T tls_as_opt=--fatal-warnings ;; ia64-*-*) @@ -3368,6 +3371,7 @@ case "$target" in # (32-bit x86) only lived in libthread, so check for that. Keep # set_have_as_tls if found, disable if not. AC_SEARCH_LIBS([$tga_func], [thread],, [set_have_as_tls=no]) + ld_tls_libs="$LIBS" # Clear LIBS if we cannot support TLS. if test $set_have_as_tls = no; then LIBS= @@ -3924,9 +3928,48 @@ foo: nop && $gcc_cv_ld -o conftest conftest.o -G > /dev/null 2>&1; then gcc_cv_as_ix86_tlsldmplt=yes fi - rm -f conftest], - [AC_DEFINE(HAVE_AS_IX86_TLSLDMPLT, 1, - [Define if your assembler and linker support @tlsldmplt.])]) + rm -f conftest]) + AC_DEFINE_UNQUOTED(HAVE_AS_IX86_TLSLDMPLT, + [`if test $gcc_cv_as_ix86_tlsldmplt = yes; then echo 1; else echo 0; fi`], + [Define to 1 if your assembler and linker support @tlsldmplt.]) + + # Enforce 32-bit output with gas and gld. + if test x$gas = xyes; then + as_ix86_tls_ldm_opt="--32" + fi + if echo "$ld_ver" | grep GNU > /dev/null; then + if $gcc_cv_ld -V 2>/dev/null | grep elf_i386_sol2 > /dev/null; then + ld_ix86_tls_ldm_opt="-melf_i386_sol2" + else + ld_ix86_tls_ldm_opt="-melf_i386" + fi + fi + conftest_s=' + .section .text,"ax",@progbits + .globl _start + .type _start, @function +_start: + leal value@tlsldm(%ebx), %eax + call ___tls_get_addr@plt + + .section .tdata,"aw'$tls_section_flag'",@progbits + .type value, @object +value:' + gcc_GAS_CHECK_FEATURE([R_386_TLS_LDM reloc], + gcc_cv_as_ix86_tlsldm,, + [$as_ix86_tls_ldm_opt], + [$conftest_s], + [if test x$gcc_cv_ld != x && test x$gcc_cv_objdump != x \ + && $gcc_cv_ld $ld_ix86_tls_ldm_opt -o conftest conftest.o $ld_tls_libs -lc > /dev/null 2>&1; then + if $gcc_cv_objdump -d conftest 2>/dev/null | grep nop > /dev/null \ + || dis conftest 2>/dev/null | grep nop > /dev/null; then + gcc_cv_as_ix86_tlsldm=yes + fi + fi + rm -f conftest]) + AC_DEFINE_UNQUOTED(HAVE_AS_IX86_TLSLDM, + [`if test $gcc_cv_as_ix86_tlsldm = yes; then echo 1; else echo 0; fi`], + [Define to 1 if your assembler and linker support @tlsldm.]) ;;
-- ----------------------------------------------------------------------------- Rainer Orth, Center for Biotechnology, Bielefeld University