Patchwork [build] Fix Solaris 2/x86 GD/LD TLS code sequences with Sun ld

login
register
mail settings
Submitter Rainer Orth
Date May 23, 2011, 5:22 p.m.
Message ID <ydd39k5uybr.fsf@manam.CeBiTec.Uni-Bielefeld.DE>
Download mbox | patch
Permalink /patch/97017/
State New
Headers show

Comments

Rainer Orth - May 23, 2011, 5:22 p.m.
As described in

	[testsuite] Provide TLS access model testcases
        http://gcc.gnu.org/ml/gcc-patches/2011-05/msg01601.html

both the 32 and 64-bit TLS GD and LD execution tests fail on Solaris 2
with Sun ld unless you have a very recent Solaris 11 version (snv_164).

This happens because the code sequences emitted by GCC don't match those
expected by Sun ld:

	32-bit x86: Thread-Local Variable Access
	http://download.oracle.com/docs/cd/E19963-01/html/819-0690/chapter8-20.html#gentextid-20367	

For GD, one needs to use call x@tlsgdplt here, but call ___tls_get_addr@plt
works, too.

For LD, one really needs call x@tlsldmplt.

The corresponding R_386_TLS_GD_PLT and R_386_TLS_LDM_PLT relocations are
not yet handled by binutils.

        x64: Thread-Local Variable Access
        http://download.oracle.com/docs/cd/E19963-01/html/819-0690/chapter8-20.html#chapter8-60

For both GD and LD, one needs to use call __tls_get_addr@plt.

The following patch handles this:

* It autoconfigures support for the @tlsgdplt and @tlsldmplt
  relocations: Sun as supports them, while gas doesn't yet.  I've got a
  patch in the works to fix this: while the gas part is easy, I have
  serious problems getting the ld side to work properly.  Unfortunately,
  I doubt the binutils maintainers will accept such partial support for
  the relocs.

* I'm using a new 'p' code to control the printing of @plt.  'P' doesn't
  work since this is needed in both PIC and non-PIC code.

Bootstrapped without regressions on i386-pc-solaris2.10.

Ok for mainline?

	Rainer


2010-12-30  Rainer Orth  <ro@CeBiTec.Uni-Bielefeld.DE>

	* configure.ac (gcc_cv_as_ix86_tlsgdplt): Check for @tlsgdplt
	(HAVE_AS_IX86_TLSGDPTL): Define.
	(gcc_cv_as_ix86_tlsldmplt): Check for @tlsldmplt.
	(HAVE_AS_IX86_TLSLDMPLT): Define.
	* configure: Regenerate.
	* config.in: Regenerate.
	* config/i386/i386.c (output_pic_addr_const): Handle code 'p' like 'P'.
	(ix86_print_operand): Handle code 'p'.
	* config/i386/i386.md (*tls_global_dynamic_32_gnu): Use @tlsgdplt
	if TARGET_SUN_TLS && HAVE_AS_IX86_TLSGDPLT.
	Use 'p' code.
	(*tls_global_dynamic_64): Use 'p' code.
	(*tls_local_dynamic_base_32_gnu): Use @tlsldmplt if TARGET_SUN_TLS
	&& HAVE_AS_IX86_TLSLDMPLT.
	Use 'p' code.
	(*tls_local_dynamic_base_64): Use 'p' code.

Patch

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
@@ -13209,7 +13209,7 @@  output_pic_addr_const (FILE *file, rtx x
 	  assemble_name (file, name);
 	}
       if (!TARGET_MACHO && !(TARGET_64BIT && DEFAULT_ABI == MS_ABI)
-	  && code == 'P' && ! SYMBOL_REF_LOCAL_P (x))
+	  && (code == 'P' || code == 'p') && ! SYMBOL_REF_LOCAL_P (x))
 	fputs ("@PLT", file);
       break;
 
@@ -13917,6 +13917,7 @@  get_some_local_dynamic_name (void)
    d -- print duplicated register operand for AVX instruction.
    D -- print condition for SSE cmp instruction.
    P -- if PIC, print an @PLT suffix.
+   p -- print an @PLT suffix for Sun ld.
    X -- don't print any sort of PIC '@' suffix for a symbol.
    & -- print some in-use local-dynamic symbol name.
    H -- print a memory address offset by 8; used for sse high-parts
