about summary refs log tree commit diff
diff options
context:
space:
mode:
authorRoland McGrath <roland@gnu.org>2002-08-16 20:16:38 +0000
committerRoland McGrath <roland@gnu.org>2002-08-16 20:16:38 +0000
commit25cb6eb22999e61aa3f97009c561eb142ca846ce (patch)
tree3656c6bf2c927073493d02be86ee95a32843787f
parentc88b47593ad1ca29959ebb6dc76c738395ae8233 (diff)
downloadglibc-25cb6eb22999e61aa3f97009c561eb142ca846ce.tar.gz
glibc-25cb6eb22999e61aa3f97009c561eb142ca846ce.tar.xz
glibc-25cb6eb22999e61aa3f97009c561eb142ca846ce.zip
* sysdeps/i386/tls.h (TLS_DO_MODIFY_LDT): Rewrite asm to use %ebx
	optimally conditional on [__PIC__].
	(TLS_DO_SET_THREAD_AREA): New macro, implement inline syscall
	without touching errno, and use latest modify_ldt-like interface.
	(TLS_SETUP_GS_SEGMENT): Use that instead of INLINE_SYSCALL.
	* sysdeps/i386/useldt.h (DO_MODIFY_LDT): Set %gs in this macro.
	(DO_SET_THREAD_AREA): New macro, uses current syscall interface with
	existing %gs value as the segment to set.
	(INIT_THREAD_SELF): Rewritten using those.  Use set_thread_area only
	under [HAVE_TLS_SUPPORT] so we can rely on the initialization done
	by the first thread's early TLS setup.
-rw-r--r--linuxthreads/ChangeLog14
-rw-r--r--linuxthreads/sysdeps/i386/tls.h54
-rw-r--r--linuxthreads/sysdeps/i386/useldt.h61
3 files changed, 83 insertions, 46 deletions
diff --git a/linuxthreads/ChangeLog b/linuxthreads/ChangeLog
index cd529e89f6..9fa83225e6 100644
--- a/linuxthreads/ChangeLog
+++ b/linuxthreads/ChangeLog
@@ -1,3 +1,17 @@
+2002-08-16  Roland McGrath  <roland@redhat.com>
+
+	* sysdeps/i386/tls.h (TLS_DO_MODIFY_LDT): Rewrite asm to use %ebx
+	optimally conditional on [__PIC__].
+	(TLS_DO_SET_THREAD_AREA): New macro, implement inline syscall
+	without touching errno, and use latest modify_ldt-like interface.
+	(TLS_SETUP_GS_SEGMENT): Use that instead of INLINE_SYSCALL.
+	* sysdeps/i386/useldt.h (DO_MODIFY_LDT): Set %gs in this macro.
+	(DO_SET_THREAD_AREA): New macro, uses current syscall interface with
+	existing %gs value as the segment to set.
+	(INIT_THREAD_SELF): Rewritten using those.  Use set_thread_area only
+	under [HAVE_TLS_SUPPORT] so we can rely on the initialization done
+	by the first thread's early TLS setup.
+
 2002-08-15  Roland McGrath  <roland@redhat.com>
 
 	* sysdeps/i386/tls.h (TLS_INIT_TP): Use statement expression and
diff --git a/linuxthreads/sysdeps/i386/tls.h b/linuxthreads/sysdeps/i386/tls.h
index 3e7e4c3302..efbaebcd85 100644
--- a/linuxthreads/sysdeps/i386/tls.h
+++ b/linuxthreads/sysdeps/i386/tls.h
@@ -88,35 +88,59 @@ typedef struct
 #  define GET_DTV(descr) \
   (((tcbhead_t *) (descr))->dtv)
 
