This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
PATCH: Fix 64-bit Solaris 2/x86 IE TLS code sequence
- From: Rainer Orth <ro at CeBiTec dot Uni-Bielefeld dot DE>
- To: gcc-patches at gcc dot gnu dot org
- Date: Wed, 24 Feb 2010 15:19:35 +0100
- Subject: PATCH: Fix 64-bit Solaris 2/x86 IE TLS code sequence
While investigating a couple of 64-bit libgomp testsuite failures on
Solaris 11/x86, I found a common root cause which manifests itself in
this minimal testcase:
int cnt;
#pragma omp threadprivate (cnt)
int
main (void)
{
cnt = 0;
return 0;
}
Compiled with gcc -m64 -fopenmp -o tie tie.c -lgomp, tie segfaults trying
to assign to cnt.
The problem is that the code sequence gcc emits in this case
movq %fs:0, %rdx
movq cnt@gottpoff(%rip), %rax
movl $0, (%rdx,%rax)
doesn't match the one expected by Sun ld, which is also clearly
documented in the Linker and Libraries Guide, Ch. 8, Thread-Local
Storage, x64: Initial Executable (IE):
http://docs.sun.com/app/docs/doc/819-0690/chapter8-1?a=view
Of course, only the first 2 instructions are part of the sequence:
movq %fs:0, %rax
addq cnt@gottpoff(%rip), %rax
movl $0, (%rax)
If I manually change the .s file and relink, the testcase works. This
can be confirmed in the OpenSolaris sources
http://src.opensolaris.org/source/xref/onnv/onnv-gate/usr/src/cmd/sgs/libld/common/machrel.amd.c#442
(tlsinstr_gd_ie): the use of %rax for both the thread pointer and the
tls variable address is required (and expected) by Sun ld.
I haven't yet checked if this is required by the AMD64 TLS ABI or if
this is a Sun-specific requirement. In any way, gld copes with the
gcc-emitted code just fine.
But even if we conclude that Sun ld is too restrictive in this case, we
need to fix gcc to work around its requirement, which is what the
following patch attempts:
* For one, I force the thread pointer into %rax if TARGET_SUN_TLS (which
has been reused here to be always 1 on Solaris 2, even with GNU as/ld;
this will be part of a subsequent patch to enable TLS with Sun as.
This part seems to work just fine.
* Afterwards, I try to emit the addq with destination %rax: this works
in some cases, but occasionally fails like this:
movq %fs:0, %rax
movq %rax, %rdx
addq cnt@gottpoff(%rip), %rdx
Being practically ignorant about this part of GCC, I need advice how
to fix this. Perhaps this can only be achieved with a define_insn in
i386.md? If so, how would this look?
Comments or suggestions?
Rainer
--
-----------------------------------------------------------------------------
Rainer Orth, Center for Biotechnology, Bielefeld University
2010-02-17 Rainer Orth <ro@CeBiTec.Uni-Bielefeld.DE>
* config/i386/i386.c (get_thread_pointer): Force thread pointer
into %rax if TARGET_64BIT && TARGET_SUN_TLS.
(legitimize_tls_address) <TLS_MODEL_INITIAL_EXEC>: Force address
into %rax if TARGET_64BIT && TARGET_SUN_TLS.
diff -r 12f2e6ffa730 -r 0ac196dcde37 gcc/config/i386/i386.c
--- a/gcc/config/i386/i386.c Wed Feb 17 14:19:49 2010 +0100
+++ b/gcc/config/i386/i386.c Wed Feb 17 14:20:38 2010 +0100
@@ -10221,7 +10221,10 @@
if (!to_reg)
return tp;
- reg = gen_reg_rtx (Pmode);
+ if (TARGET_64BIT && TARGET_SUN_TLS)
+ reg = gen_rtx_REG (Pmode, AX_REG);
+ else
+ reg = gen_reg_rtx (Pmode);
insn = gen_rtx_SET (VOIDmode, reg, tp);
insn = emit_insn (insn);
@@ -10349,8 +10352,13 @@
if (TARGET_64BIT || TARGET_ANY_GNU_TLS)
{
base = get_thread_pointer (for_mov || !TARGET_TLS_DIRECT_SEG_REFS);
- off = force_reg (Pmode, off);
- return gen_rtx_PLUS (Pmode, base, off);
+ if (TARGET_64BIT && TARGET_SUN_TLS)
+ return gen_rtx_PLUS (Pmode, base, off);
+ else
+ {
+ off = force_reg (Pmode, off);
+ return gen_rtx_PLUS (Pmode, base, off);
+ }
}
else
{