This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

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
 	{


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]