+#  ifdef __PIC__
+#   define TLS_EBX_ARG "r"
+#   define TLS_LOAD_EBX "xchgl %3, %%ebx\n\t"
+#  else
+#   define TLS_EBX_ARG "b"
+#   define TLS_LOAD_EBX
+#  endif
+
 #  define TLS_DO_MODIFY_LDT(descr, nr)					      \
 ({									      \
   struct modify_ldt_ldt_s ldt_entry =					      \
     { nr, (unsigned long int) (descr), sizeof (struct _pthread_descr_struct), \
       1, 0, 0, 0, 0, 1, 0 };						      \
   int result;								      \
-  asm volatile (							      \
-       "pushl %%ebx\n\t"						      \
-       "movl $1, %%ebx\n\t"						      \
-       "int $0x80\n\t"							      \
-       "popl %%ebx"							      \
-       : "=a" (result)							      \
-       : "0" (__NR_modify_ldt),						      \
-         /* The extra argument with the "m" constraint is necessary	      \
-	    to let the compiler know that we are accessing LDT_ENTRY here.  */\
-         "m" (ldt_entry), "c" (&ldt_entry), "d" (sizeof (ldt_entry)));	      \
+  asm volatile (TLS_LOAD_EBX						      \
+		"int $0x80\n\t"						      \
+		TLS_LOAD_EBX						      \
+		: "=a" (result)						      \
+		: "0" (__NR_modify_ldt),				      \
+		/* The extra argument with the "m" constraint is necessary    \
+		   to let the compiler know that we are accessing LDT_ENTRY   \
+		   here.  */						      \
+		"m" (ldt_entry), TLS_EBX_ARG (1), "c" (&ldt_entry),	      \
+		"d" (sizeof (ldt_entry)));				      \
   __builtin_expect (result, 0) != 0 ? -1 : nr * 8 + 7;			      \
 })
 
+#  define TLS_DO_SET_THREAD_AREA(descr)					      \
+({									      \
+  struct modify_ldt_ldt_s ldt_entry =					      \
+    { -1, (unsigned long int) (descr), sizeof (struct _pthread_descr_struct), \
+      1, 0, 0, 0, 0, 1, 0 };						      \
+  int result;								      \
+  asm volatile (TLS_LOAD_EBX						      \
+		"int $0x80\n\t"						      \
+		TLS_LOAD_EBX						      \
+		: "=a" (result), "=m" (ldt_entry.entry_number)		      \
+		: "0" (__NR_set_thread_area),				      \
+		/* The extra argument with the "m" constraint is necessary    \
+		   to let the compiler know that we are accessing LDT_ENTRY   \
+		   here.  */						      \
+		TLS_EBX_ARG (&ldt_entry), "m" (ldt_entry));		      \
+    __builtin_expect (result, 0) == 0 ? ldt_entry.entry_number : -1;	      \
+})
+
 #  ifdef __ASSUME_SET_THREAD_AREA_SYSCALL
-#   define TLS_SETUP_GS_SEGMENT(descr) \
-  INLINE_SYSCALL (set_thread_area, 2, descr, 1)
+#   define TLS_SETUP_GS_SEGMENT(descr) TLS_DO_SET_THREAD_AREA (descr)
 #  elif defined __NR_set_thread_area
 #   define TLS_SETUP_GS_SEGMENT(descr) \