@@ -14122,6 +14123,7 @@  ix86_print_operand (FILE *file, rtx x, i
 	case 'x':
 	case 'X':
 	case 'P':
+	case 'p':
 	  break;
 
 	case 's':
@@ -14426,7 +14428,8 @@  ix86_print_operand (FILE *file, rtx x, i
   else if (MEM_P (x))
     {
       /* No `byte ptr' prefix for call instructions or BLKmode operands.  */
-      if (ASSEMBLER_DIALECT == ASM_INTEL && code != 'X' && code != 'P'
+      if (ASSEMBLER_DIALECT == ASM_INTEL
+	  && code != 'X' && code != 'P' && code != 'p'
 	  && GET_MODE (x) != BLKmode)
 	{
 	  const char * size;
@@ -14462,9 +14465,13 @@  ix86_print_operand (FILE *file, rtx x, i
 
       x = XEXP (x, 0);
       /* Avoid (%rip) for call operands.  */
-      if (CONSTANT_ADDRESS_P (x) && code == 'P'
+      if (CONSTANT_ADDRESS_P (x) && (code == 'P' || code == 'p')
 	  && !CONST_INT_P (x))
-	output_addr_const (file, x);
+	{
+	  output_addr_const (file, x);
+	  if (code == 'p' && TARGET_SUN_TLS)
+	    fputs ("@PLT", file);
+	}
       else if (this_is_asm_operands && ! address_operand (x, VOIDmode))
 	output_operand_lossage ("invalid constraints for operand");
       else
@@ -14521,7 +14528,7 @@  ix86_print_operand (FILE *file, rtx x, i
 	  x = const0_rtx;
 	}
 
-      if (code != 'P')
+      if (code != 'P' && code != 'p')
 	{
 	  if (CONST_INT_P (x) || GET_CODE (x) == CONST_DOUBLE)
 	    {
@@ -14542,7 +14549,11 @@  ix86_print_operand (FILE *file, rtx x, i
       else if (flag_pic || MACHOPIC_INDIRECT)
 	output_pic_addr_const (file, x, code);
       else
-	output_addr_const (file, x);
+	{
+	  output_addr_const (file, x);
+	  if (code == 'p' && TARGET_SUN_TLS)
+	    fputs ("@PLT", file);
+	}
     }
 }
 
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
@@ -53,6 +53,7 @@ 
 ;; d -- print duplicated register operand for AVX instruction.
 ;; D -- print condition for SSE cmp instruction.
 ;; P -- if PIC, print an @PLT suffix.
+;; p -- if Sun ld, print an @PLT suffix.
 ;; X -- don't print any sort of PIC '@' suffix for a symbol.
 ;; & -- print some in-use local-dynamic symbol name.
 ;; H -- print a memory address offset by 8; used for sse high-parts
@@ -12367,7 +12368,10 @@ 
 {
   output_asm_insn
     ("lea{l}\t{%a2@tlsgd(,%1,1), %0|%0, %a2@tlsgd[%1*1]}", operands);
-  return "call\t%P3";
+  if (TARGET_SUN_TLS && HAVE_AS_IX86_TLSGDPLT)
+    return "call\t%a2@tlsgdplt";
+  else
+    return "call\t%p3";
 }
   [(set_attr "type" "multi")
    (set_attr "length" "12")])
@@ -12397,7 +12401,7 @@ 
     ("lea{q}\t{%a1@tlsgd(%%rip), %%rdi|rdi, %a1@tlsgd[rip]}", operands);
   fputs (ASM_SHORT "0x6666\n", asm_out_file);
   fputs ("\trex64\n", asm_out_file);
-  return "call\t%P2";
+  return "call\t%p2";
 }
   [(set_attr "type" "multi")
    (set_attr "length" "16")])
@@ -12424,7 +12428,10 @@ 
 {
   output_asm_insn
     ("lea{l}\t{%&@tlsldm(%1), %0|%0, %&@tlsldm[%1]}", operands);
-  return "call\t%P2";
+  if (TARGET_SUN_TLS && HAVE_AS_IX86_TLSLDMPLT)
+    return "call\t%&@tlsldmplt";
+  else
+    return "call\t%p2";
 }
   [(set_attr "type" "multi")
    (set_attr "length" "11")])
@@ -12450,7 +12457,7 @@ 
 {
   output_asm_insn
     ("lea{q}\t{%&@tlsld(%%rip), %%rdi|rdi, %&@tlsld[rip]}", operands);
-  return "call\t%P1";
+  return "call\t%p1";
 }
   [(set_attr "type" "multi")
    (set_attr "length" "12")])
diff --git a/gcc/configure.ac b/gcc/configure.ac
--- a/gcc/configure.ac
+++ b/gcc/configure.ac
@@ -3653,6 +3653,20 @@  foo:	nop
         [AC_DEFINE(HAVE_AS_IX86_REP_LOCK_PREFIX, 1,
           [Define if the assembler supports 'rep <insn>, lock <insn>'.])])
 
+    gcc_GAS_CHECK_FEATURE([R_386_TLS_GD_PLT reloc],
+        gcc_cv_as_ix86_tlsgdplt,,,
+	[call    tls_gd@tlsgdplt])
+    AC_DEFINE_UNQUOTED(HAVE_AS_IX86_TLSGDPLT,
+      [`if test $gcc_cv_as_ix86_tlsgdplt = yes; then echo 1; else echo 0; fi`],
+      [Define 0/1 if your assembler supports @tlsgdplt.])
+
+    gcc_GAS_CHECK_FEATURE([R_386_TLS_LDM_PLT reloc],
+        gcc_cv_as_ix86_tlsldmplt,,,
+	[call    tls_ld@tlsldmplt])
+    AC_DEFINE_UNQUOTED(HAVE_AS_IX86_TLSLDMPLT,
+      [`if test $gcc_cv_as_ix86_tlsldmplt = yes; then echo 1; else echo 0; fi`],
+      [Define 0/1 if your assembler supports @tlsldmplt.])
+
     ;;
 
   ia64*-*-*)