about summary refs log tree commit diff
path: root/elf/tst-tls1.c
diff options
context:
space:
mode:
Diffstat (limited to 'elf/tst-tls1.c')
-rw-r--r--elf/tst-tls1.c158
1 files changed, 107 insertions, 51 deletions
diff --git a/elf/tst-tls1.c b/elf/tst-tls1.c
index 4d0913890c..fc426b0d3c 100644
--- a/elf/tst-tls1.c
+++ b/elf/tst-tls1.c
@@ -6,14 +6,8 @@
 
 /* XXX Until gcc gets told how to define and use thread-local
    variables we will have to resort to use asms.  */
-//asm (".tls_common foo,4,4");
-asm (".section \".tdata\", \"awT\", @progbits\n\t"
-     ".align 4\n\t"
-     ".globl foo\n"
-     "foo:\t.long 0\n\t"
-     ".globl bar\n"
-     "bar:\t.long 0\n\t"
-     ".previous");
+asm (".tls_common foo,4,4");
+asm (".tls_common bar,4,4");
 
 
 int
@@ -21,59 +15,121 @@ main (void)
 {
 #ifdef USE_TLS
   int result = 0;
-  int a, b;
+  int *ap, *bp;
 
   /* XXX Each architecture must have its own asm for now.  */
 # ifdef __i386__
-  /* Set the variable using the local exec model.  */
-  puts ("set bar to 1 (LE)");
-  asm ("movl %gs:0,%eax\n\t"
-     "subl $bar@tpoff,%eax\n\t"
-     "movl $1,(%eax)");
+#  define TLS_LE(x) \
+  ({ int *__l;								      \
+     asm ("movl %%gs:0,%0\n\t"						      \
+	  "subl $" #x "@tpoff,%0"					      \
+	  : "=r" (__l));						      \
+     __l; })
 
-#if 0
-  // XXX Doesn't work yet; no runtime relocations.
-  fputs ("get sum of foo and bar (IE)", stdout);
-  asm ("call 1f\n\t"
-       ".subsection 1\n"
-       "1:\tmovl (%%esp), %%ebx\n\t"
-       "ret\n\t"
-       ".previous\n\t"
-       "addl $_GLOBAL_OFFSET_TABLE_, %%ebx\n\t"
-       "movl %%gs:0,%%eax\n\t"
-       "movl %%eax,%%edx\n\t"
-       "addl foo@gottpoff(%%ebx),%%eax\n\t"
-       "addl bar@gottpoff(%%ebx),%%eax\n\t"
-       "movl (%%eax), %0\n\t"
-       "addl (%%edx), %0"
-       : "=a" (a), "=&b" (b));
-  printf (" = %d\n", a);
-  result |= a != 1;
-#endif
+#define TLS_IE(x) \
+  ({ int *__l, __b;							      \
+     asm ("call 1f\n\t"							      \
+	  ".subsection 1\n"						      \
+	  "1:\tmovl (%%esp), %%ebx\n\t"					      \
+	  "ret\n\t"							      \
+	  ".previous\n\t"						      \
+	  "addl $_GLOBAL_OFFSET_TABLE_, %%ebx\n\t"			      \
+	  "movl %%gs:0,%0\n\t"						      \
+	  "subl " #x "@gottpoff(%%ebx),%0"				      \
+	  : "=r" (__l), "=&b" (__b));					      \
+     __l; })
 
-  fputs ("get sum of foo and bar (GD)", stdout);
-  asm ("call 1f\n\t"
-       ".subsection 1\n"
-       "1:\tmovl (%%esp), %%ebx\n\t"
-       "ret\n\t"
-       ".previous\n\t"
-       "addl $_GLOBAL_OFFSET_TABLE_, %%ebx\n\t"
-       "leal foo@tlsgd(%%ebx),%%eax\n\t"
-       "call ___tls_get_addr@plt\n\t"
-       "nop\n\t"
-       "movl (%%eax), %%edx\n\t"
-       "leal bar@tlsgd(%%ebx),%%eax\n\t"
-       "call ___tls_get_addr@plt\n\t"
-       "nop\n\t"
-       "addl (%%eax), %%edx\n\t"
-       : "=&a" (a), "=d" (b));
-  printf (" = %d\n", b);
-  result |= b != 1;
+#define TLS_LD(x) \
+  ({ int *__l, __b;							      \
+     asm ("call 1f\n\t"							      \
+	  ".subsection 1\n"						      \
+	  "1:\tmovl (%%esp), %%ebx\n\t"					      \
+	  "ret\n\t"							      \
+	  ".previous\n\t"						      \
+	  "addl $_GLOBAL_OFFSET_TABLE_, %%ebx\n\t"			      \
+	  "leal " #x "@tlsldm(%%ebx),%%eax\n\t"				      \
+	  "call ___tls_get_addr@plt\n\t"				      \
+	  "leal " #x "@dtpoff(%%eax), %%eax"				      \
+	  : "=a" (__l), "=&b" (__b));					      \
+     __l; })
+
+#define TLS_GD(x) \
+  ({ int *__l, __b;							      \
+     asm ("call 1f\n\t"							      \
+	  ".subsection 1\n"						      \
+	  "1:\tmovl (%%esp), %%ebx\n\t"					      \
+	  "ret\n\t"							      \
+	  ".previous\n\t"						      \
+	  "addl $_GLOBAL_OFFSET_TABLE_, %%ebx\n\t"			      \
+	  "leal " #x "@tlsgd(%%ebx),%%eax\n\t"				      \
+	  "call ___tls_get_addr@plt\n\t"				      \
+	  "nop"								      \
+	  : "=a" (__l), "=&b" (__b));					      \
+     __l; })
 
 # else
 #  error "No support for this architecture so far."
 # endif
 
+  /* Set the variable using the local exec model.  */
+  puts ("set bar to 1 (LE)");
+  ap = TLS_LE (bar);
+  *ap = 1;
+
+
+  /* Get variables using initial exec model.  */
+  fputs ("get sum of foo and bar (IE)", stdout);
+  ap = TLS_IE (foo);
+  bp = TLS_IE (bar);
+  printf (" = %d\n", *ap + *bp);
+  result |= *ap + *bp != 1;
+  if (*ap != 0)
+    {
+      printf ("foo = %d\n", *ap);
+      result = 1;
+    }
+  if (*bp != 1)
+    {
+      printf ("bar = %d\n", *bp);
+      result = 1;
+    }
+
+
+  /* Get variables using local dynamic model.  */
+  fputs ("get sum of foo and bar (LD)", stdout);
+  ap = TLS_LD (foo);
+  bp = TLS_LD (bar);
+  printf (" = %d\n", *ap + *bp);
+  result |= *ap + *bp != 1;
+  if (*ap != 0)
+    {
+      printf ("foo = %d\n", *ap);
+      result = 1;
+    }
+  if (*bp != 1)
+    {
+      printf ("bar = %d\n", *bp);
+      result = 1;
+    }
+
+
+  /* Get variables using generic dynamic model.  */
+  fputs ("get sum of foo and bar (GD)", stdout);
+  ap = TLS_GD (foo);
+  bp = TLS_GD (bar);
+  printf (" = %d\n", *ap + *bp);
+  result |= *ap + *bp != 1;
+  if (*ap != 0)
+    {
+      printf ("foo = %d\n", *ap);
+      result = 1;
+    }
+  if (*bp != 1)
+    {
+      printf ("bar = %d\n", *bp);
+      result = 1;
+    }
+
   return result;
 #else
   return 0;