From 25cb6eb22999e61aa3f97009c561eb142ca846ce Mon Sep 17 00:00:00 2001 From: Roland McGrath Date: Fri, 16 Aug 2002 20:16:38 +0000 Subject: * 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. --- linuxthreads/ChangeLog | 14 +++++++++ linuxthreads/sysdeps/i386/tls.h | 54 +++++++++++++++++++++++---------- linuxthreads/sysdeps/i386/useldt.h | 61 +++++++++++++++++++------------------- 3 files changed, 83 insertions(+), 46 deletions(-) (limited to 'linuxthreads') 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 + + * 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 * 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. */ -- cgit 1.4.1