This is the mail archive of the binutils@sourceware.org mailing list for the binutils 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 i386 GD->IE TLS transition


Hi!

#!/bin/sh
CFLAGS="-g -m32 -O2"
gcc $CFLAGS -fpic -c -o a.o -xc - <<EOF
extern __thread int data; extern int *foo (void); extern void abort (void);
int main (void) { if (foo () != &data) abort (); return 0; }
EOF
gcc $CFLAGS -c -o b.o -xc - <<EOF
extern __thread int data;
int *foo (void) { return &data; }
EOF
echo '__thread int data;' | gcc $CFLAGS -c -o c.o -xc -
gcc $CFLAGS -Wl,--export-dynamic -o test a.o b.o c.o
./test; echo $?

is mis-linked, as the GOT slot contains R_386_TPOFF value (0xfffffffc),
but the code in main subtracts this value from %gs:0 rather than adds to it.

Apparently H.J. was trying to fix this two months ago, but the fix was both
insufficient and flawed.
If we only have R_386_TLS_GOTIE/R_386_TLS_IE/R_386_TLS_GD relocations
for some symbols, we don't need 2 got slots and 2 dynamic
relocations, one is enough and the pre-2006-04-08 code was correctly
assuming that.  The only bug is that the subl -> addl change was keyed off
the r_type value and so did the right thing only if -shared
(if -shared, elf_i386_tls_transition always return the r_type passed to it
unchanged and the
          if (r_type == R_386_TLS_GD
              || r_type == R_386_TLS_GOTDESC
              || r_type == R_386_TLS_DESC_CALL)
            {
              if (tls_type == GOT_TLS_IE_POS)
                r_type = R_386_TLS_GOTIE;
              else if (tls_type & GOT_TLS_IE)
                r_type = R_386_TLS_IE_32;
            }
hunk in that case fired and set r_type to R_386_TLS_GOTIE (which means
subl was correctly changed into addl)).  For executables though
elf_i386_tls_transition returns R_386_TLS_IE_32 though (assuming the symbol
is not local), the r_type = R_386_TLS_GOTIE; statement is not executed
(eventhough tls_type == GOT_TLS_IE_POS) and subl is unchanged.

The following patch reverts the 2006-04-08 change and instead
replaces in GD->IE transition
-             if (r_type == R_386_TLS_GOTIE)
-               {
-                 contents[roff + 6] = 0x03;
-                 if (tls_type == GOT_TLS_IE_BOTH)
-                   off += 4;
-               }
with:
+             if (tls_type == GOT_TLS_IE_POS)
+               contents[roff + 6] = 0x03;
(clearly, if tls_type is GOT_TLS_IE_BOTH, r_type would never be
R_386_TLS_GOTIE here and we really should adjust according to the exact
TLS type of the GOT slot).

Ok for trunk?

Alternatively, we could revert the 2006-04-08 patch and replace
          if (r_type == R_386_TLS_GD
              || r_type == R_386_TLS_GOTDESC
              || r_type == R_386_TLS_DESC_CALL)
            {
              if (tls_type == GOT_TLS_IE_POS)
                r_type = R_386_TLS_GOTIE;
              else if (tls_type & GOT_TLS_IE)
                r_type = R_386_TLS_IE_32;
            }
with:
          if (ELF32_R_TYPE (rel->r_info) == R_386_TLS_GD
              || ELF32_R_TYPE (rel->r_info) == R_386_TLS_GOTDESC
              || ELF32_R_TYPE (rel->r_info) == R_386_TLS_DESC_CALL)
            {
              if (tls_type == GOT_TLS_IE_POS)
                r_type = R_386_TLS_GOTIE;
              else if (tls_type & GOT_TLS_IE)
                r_type = R_386_TLS_IE_32;
            }
(and remove the unneeded:
-                 if (tls_type == GOT_TLS_IE_BOTH)
-                   off += 4;
), but as GOTDESC and DESC_CALL code only look at tls_type and not
at r_type, this seems more consistent with it.

2006-06-23  Jakub Jelinek  <jakub@redhat.com>

	PR ld/2513
	* elf32-i386.c (GOT_TLS_MASK, GOT_TLS_IE_IE, GOT_TLS_IE_GD,
	GOT_TLS_IE_MASK, elf_i386_check_relocs, allocate_dynrelocs): Revert
	2006-04-08 changes.
	(elf_i386_relocate_section): Likewise.  For GD->IE transition
	change subl into addl whenever tls_type is GOT_TLS_IE_POS.

	* ld-i386/tlsbin.dd: Fix expected output.

--- ld/testsuite/ld-i386/tlsbin.dd.jj	2004-05-11 19:02:12.000000000 +0200
+++ ld/testsuite/ld-i386/tlsbin.dd	2006-06-23 15:10:54.000000000 +0200
@@ -50,7 +50,7 @@ Disassembly of section .text:
 #  GD -> IE because variable is not defined in executable where
 #  the variable is referenced through @gotntpoff too
  8049035:	65 a1 00 00 00 00[ 	]+mov    %gs:0x0,%eax
- 804903b:	2b 83 dc ff ff ff[ 	]+sub    0xffffffdc\(%ebx\),%eax
+ 804903b:	03 83 dc ff ff ff[ 	]+add    0xffffffdc\(%ebx\),%eax
 #				->R_386_TLS_TPOFF	sG3
  8049041:	90[ 	]+nop *
  8049042:	90[ 	]+nop *