-  ({ int __seg = INLINE_SYSCALL (set_thread_area, 2, descr, 1); \
+  ({ int __seg = TLS_DO_SET_THREAD_AREA (descr); \
      __seg == -1 ? TLS_DO_MODIFY_LDT (descr, 0) : __seg; })
 #  else
-#   define TLS_SETUP_GS_SEGMENT(descr) \
-  TLS_DO_MODIFY_LDT (descr, 0)
+#   define TLS_SETUP_GS_SEGMENT(descr) TLS_DO_MODIFY_LDT ((descr), 0)
 #  endif
 
 /* Code to initially initialize the thread pointer.  This might need
diff --git a/linuxthreads/sysdeps/i386/useldt.h b/linuxthreads/sysdeps/i386/useldt.h
index 4fd226e270..49471d61fa 100644
--- a/linuxthreads/sysdeps/i386/useldt.h
+++ b/linuxthreads/sysdeps/i386/useldt.h
@@ -62,49 +62,48 @@ extern int __modify_ldt (int, struct modify_ldt_ldt_s *, size_t);
   __self;								      \
 })
 
-#define DO_MODIFY_LDT(descr, nr) \
+
+/* Initialize the thread-unique value.  Two possible ways to do it.  */
+
+#define DO_MODIFY_LDT(descr, nr)					      \
 ({									      \
   struct modify_ldt_ldt_s ldt_entry =					      \
     { nr, (unsigned long int) descr, sizeof (struct _pthread_descr_struct),   \
       1, 0, 0, 0, 0, 1, 0 };						      \
   if (__modify_ldt (1, &ldt_entry, sizeof (ldt_entry)) != 0)		      \
     abort ();								      \
-  nr * 8 + 7;								      \
+  asm ("movw %w0, %%gs" : : "q" (nr * 8 + 7));				      \
 })
 
-/* Initialize the thread-unique value.  */
-#ifdef __ASSUME_SET_THREAD_AREA_SYSCALL
-#define INIT_THREAD_SELF(descr, nr) \
-{									      \
-  int __gs = INLINE_SYSCALL (set_thread_area, 2, descr, 1);		      \
-  if (__gs == -1)							      \
-    abort ();								      \
-  __asm__ __volatile__ ("movw %w0, %%gs" : : "q" (__gs));		      \
-}
-#elif defined __NR_set_thread_area
+/* When using the new set_thread_area call, we don't need to change %gs
+   because we inherited the value set up in the main thread by TLS setup.
+   We need to extract that value and set up the same segment in this
+   thread.  */
+# define DO_SET_THREAD_AREA(descr)					      \
+({									      \
+  int __gs;								      \
+  struct modify_ldt_ldt_s ldt_entry =					      \
+    { ({ asm ("movw %%gs, %w0" : "=q" (__gs)); __gs >> 2; }),		      \
+      (unsigned long int) descr, sizeof (struct _pthread_descr_struct),	      \
+      1, 0, 0, 0, 0, 1, 0 };						      \
+  __builtin_expect (INLINE_SYSCALL (set_thread_area, 1, &ldt_entry) == 0, 1)  \
+  ? __gs : -1;	      							      \
+})
 
+#if defined __ASSUME_SET_THREAD_AREA_SYSCALL && defined HAVE_TLS_SUPPORT
+# define INIT_THREAD_SELF(descr, nr)	DO_SET_THREAD_AREA (descr)
+#elif defined __NR_set_thread_area && defined HAVE_TLS_SUPPORT
+# define INIT_THREAD_SELF(descr, nr)					      \
+({									      \
+  if (__builtin_expect (__have_no_set_thread_area, 0)			      \
+      || (DO_SET_THREAD_AREA (descr) == -1				      \
+	  && (__have_no_set_thread_area = 1)))				      \
+    DO_MODIFY_LDT (descr, nr);						      \
+})
 /* Defined in pspinlock.c.  */
 extern int __have_no_set_thread_area;
-
-#define INIT_THREAD_SELF(descr, nr) \
-{									      \
-  int __gs = -1;							      \
-  if (! __builtin_expect (__have_no_set_thread_area, 0))		      \
-    {									      \
-      if ((__gs = INLINE_SYSCALL (set_thread_area, 2, descr, 1)) == -1	      \
-	  && errno == ENOSYS)						      \
-	__have_no_set_thread_area = 1;					      \
-    }									      \
-  if (__builtin_expect (__gs == -1, 0))					      \
-    __gs = DO_MODIFY_LDT (descr, nr);					      \
-  __asm__ __volatile__ ("movw %w0, %%gs" : : "q" (__gs));		      \
-}
 #else
-#define INIT_THREAD_SELF(descr, nr) \
-{									      \
-  int __gs = DO_MODIFY_LDT (descr, nr);					      \
-  __asm__ __volatile__ ("movw %w0, %%gs" : : "q" (__gs));		      \
-}
+# define INIT_THREAD_SELF(descr, nr)	DO_MODIFY_LDT (descr, nr)
 #endif
 
 /* Free resources associated with thread descriptor.  */