In the ELF Handling for Thread-Local Storage document [1] in section 4.1.3 SPARC General Dynamic TLS Model on page 20-21, following code sequence is defined for GD relocations: General Dynamic Model Code Sequence Initial Relocation Symbol 0x00 sethi %hi(@dtlndx(x)), %o0 R_SPARC_TLS_GD_HI22 x 0x04 add %o0,%lo(@dtlndx(x)), %o0 R_SPARC_TLS_GD_LO10 x 0x08 add %l7,%o0, %o0 R_SPARC_TLS_GD_ADD x 0x0c call __tls_get_addr R_SPARC_TLS_GD_CALL x With comment: > The code sequence must appear in the code as is. It is not possible to move > the second add instruction in the delay slot of the call instruction since > the linker would not recognize the instruction sequence. (2) and note (2): > This is at least what Sun’s documentation says and apparently how Sun’s > linker works. Given the relocations which show exactly what the instructions > do this seems not really necessary. However, GCC 7/9 emits this sequence in .o file: 2c: 11 00 00 00 sethi %hi(0), %o0 2c: R_SPARC_TLS_GD_HI22 __gcov_indirect_call_callee 30: 90 02 20 00 add %o0, 0, %o0 ! 0 <main> 30: R_SPARC_TLS_GD_LO10 __gcov_indirect_call_callee 34: 40 00 00 00 call 34 <main+0x34> 34: R_SPARC_TLS_GD_CALL __gcov_indirect_call_callee 38: 90 05 c0 08 add %l7, %o0, %o0 38: R_SPARC_TLS_GD_ADD __gcov_indirect_call_callee It is apparent that the compiler generated the GD TLS sequence in different order than the TLS document suggests. It placed the second add instruction in the branch delay slot of call instruction, which is against the document statement: "It is not possible to move the second add instruction in the delay slot of the call instruction" This relaxed order generated by GCC is no doubt more efficient, however, it is not understood by Solaris linker, which converts the call instruction during GD->IE transition to add instruction: 'add %g7, %o0, %o0' (opcode: 90 01 c0 08). The problem is that the original instruction in branch delay slot was supposed to execute before instruction on branch target (it calculates input argument for call instruction target), but after it is converted to add instruction, branch is gone and so is its delay slot and instructions execute in program order. This corrupts value in %o0 register as both instructions write to it but execute in different than originally supposed order and corrupted %o0 causes SIGSEGV (if lucky) in subsequent attempt to use it in memory de-reference to get value of a TLS variable.
[1] https://www.uclibc.org/docs/tls.pdf
How did you configure gcc?
Yep, a thinko pertaining to TARGET_GNU_TLS.
Fixing.
To answer previous question, here are configure options for GCC in Solaris: https://github.com/oracle/solaris-userland/blob/60efc343ffab1adac2d1c9cac7629af26d40de50/components/gcc9/Makefile#L91 CONFIGURE_OPTIONS += --infodir=$(CONFIGURE_INFODIR) CONFIGURE_OPTIONS += --libexecdir=$(CONFIGURE_PREFIX)/lib CONFIGURE_OPTIONS += --enable-languages="c,c++,fortran,go,objc" CONFIGURE_OPTIONS += --enable-shared CONFIGURE_OPTIONS += --enable-initfini-array CONFIGURE_OPTIONS += --disable-rpath CONFIGURE_OPTIONS += --with-system-zlib CONFIGURE_OPTIONS += --with-build-config=no CONFIGURE_OPTIONS += --with-gmp-include=$(shell pkg-config --variable=includedir libgmp) CONFIGURE_OPTIONS += --with-mpfr-include=$(shell pkg-config --variable=includedir libmpfr) CONFIGURE_OPTIONS += --without-gnu-ld --with-ld=$(USRBINDIR)/ld CONFIGURE_OPTIONS += --with-gnu-as --with-as=$(GNUBIN)/as See last two lines, GCC is built with GNU as, but Solaris ld.
The master branch has been updated by Eric Botcazou <ebotcazou@gcc.gnu.org>: https://gcc.gnu.org/g:81fc552558f54c6f691e7816da9ab4ad8483f7ef commit r10-6639-g81fc552558f54c6f691e7816da9ab4ad8483f7ef Author: Eric Botcazou <ebotcazou@gcc.gnu.org> Date: Fri Feb 14 19:21:02 2020 +0100 Fix problematic TLS sequences for the Solaris linker This is an old thinko pertaining to the interaction between TLS sequences and delay slot filling: the compiler knows that it cannot put instructions with TLS relocations into delay slots with the original Sun TLS model, but it tests TARGET_SUN_TLS in this context, which depends only on the assembler. So if the compiler is configured with the GNU assembler and the Solaris linker, then TARGET_GNU_TLS is set instead and the limitation is not enforced. PR target/93704 * config/sparc/sparc.c (eligible_for_call_delay): Test HAVE_GNU_LD in conjunction with TARGET_GNU_TLS in early return.
The releases/gcc-9 branch has been updated by Eric Botcazou <ebotcazou@gcc.gnu.org>: https://gcc.gnu.org/g:c1379a1c645684599b8902edcdf4a2b5f2648542 commit r9-8239-gc1379a1c645684599b8902edcdf4a2b5f2648542 Author: Eric Botcazou <ebotcazou@gcc.gnu.org> Date: Fri Feb 14 19:21:02 2020 +0100 Fix problematic TLS sequences for the Solaris linker This is an old thinko pertaining to the interaction between TLS sequences and delay slot filling: the compiler knows that it cannot put instructions with TLS relocations into delay slots with the original Sun TLS model, but it tests TARGET_SUN_TLS in this context, which depends only on the assembler. So if the compiler is configured with the GNU assembler and the Solaris linker, then TARGET_GNU_TLS is set instead and the limitation is not enforced. PR target/93704 * config/sparc/sparc.c (eligible_for_call_delay): Test HAVE_GNU_LD in conjunction with TARGET_GNU_TLS in early return.
The releases/gcc-8 branch has been updated by Eric Botcazou <ebotcazou@gcc.gnu.org>: https://gcc.gnu.org/g:c35cfc834eda41cd8b08ee989b028552ad9cd6a8 commit r8-10023-gc35cfc834eda41cd8b08ee989b028552ad9cd6a8 Author: Eric Botcazou <ebotcazou@gcc.gnu.org> Date: Fri Feb 14 19:21:02 2020 +0100 Fix problematic TLS sequences for the Solaris linker This is an old thinko pertaining to the interaction between TLS sequences and delay slot filling: the compiler knows that it cannot put instructions with TLS relocations into delay slots with the original Sun TLS model, but it tests TARGET_SUN_TLS in this context, which depends only on the assembler. So if the compiler is configured with the GNU assembler and the Solaris linker, then TARGET_GNU_TLS is set instead and the limitation is not enforced. PR target/93704 * config/sparc/sparc.c (eligible_for_call_delay): Test HAVE_GNU_LD in conjunction with TARGET_GNU_TLS in early return.
Thanks for reporting the problem.