--- bfd/elf32-i386.c.jj	2006-06-19 10:33:41.000000000 +0200
+++ bfd/elf32-i386.c	2006-06-23 15:01:39.000000000 +0200
@@ -582,10 +582,6 @@ struct elf_i386_link_hash_entry
 #define GOT_TLS_IE_NEG	6
 #define GOT_TLS_IE_BOTH 7
 #define GOT_TLS_GDESC	8
-#define GOT_TLS_MASK	0x0f
-#define GOT_TLS_IE_IE	0x10
-#define GOT_TLS_IE_GD	0x20
-#define GOT_TLS_IE_MASK	0x30
 #define GOT_TLS_GD_BOTH_P(type)						\
   ((type) == (GOT_TLS_GD | GOT_TLS_GDESC))
 #define GOT_TLS_GD_P(type)						\
@@ -1011,25 +1007,12 @@ elf_i386_check_relocs (bfd *abfd,
 	      case R_386_TLS_IE_32:
 		if (ELF32_R_TYPE (rel->r_info) == r_type)
 		  tls_type = GOT_TLS_IE_NEG;
-		else if (h
-			 && ELF32_R_TYPE (rel->r_info) == R_386_TLS_GD)
-		  /* If this is a GD->IE transition, we may use either
-		     of R_386_TLS_TPOFF and R_386_TLS_TPOFF32.  But if
-		     we may have both R_386_TLS_IE and R_386_TLS_GD,
-		     we can't share the same R_386_TLS_TPOFF since
-		     they require different offsets. So we remember
-		     it comes from R_386_TLS_GD.  */
-		  tls_type = GOT_TLS_IE | GOT_TLS_IE_GD;
 		else
+		  /* If this is a GD->IE transition, we may use either of
+		     R_386_TLS_TPOFF and R_386_TLS_TPOFF32.  */
 		  tls_type = GOT_TLS_IE;
 		break;
 	      case R_386_TLS_IE:
-		if (h)
-		  {
-		    /* We remember it comes from R_386_TLS_IE.  */
-		    tls_type = GOT_TLS_IE_POS | GOT_TLS_IE_IE;
-		    break;
-		  }
 	      case R_386_TLS_GOTIE:
 		tls_type = GOT_TLS_IE_POS; break;
 	      }
@@ -1069,8 +1052,7 @@ elf_i386_check_relocs (bfd *abfd,
 	      tls_type |= old_tls_type;
 	    /* If a TLS symbol is accessed using IE at least once,
 	       there is no point to use dynamic model for it.  */
-	    else if (old_tls_type != tls_type
-		     && old_tls_type != GOT_UNKNOWN
+	    else if (old_tls_type != tls_type && old_tls_type != GOT_UNKNOWN
 		     && (! GOT_TLS_GD_ANY_P (old_tls_type)
 			 || (tls_type & GOT_TLS_IE) == 0))
 	      {
@@ -1700,14 +1682,6 @@ allocate_dynrelocs (struct elf_link_hash
       asection *s;
       bfd_boolean dyn;
       int tls_type = elf_i386_hash_entry(h)->tls_type;
-      
-      /* If we have both R_386_TLS_IE and R_386_TLS_GD, GOT_TLS_IE_BOTH
-	 should be used.  */
-      if ((tls_type & GOT_TLS_IE_MASK)
-	  == (GOT_TLS_IE_IE | GOT_TLS_IE_GD))
-	tls_type = GOT_TLS_IE_BOTH;
-      else
-	tls_type &= GOT_TLS_MASK;
 
       /* Make sure this symbol is output as a dynamic symbol.
 	 Undefined weak syms won't yet be marked as dynamic.  */
@@ -2711,13 +2685,6 @@ elf_i386_relocate_section (bfd *output_b
 	  else if (h != NULL)
 	    {
 	      tls_type = elf_i386_hash_entry(h)->tls_type;
-	      /* If we have both R_386_TLS_IE and R_386_TLS_GD,
-		 GOT_TLS_IE_BOTH should be used.  */
-	      if ((tls_type & GOT_TLS_IE_MASK)
-		  == (GOT_TLS_IE_IE | GOT_TLS_IE_GD))
-		tls_type = GOT_TLS_IE_BOTH;
-	      else
-		tls_type &= GOT_TLS_MASK;
 	      if (!info->shared && h->dynindx == -1 && (tls_type & GOT_TLS_IE))
 		r_type = R_386_TLS_LE_32;
 	    }
@@ -3172,12 +3139,8 @@ elf_i386_relocate_section (bfd *output_b
 		 subl $foo@gottpoff(%reg), %eax
 		 into:
 		 addl $foo@gotntpoff(%reg), %eax.  */
-	      if (r_type == R_386_TLS_GOTIE)
-		{
-		  contents[roff + 6] = 0x03;
-		  if (tls_type == GOT_TLS_IE_BOTH)
-		    off += 4;
-		}
+	      if (tls_type == GOT_TLS_IE_POS)
+		contents[roff + 6] = 0x03;
 	      bfd_put_32 (output_bfd,
 			  htab->sgot->output_section->vma
 			  + htab->sgot->output_offset + off

	Jakub


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