about summary refs log tree commit diff
diff options
context:
space:
mode:
authorUlrich Drepper <drepper@redhat.com>2002-02-05 00:57:29 +0000
committerUlrich Drepper <drepper@redhat.com>2002-02-05 00:57:29 +0000
commit535b764df5ca722066c2db615190e6a70688c6a6 (patch)
tree06f6ba9853ac4e8f698fc1e3b0b4cb80ffd06bae
parent67ddea92542c12f2099a89dbc58a045a65bb7771 (diff)
downloadglibc-535b764df5ca722066c2db615190e6a70688c6a6.tar.gz
glibc-535b764df5ca722066c2db615190e6a70688c6a6.tar.xz
glibc-535b764df5ca722066c2db615190e6a70688c6a6.zip
Update.
	* elf/rtld.c (_dl_start_final): Allocate TLS and initialize
	thread-pointer as soon as possible.
	* sysdeps/generic/ldsodefs.h: Include <tls.h>.  Define first TLS
	elements in rtld_global.
	* sysdeps/generic/tls.h: New file.
	* elf/Makefile (distribute): Add tls.h.
	* sysdeps/i386/dl-machine.h (elf_machine_rel): Add support for TLS
	relocations.  Not complete yet.

	* resolv/resolv.h: Allow user to define __need_res_state and only
	define __res_start structure then.
	* include/resolv.h: Only declare functions if _RESOLV_H_ is defined.
-rw-r--r--ChangeLog13
-rw-r--r--elf/Makefile2
-rw-r--r--elf/rtld.c75
-rw-r--r--include/resolv.h2
-rw-r--r--linuxthreads/ChangeLog6
-rw-r--r--linuxthreads/descr.h168
-rw-r--r--linuxthreads/internals.h141
-rw-r--r--linuxthreads/sysdeps/i386/tls.h95
-rw-r--r--linuxthreads_db/ChangeLog11
-rw-r--r--linuxthreads_db/td_ta_event_getmsg.c3
-rw-r--r--linuxthreads_db/td_ta_map_id2thr.c3
-rw-r--r--linuxthreads_db/td_ta_map_lwp2thr.c3
-rw-r--r--linuxthreads_db/td_ta_thr_iter.c3
-rw-r--r--linuxthreads_db/td_ta_tsd_iter.c3
-rw-r--r--linuxthreads_db/td_thr_tsd.c3
-rw-r--r--linuxthreads_db/td_thr_validate.c3
-rw-r--r--linuxthreads_db/thread_dbP.h2
-rw-r--r--resolv/resolv.h101
-rw-r--r--sysdeps/generic/ldsodefs.h6
-rw-r--r--sysdeps/generic/tls.h22
-rw-r--r--sysdeps/i386/dl-machine.h39
-rwxr-xr-xsysdeps/i386/elf/configure6
22 files changed, 513 insertions, 197 deletions
diff --git a/ChangeLog b/ChangeLog
index f6c2bac197..4931ba52c7 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,18 @@
 2002-02-04  Ulrich Drepper  <drepper@redhat.com>
 
+	* elf/rtld.c (_dl_start_final): Allocate TLS and initialize
+	thread-pointer as soon as possible.
+	* sysdeps/generic/ldsodefs.h: Include <tls.h>.  Define first TLS
+	elements in rtld_global.
+	* sysdeps/generic/tls.h: New file.
+	* elf/Makefile (distribute): Add tls.h.
+	* sysdeps/i386/dl-machine.h (elf_machine_rel): Add support for TLS
+	relocations.  Not complete yet.
+
+	* resolv/resolv.h: Allow user to define __need_res_state and only
+	define __res_start structure then.
+	* include/resolv.h: Only declare functions if _RESOLV_H_ is defined.
+
 	* sysdeps/generic/dl-sysdep.c (_dl_sysdep_start): Move
 	dl_cpuclock_offset initialization to _dl_start_final.
 	(_dl_show_auxv): Avoid unnecessary sign extension.
diff --git a/elf/Makefile b/elf/Makefile
index 12277741c4..e84c6d15cc 100644
--- a/elf/Makefile
+++ b/elf/Makefile
@@ -67,7 +67,7 @@ distribute	:= $(rtld-routines:=.c) dynamic-link.h do-rel.h dl-machine.h \
 		   reldep6mod4.c reldep6mod3.c reldep6mod2.c reldep6mod1.c \
 		   reldep6mod0.c \
 		   unwind-dw2.c unwind-dw2-fde.c unwind.h unwind-pe.h \
-		   unwind-dw2-fde.h dwarf2.h dl-procinfo.c
+		   unwind-dw2-fde.h dwarf2.h dl-procinfo.c tls.h
 
 include ../Makeconfig
 
diff --git a/elf/rtld.c b/elf/rtld.c
index e2360e3ae1..b7439b2e7b 100644
--- a/elf/rtld.c
+++ b/elf/rtld.c
@@ -218,6 +218,16 @@ _dl_start_final (void *arg, struct link_map *bootstrap_map_p,
      which use `alloca'.  */
   ElfW(Addr) *start_addr = alloca (sizeof (ElfW(Addr)));
   extern char _begin[], _end[];
+#ifdef USE_TLS
+  ElfW(Ehdr) *ehdr;
+  ElfW(Phdr) *phdr;
+  size_t cnt;
+  size_t tlssize = 0;
+  size_t tlsimagesize = 0;
+  const void *tlsimage = NULL;
+  void *tlsblock = NULL;
+  dtv_t initdtv[2];
+#endif
 
   if (HP_TIMING_AVAIL)
     {
@@ -244,11 +254,76 @@ _dl_start_final (void *arg, struct link_map *bootstrap_map_p,
   HP_TIMING_NOW (GL(dl_cpuclock_offset));
 #endif
 
+#if USE_TLS
+  /* Get the dynamic linkers program header.  */
+  ehdr = (ElfW(Ehdr) *) bootstrap_map_p->l_addr;
+  phdr = (ElfW(Phdr) *) (bootstrap_map_p->l_addr + ehdr->e_phoff);
+  for (cnt = 0; cnt < ehdr->e_phnum; ++cnt)
+    if (phdr[cnt].p_type == PT_TLS)
+      {
+	size_t align = MAX (TLS_INIT_TCB_ALIGN,  phdr[cnt].p_align);
+
+	tlssize = phdr[cnt].p_memsz;
+	tlsimagesize = phdr[cnt].p_filesz;
+	tlsimage = (void *) (bootstrap_map_p->l_addr + phdr[cnt].p_offset);
+
+	/* We can now allocate the initial TLS block.  This can happen
+	   on the stack.  We'll get the final memory later when we
+	   know all about the various objects loaded at startup
+	   time.  */
+# if TLS_TCB_AT_TP
+	tlsblock = alloca (roundup (tlssize, TLS_INIT_TCB_ALIGN)
+			   + TLS_INIT_TCB_SIZE
+			   + align);
+# elif TLS_DTV_AT_TP
+	tlsblock = alloca (roundup (TLS_INIT_TCB_SIZE, phdr[cnt].p_align)
+			   + tlssize
+			   + align);
+# else
+	/* In case a model with a different layout for the TCB and DTV
+	   is defined add another #elif here and in the following #ifs.  */
+#  error "Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined"
+# endif
+	/* Align the TLS block.  */
+	tlsblock = (void *) (((uintptr_t) tlsblock + align - 1)
+			     & ~(align - 1));
+
+	/* Initialize the dtv.  */
+	initdtv[0].counter = 1;
+
+	/* Initialize the TLS block.  */
+# if TLS_TCB_AT_TP
+	initdtv[1].pointer = tlsblock;
+# elif TLS_DTV_AT_TP
+	GL(rtld_tlsoffset) = roundup (TLS_INIT_TCB_SIZE, phdr[cnt].p_align);
+	initdtv[1].pointer = (char *) tlsblock + GL(rtld_tlsoffset);
+# else
+#  error "Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined"
+# endif
+	memset (__mempcpy (initdtv[1].pointer, tlsimage, tlsimagesize),
+		'\0', tlssize - tlsimagesize);
+
+	/* Initialize the thread pointer.  */
+# if TLS_TCB_AT_TP
+	GL(rtld_tlsoffset) = roundup (tlssize, TLS_INIT_TCB_ALIGN);
+	TLS_INIT_TP ((char *) tlsblock + GL(rtld_tlsoffset), initdtv);
+# elif TLS_DTV_AT_TP
+	TLS_INIT_TP (tlsblock, intidtv);
+# else
+#  error "Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined"
+# endif
+
+	/* There can only be one PT_TLS entry.  */
+	break;
+      }
+#endif	/* use TLS */
+
   /* Call the OS-dependent function to set up life so we can do things like
      file access.  It will call `dl_main' (below) to do all the real work
      of the dynamic linker, and then unwind our frame and run the user
      entry point on the same stack we entered on.  */
   *start_addr =  _dl_sysdep_start (arg, &dl_main);
+
 #ifndef HP_TIMING_NONAVAIL
   if (HP_TIMING_AVAIL)
     {
diff --git a/include/resolv.h b/include/resolv.h
index fe79c16ba3..d4a531f244 100644
--- a/include/resolv.h
+++ b/include/resolv.h
@@ -10,6 +10,7 @@
 
 #include <resolv/resolv.h>
 
+#ifdef _RESOLV_H_
 /* Now define the internal interfaces.  */
 extern int __res_vinit (res_state, int);
 extern void _sethtent (int);
@@ -26,5 +27,6 @@ extern void res_send_setqhook (res_send_qhook __hook);
 extern void res_send_setrhook (res_send_rhook __hook);
 extern int res_ourserver_p (const res_state __statp,
 			    const struct sockaddr_in6 *__inp);
+#endif
 
 #endif
diff --git a/linuxthreads/ChangeLog b/linuxthreads/ChangeLog
index 6f9c93687b..f55477ea41 100644
--- a/linuxthreads/ChangeLog
+++ b/linuxthreads/ChangeLog
@@ -1,3 +1,9 @@
+2002-02-04  Ulrich Drepper  <drepper@redhat.com>
+
+	* internals.h: Move thread descriptor definition...
+	* descr.h.: ...here.  New file.
+	* sysdeps/i386/tls.h: New file.
+
 2002-02-01  H.J. Lu  <hjl@gnu.org>
 
 	* sysdeps/mips/pspinlock.c (__pthread_spin_lock): Use a
diff --git a/linuxthreads/descr.h b/linuxthreads/descr.h
new file mode 100644
index 0000000000..4cfad89dcb
--- /dev/null
+++ b/linuxthreads/descr.h
@@ -0,0 +1,168 @@
+/* Linuxthreads - a simple clone()-based implementation of Posix        */
+/* threads for Linux.                                                   */
+/* Copyright (C) 1996 Xavier Leroy (Xavier.Leroy@inria.fr)              */
+/*                                                                      */
+/* This program is free software; you can redistribute it and/or        */
+/* modify it under the terms of the GNU Library General Public License  */
+/* as published by the Free Software Foundation; either version 2       */
+/* of the License, or (at your option) any later version.               */
+/*                                                                      */
+/* This program is distributed in the hope that it will be useful,      */
+/* but WITHOUT ANY WARRANTY; without even the implied warranty of       */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the        */
+/* GNU Library General Public License for more details.                 */
+
+#ifndef _DESCR_H
+#define _DESCR_H	1
+
+#define __need_res_state
+#include <resolv.h>
+#include <sched.h>
+#include <setjmp.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <hp-timing.h>
+#include <bits/libc-tsd.h> /* for _LIBC_TSD_KEY_N */
+
+
+/* The type of thread descriptors */
+typedef struct _pthread_descr_struct *pthread_descr;
+
+
+/* Some more includes.  */
+#include <pt-machine.h>
+#include <linuxthreads_db/thread_dbP.h>
+
+
+/* Arguments passed to thread creation routine */
+struct pthread_start_args {
+  void *(*start_routine)(void *); /* function to run */
+  void *arg;                      /* its argument */
+  sigset_t mask;                  /* initial signal mask for thread */
+  int schedpolicy;                /* initial scheduling policy (if any) */
+  struct sched_param schedparam;  /* initial scheduling parameters (if any) */
+};
+
+
+/* Callback interface for removing the thread from waiting on an
+   object if it is cancelled while waiting or about to wait.
+   This hold a pointer to the object, and a pointer to a function
+   which ``extricates'' the thread from its enqueued state.
+   The function takes two arguments: pointer to the wait object,
+   and a pointer to the thread. It returns 1 if an extrication
+   actually occured, and hence the thread must also be signalled.
+   It returns 0 if the thread had already been extricated. */
+typedef struct _pthread_extricate_struct {
+    void *pu_object;
+    int (*pu_extricate_func)(void *, pthread_descr);
+} pthread_extricate_if;
+
+
+/* Atomic counter made possible by compare_and_swap */
+struct pthread_atomic {
+  long p_count;
+  int p_spinlock;
+};
+
+
+/* Context info for read write locks. The pthread_rwlock_info structure
+   is information about a lock that has been read-locked by the thread
+   in whose list this structure appears. The pthread_rwlock_context
+   is embedded in the thread context and contains a pointer to the
+   head of the list of lock info structures, as well as a count of
+   read locks that are untracked, because no info structure could be
+   allocated for them. */
+struct _pthread_rwlock_t;
+typedef struct _pthread_rwlock_info {
+  struct _pthread_rwlock_info *pr_next;
+  struct _pthread_rwlock_t *pr_lock;
+  int pr_lock_count;
+} pthread_readlock_info;
+
+
+/* We keep thread specific data in a special data structure, a two-level
+   array.  The top-level array contains pointers to dynamically allocated
+   arrays of a certain number of data pointers.  So we can implement a
+   sparse array.  Each dynamic second-level array has
+	PTHREAD_KEY_2NDLEVEL_SIZE
+   entries.  This value shouldn't be too large.  */
+#define PTHREAD_KEY_2NDLEVEL_SIZE	32
+
+/* We need to address PTHREAD_KEYS_MAX key with PTHREAD_KEY_2NDLEVEL_SIZE
+   keys in each subarray.  */
+#define PTHREAD_KEY_1STLEVEL_SIZE \
+  ((PTHREAD_KEYS_MAX + PTHREAD_KEY_2NDLEVEL_SIZE - 1) \
+   / PTHREAD_KEY_2NDLEVEL_SIZE)
+
+
+union dtv;
+
+
+struct _pthread_descr_struct {
+  /* XXX Remove this union for IA-64 style TLS module */
+  union {
+    struct {
+      pthread_descr self;	/* Pointer to this structure */
+      union dtv *dtvp;
+    } data;
+    void *__padding[16];
+  } p_header;
+  pthread_descr p_nextlive, p_prevlive;
+                                /* Double chaining of active threads */
+  pthread_descr p_nextwaiting;  /* Next element in the queue holding the thr */
+  pthread_descr p_nextlock;	/* can be on a queue and waiting on a lock */
+  pthread_t p_tid;              /* Thread identifier */
+  int p_pid;                    /* PID of Unix process */
+  int p_priority;               /* Thread priority (== 0 if not realtime) */
+  struct _pthread_fastlock * p_lock; /* Spinlock for synchronized accesses */
+  int p_signal;                 /* last signal received */
+  sigjmp_buf * p_signal_jmp;    /* where to siglongjmp on a signal or NULL */
+  sigjmp_buf * p_cancel_jmp;    /* where to siglongjmp on a cancel or NULL */
+  char p_terminated;            /* true if terminated e.g. by pthread_exit */
+  char p_detached;              /* true if detached */
+  char p_exited;                /* true if the assoc. process terminated */
+  void * p_retval;              /* placeholder for return value */
+  int p_retcode;                /* placeholder for return code */
+  pthread_descr p_joining;      /* thread joining on that thread or NULL */
+  struct _pthread_cleanup_buffer * p_cleanup; /* cleanup functions */
+  char p_cancelstate;           /* cancellation state */
+  char p_canceltype;            /* cancellation type (deferred/async) */
+  char p_canceled;              /* cancellation request pending */
+  int * p_errnop;               /* pointer to used errno variable */
+  int p_errno;                  /* error returned by last system call */
+  int * p_h_errnop;             /* pointer to used h_errno variable */
+  int p_h_errno;                /* error returned by last netdb function */
+  char * p_in_sighandler;       /* stack address of sighandler, or NULL */
+  char p_sigwaiting;            /* true if a sigwait() is in progress */
+  struct pthread_start_args p_start_args; /* arguments for thread creation */
+  void ** p_specific[PTHREAD_KEY_1STLEVEL_SIZE]; /* thread-specific data */
+  void * p_libc_specific[_LIBC_TSD_KEY_N]; /* thread-specific data for libc */
+  int p_userstack;		/* nonzero if the user provided the stack */
+  void *p_guardaddr;		/* address of guard area or NULL */
+  size_t p_guardsize;		/* size of guard area */
+  int p_nr;                     /* Index of descriptor in __pthread_handles */
+  int p_report_events;		/* Nonzero if events must be reported.  */
+  td_eventbuf_t p_eventbuf;     /* Data for event.  */
+  struct pthread_atomic p_resume_count; /* number of times restart() was
+					   called on thread */
+  char p_woken_by_cancel;       /* cancellation performed wakeup */
+  char p_condvar_avail;		/* flag if conditional variable became avail */
+  char p_sem_avail;             /* flag if semaphore became available */
+  pthread_extricate_if *p_extricate; /* See above */
+  pthread_readlock_info *p_readlock_list;  /* List of readlock info structs */
+  pthread_readlock_info *p_readlock_free;  /* Free list of structs */
+  int p_untracked_readlock_count;	/* Readlocks not tracked by list */
+  struct __res_state *p_resp;	/* Pointer to resolver state */
+  struct __res_state p_res;	/* per-thread resolver state */
+  int p_inheritsched;           /* copied from the thread attribute */
+#if HP_TIMING_AVAIL
+  hp_timing_t p_cpuclock_offset; /* Initial CPU clock for thread.  */
+#endif
+  /* New elements must be added at the end.  */
+} __attribute__ ((aligned(32))); /* We need to align the structure so that
+				    doubles are aligned properly.  This is 8
+				    bytes on MIPS and 16 bytes on MIPS64.
+				    32 bytes might give better cache
+				    utilization.  */
+
+#endif	/* descr.h */
diff --git a/linuxthreads/internals.h b/linuxthreads/internals.h
index 8297c781c8..e1768b4a1f 100644
--- a/linuxthreads/internals.h
+++ b/linuxthreads/internals.h
@@ -20,21 +20,15 @@
 /* Includes */
 
 #include <limits.h>
-#include <resolv.h>
-#include <setjmp.h>
-#include <signal.h>
 #include <unistd.h>
 #include <stackinfo.h>
-#include <sys/types.h>
-#include <bits/libc-tsd.h> /* for _LIBC_TSD_KEY_N */
+
+#include "descr.h"
 
 extern long int testandset (int *spinlock);
 extern int __compare_and_swap (long int *p, long int oldval, long int newval);
 
-#include "pt-machine.h"
 #include "semaphore.h"
-#include "../linuxthreads_db/thread_dbP.h"
-#include <hp-timing.h>
 
 #ifndef THREAD_GETMEM
 # define THREAD_GETMEM(descr, member) descr->member
@@ -49,31 +43,6 @@ extern int __compare_and_swap (long int *p, long int oldval, long int newval);
 # define THREAD_SETMEM_NC(descr, member, value) descr->member = (value)
 #endif
 
-/* Arguments passed to thread creation routine */
-
-struct pthread_start_args {
-  void * (*start_routine)(void *); /* function to run */
-  void * arg;                   /* its argument */
-  sigset_t mask;                /* initial signal mask for thread */
-  int schedpolicy;              /* initial scheduling policy (if any) */
-  struct sched_param schedparam; /* initial scheduling parameters (if any) */
-};
-
-
-/* We keep thread specific data in a special data structure, a two-level
-   array.  The top-level array contains pointers to dynamically allocated
-   arrays of a certain number of data pointers.  So we can implement a
-   sparse array.  Each dynamic second-level array has
-	PTHREAD_KEY_2NDLEVEL_SIZE
-   entries.  This value shouldn't be too large.  */
-#define PTHREAD_KEY_2NDLEVEL_SIZE	32
-
-/* We need to address PTHREAD_KEYS_MAX key with PTHREAD_KEY_2NDLEVEL_SIZE
-   keys in each subarray.  */
-#define PTHREAD_KEY_1STLEVEL_SIZE \
-  ((PTHREAD_KEYS_MAX + PTHREAD_KEY_2NDLEVEL_SIZE - 1) \
-   / PTHREAD_KEY_2NDLEVEL_SIZE)
-
 typedef void (*destr_function)(void *);
 
 struct pthread_key_struct {
@@ -85,112 +54,6 @@ struct pthread_key_struct {
 #define PTHREAD_START_ARGS_INITIALIZER(fct) \
   { (void *(*) (void *)) fct, NULL, {{0, }}, 0, { 0 } }
 
-/* The type of thread descriptors */
-
-typedef struct _pthread_descr_struct * pthread_descr;
-
-/* Callback interface for removing the thread from waiting on an
-   object if it is cancelled while waiting or about to wait.
-   This hold a pointer to the object, and a pointer to a function
-   which ``extricates'' the thread from its enqueued state.
-   The function takes two arguments: pointer to the wait object,
-   and a pointer to the thread. It returns 1 if an extrication
-   actually occured, and hence the thread must also be signalled.
-   It returns 0 if the thread had already been extricated. */
-
-typedef struct _pthread_extricate_struct {
-    void *pu_object;
-    int (*pu_extricate_func)(void *, pthread_descr);
-} pthread_extricate_if;
-
-/* Atomic counter made possible by compare_and_swap */
-
-struct pthread_atomic {
-  long p_count;
-  int p_spinlock;
-};
-
-/* Context info for read write locks. The pthread_rwlock_info structure
-   is information about a lock that has been read-locked by the thread
-   in whose list this structure appears. The pthread_rwlock_context
-   is embedded in the thread context and contains a pointer to the
-   head of the list of lock info structures, as well as a count of
-   read locks that are untracked, because no info structure could be
-   allocated for them. */
-
-struct _pthread_rwlock_t;
-
-typedef struct _pthread_rwlock_info {
-  struct _pthread_rwlock_info *pr_next;
-  struct _pthread_rwlock_t *pr_lock;
-  int pr_lock_count;
-} pthread_readlock_info;
-
-struct _pthread_descr_struct {
-  union {
-    struct {
-      pthread_descr self;	/* Pointer to this structure */
-    } data;
-    void *__padding[16];
-  } p_header;
-  pthread_descr p_nextlive, p_prevlive;
-                                /* Double chaining of active threads */
-  pthread_descr p_nextwaiting;  /* Next element in the queue holding the thr */
-  pthread_descr p_nextlock;	/* can be on a queue and waiting on a lock */
-  pthread_t p_tid;              /* Thread identifier */
-  int p_pid;                    /* PID of Unix process */
-  int p_priority;               /* Thread priority (== 0 if not realtime) */
-  struct _pthread_fastlock * p_lock; /* Spinlock for synchronized accesses */
-  int p_signal;                 /* last signal received */
-  sigjmp_buf * p_signal_jmp;    /* where to siglongjmp on a signal or NULL */
-  sigjmp_buf * p_cancel_jmp;    /* where to siglongjmp on a cancel or NULL */
-  char p_terminated;            /* true if terminated e.g. by pthread_exit */
-  char p_detached;              /* true if detached */
-  char p_exited;                /* true if the assoc. process terminated */
-  void * p_retval;              /* placeholder for return value */
-  int p_retcode;                /* placeholder for return code */
-  pthread_descr p_joining;      /* thread joining on that thread or NULL */
-  struct _pthread_cleanup_buffer * p_cleanup; /* cleanup functions */
-  char p_cancelstate;           /* cancellation state */
-  char p_canceltype;            /* cancellation type (deferred/async) */
-  char p_canceled;              /* cancellation request pending */
-  int * p_errnop;               /* pointer to used errno variable */
-  int p_errno;                  /* error returned by last system call */
-  int * p_h_errnop;             /* pointer to used h_errno variable */
-  int p_h_errno;                /* error returned by last netdb function */
-  char * p_in_sighandler;       /* stack address of sighandler, or NULL */
-  char p_sigwaiting;            /* true if a sigwait() is in progress */
-  struct pthread_start_args p_start_args; /* arguments for thread creation */
-  void ** p_specific[PTHREAD_KEY_1STLEVEL_SIZE]; /* thread-specific data */
-  void * p_libc_specific[_LIBC_TSD_KEY_N]; /* thread-specific data for libc */
-  int p_userstack;		/* nonzero if the user provided the stack */
-  void *p_guardaddr;		/* address of guard area or NULL */
-  size_t p_guardsize;		/* size of guard area */
-  int p_nr;                     /* Index of descriptor in __pthread_handles */
-  int p_report_events;		/* Nonzero if events must be reported.  */
-  td_eventbuf_t p_eventbuf;     /* Data for event.  */
-  struct pthread_atomic p_resume_count; /* number of times restart() was
-					   called on thread */
-  char p_woken_by_cancel;       /* cancellation performed wakeup */
-  char p_condvar_avail;		/* flag if conditional variable became avail */
-  char p_sem_avail;             /* flag if semaphore became available */
-  pthread_extricate_if *p_extricate; /* See above */
-  pthread_readlock_info *p_readlock_list;  /* List of readlock info structs */
-  pthread_readlock_info *p_readlock_free;  /* Free list of structs */
-  int p_untracked_readlock_count;	/* Readlocks not tracked by list */
-  struct __res_state *p_resp;	/* Pointer to resolver state */
-  struct __res_state p_res;	/* per-thread resolver state */
-  int p_inheritsched;           /* copied from the thread attribute */
-#if HP_TIMING_AVAIL
-  hp_timing_t p_cpuclock_offset; /* Initial CPU clock for thread.  */
-#endif
-  /* New elements must be added at the end.  */
-} __attribute__ ((aligned(32))); /* We need to align the structure so that
-				    doubles are aligned properly.  This is 8
-				    bytes on MIPS and 16 bytes on MIPS64.
-				    32 bytes might give better cache
-				    utilization.  */
-
 
 /* The type of thread handles. */
 
diff --git a/linuxthreads/sysdeps/i386/tls.h b/linuxthreads/sysdeps/i386/tls.h
new file mode 100644
index 0000000000..17f6e0ae45
--- /dev/null
+++ b/linuxthreads/sysdeps/i386/tls.h
@@ -0,0 +1,95 @@
+/* Definition for thread-local data handling.  linuxthreads/i386 version.
+   Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#ifndef _TLS_H
+#define _TLS_H
+
+/* Type for the dtv.  */
+typedef union dtv
+{
+  size_t counter;
+  void *pointer;
+} dtv_t;
+
+
+typedef struct
+{
+  void *tcb;
+  dtv_t *dtv;
+} tcbhead_t;
+
+
+/* Get the thread descriptor definition.  */
+#include <linuxthreads/descr.h>
+
+
+/* We can support TLS only if the floating-stack support is available.  */
+#if FLOATING_STACKS && defined HAVE_TLS_SUPPORT
+
+/* Get system call information.  */
+# include <sysdep.h>
+
+/* Signal that TLS support is available.  */
+# define USE_TLS	1
+
+/* This is the size of the initial TCB.  */
+# define TLS_INIT_TCB_SIZE sizeof (tcbhead_t)
+
+/* Alignment requirements for the initial TCB.  */
+# define TLS_INIT_TCB_ALIGN __alignof__ (tcbhead_t)
+
+/* This is the size of the TCB.  */
+# define TLS_TCB_SIZE sizeof (struct _pthread_descr_struct)
+
+/* Alignment requirements for the TCB.  */
+# define TLS_TCB_ALIGN __alignof__ (struct _pthread_descr_struct)
+
+/* The TCB can have any size and the memory following the address the
+   thread pointer points to is unspecified.  Allocate the TCB there.  */
+# define TLS_TCB_AT_TP	1
+
+/* Code to initially initialize the thread pointer.  This might need
+   special attention since 'errno' is not yet available and if the
+   operation can cause a failure 'errno' must not be touched.  */
+# define TLS_INIT_TP(descr, dtvp) \
+  do {									      \
+    void *_descr = (descr);						      \
+    struct modify_ldt_ldt_s ldt_entry =					      \
+      { 0, (unsigned long int) _descr, 1048576, 1, 0, 0, 1, 0, 1, 0 };	      \
+    int result;								      \
+    tcbhead_t *head = _descr;						      \
+									      \
+    head->tcb = _descr;							      \
+    head->dtv = dtvp;							      \
+									      \
+    asm ("pushl %%ebx\n\t"						      \
+	 "movl $1, %%ebx\n\t"						      \
+	 "int $0x80\n\t"						      \
+	 "popl %%ebx"							      \
+	 : "=a" (result)						      \
+	 : "0" (__NR_modify_ldt), "d" (sizeof (ldt_entry)), "c" (&ldt_entry));\
+									      \
+    if (__builtin_expect (result, 0) != 0)				      \
+      /* Nothing else we can do.  */					      \
+      asm ("hlt");							      \
+  } while (0)
+
+#endif
+
+#endif	/* tls.h */
diff --git a/linuxthreads_db/ChangeLog b/linuxthreads_db/ChangeLog
index 17a391add8..d4cf2aaeb7 100644
--- a/linuxthreads_db/ChangeLog
+++ b/linuxthreads_db/ChangeLog
@@ -1,3 +1,14 @@
+2002-02-04  Ulrich Drepper  <drepper@redhat.com>
+
+	* thread_dbP.h: Include descr.h instead of internals.h.
+	* td_ta_event_getmsg.c: Also include <linuxthreads/internals.h>.
+	* td_ta_map_id2thr.c: Likewise.
+	* td_ta_map_lwp2thr.c: Likewise.
+	* td_ta_thr_iter.c: Likewise.
+	* td_ta_tsd_iter.c: Likewise.
+	* td_thr_tsd.c: Likewise.
+	* td_thr_validate.c: Likewise.
+
 2001-12-28  Andreas Jaeger  <aj@suse.de>
 
 	* td_init.c (td_init): Don't use __FUNCTION__ as literal.
diff --git a/linuxthreads_db/td_ta_event_getmsg.c b/linuxthreads_db/td_ta_event_getmsg.c
index 31ac80b69e..c3a4492a12 100644
--- a/linuxthreads_db/td_ta_event_getmsg.c
+++ b/linuxthreads_db/td_ta_event_getmsg.c
@@ -1,5 +1,5 @@
 /* Retrieve event.
-   Copyright (C) 1999, 2001 Free Software Foundation, Inc.
+   Copyright (C) 1999, 2001, 2002 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Ulrich Drepper <drepper@cygnus.com>, 1999.
 
@@ -22,6 +22,7 @@
 #include <string.h>
 
 #include "thread_dbP.h"
+#include <linuxthreads/internals.h>
 
 
 td_err_e
diff --git a/linuxthreads_db/td_ta_map_id2thr.c b/linuxthreads_db/td_ta_map_id2thr.c
index 184f2de2e1..e6be74ff19 100644
--- a/linuxthreads_db/td_ta_map_id2thr.c
+++ b/linuxthreads_db/td_ta_map_id2thr.c
@@ -1,5 +1,5 @@
 /* Map thread ID to thread handle.
-   Copyright (C) 1999, 2001 Free Software Foundation, Inc.
+   Copyright (C) 1999, 2001, 2002 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Ulrich Drepper <drepper@cygnus.com>, 1999.
 
@@ -19,6 +19,7 @@
    02111-1307 USA.  */
 
 #include "thread_dbP.h"
+#include <linuxthreads/internals.h>
 
 
 td_err_e
diff --git a/linuxthreads_db/td_ta_map_lwp2thr.c b/linuxthreads_db/td_ta_map_lwp2thr.c
index e7addf9cc7..1fc614cc21 100644
--- a/linuxthreads_db/td_ta_map_lwp2thr.c
+++ b/linuxthreads_db/td_ta_map_lwp2thr.c
@@ -1,5 +1,5 @@
 /* Which thread is running on an lwp?
-   Copyright (C) 1999, 2001 Free Software Foundation, Inc.
+   Copyright (C) 1999, 2001, 2002 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Ulrich Drepper <drepper@cygnus.com>, 1999.
 
@@ -19,6 +19,7 @@
    02111-1307 USA.  */
 
 #include "thread_dbP.h"
+#include <linuxthreads/internals.h>
 
 
 td_err_e
diff --git a/linuxthreads_db/td_ta_thr_iter.c b/linuxthreads_db/td_ta_thr_iter.c
index 80ee539297..7d7085870f 100644
--- a/linuxthreads_db/td_ta_thr_iter.c
+++ b/linuxthreads_db/td_ta_thr_iter.c
@@ -1,5 +1,5 @@
 /* Iterate over a process's threads.
-   Copyright (C) 1999, 2000, 2001 Free Software Foundation, Inc.
+   Copyright (C) 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Ulrich Drepper <drepper@cygnus.com>, 1999.
 
@@ -19,6 +19,7 @@
    02111-1307 USA.  */
 
 #include "thread_dbP.h"
+#include <linuxthreads/internals.h>
 #include <alloca.h>
 
 static int
diff --git a/linuxthreads_db/td_ta_tsd_iter.c b/linuxthreads_db/td_ta_tsd_iter.c
index 4dbc8dd647..2eb41f6a15 100644
--- a/linuxthreads_db/td_ta_tsd_iter.c
+++ b/linuxthreads_db/td_ta_tsd_iter.c
@@ -1,5 +1,5 @@
 /* Iterate over a process's thread-specific data.
-   Copyright (C) 1999, 2000, 2001 Free Software Foundation, Inc.
+   Copyright (C) 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Ulrich Drepper <drepper@cygnus.com>, 1999.
 
@@ -19,6 +19,7 @@
    02111-1307 USA.  */
 
 #include "thread_dbP.h"
+#include <linuxthreads/internals.h>
 #include <alloca.h>
 
 td_err_e
diff --git a/linuxthreads_db/td_thr_tsd.c b/linuxthreads_db/td_thr_tsd.c
index 0dd37f8f2b..aa362fe68a 100644
--- a/linuxthreads_db/td_thr_tsd.c
+++ b/linuxthreads_db/td_thr_tsd.c
@@ -1,5 +1,5 @@
 /* Get a thread-specific data pointer for a thread.
-   Copyright (C) 1999, 2001 Free Software Foundation, Inc.
+   Copyright (C) 1999, 2001, 2002 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Ulrich Drepper <drepper@cygnus.com>, 1999.
 
@@ -19,6 +19,7 @@
    02111-1307 USA.  */
 
 #include "thread_dbP.h"
+#include <linuxthreads/internals.h>
 
 
 td_err_e
diff --git a/linuxthreads_db/td_thr_validate.c b/linuxthreads_db/td_thr_validate.c
index 8821f0e846..fcce270f29 100644
--- a/linuxthreads_db/td_thr_validate.c
+++ b/linuxthreads_db/td_thr_validate.c
@@ -1,5 +1,5 @@
 /* Validate a thread handle.
-   Copyright (C) 1999, 2001 Free Software Foundation, Inc.
+   Copyright (C) 1999, 2001, 2002 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Ulrich Drepper <drepper@cygnus.com>, 1999.
 
@@ -19,6 +19,7 @@
    02111-1307 USA.  */
 
 #include "thread_dbP.h"
+#include <linuxthreads/internals.h>
 
 
 td_err_e
diff --git a/linuxthreads_db/thread_dbP.h b/linuxthreads_db/thread_dbP.h
index 8e87bae52d..5d88a81528 100644
--- a/linuxthreads_db/thread_dbP.h
+++ b/linuxthreads_db/thread_dbP.h
@@ -5,7 +5,7 @@
 #include <string.h>
 #include "proc_service.h"
 #include "thread_db.h"
-#include "../linuxthreads/internals.h"
+#include "../linuxthreads/descr.h"
 
 
 /* Indeces for the symbol names.  */
diff --git a/resolv/resolv.h b/resolv/resolv.h
index bb8c782939..238ea59d65 100644
--- a/resolv/resolv.h
+++ b/resolv/resolv.h
@@ -50,39 +50,24 @@
  */
 
 #ifndef _RESOLV_H_
-#define	_RESOLV_H_
+#ifndef __need_res_state
+# define _RESOLV_H_
 
-#include <sys/param.h>
-#if (!defined(BSD)) || (BSD < 199306)
-# include <sys/bitypes.h>
-#else
-# include <sys/types.h>
+# include <sys/param.h>
+# if (!defined(BSD)) || (BSD < 199306)
+#  include <sys/bitypes.h>
+# else
+#  include <sys/types.h>
+# endif
+# include <sys/cdefs.h>
+# include <stdio.h>
+# include <arpa/nameser.h>
 #endif
-#include <sys/cdefs.h>
-#include <stdio.h>
 
 #include <netinet/in.h>
-#include <arpa/nameser.h>
-
-/*
- * Revision information.  This is the release date in YYYYMMDD format.
- * It can change every day so the right thing to do with it is use it
- * in preprocessor commands such as "#if (__RES > 19931104)".  Do not
- * compare for equality; rather, use it to determine whether your resolver
- * is new enough to contain a certain feature.
- */
 
-#define	__RES	19991006
-
-/*
- * Resolver configuration file.
- * Normally not present, but may contain the address of the
- * inital name server(s) to query and the domain search list.
- */
-
-#ifndef _PATH_RESCONF
-#define _PATH_RESCONF        "/etc/resolv.conf"
-#endif
+#ifndef __res_state_defined
+# define __res_state_defined
 
 typedef enum { res_goahead, res_nextns, res_modified, res_done, res_error }
 	res_sendhookact;
@@ -101,27 +86,21 @@ typedef res_sendhookact (*res_send_rhook) (const struct sockaddr_in *ns,
 					   int anssiz,
 					   int *resplen);
 
-struct res_sym {
-	int	number;		/* Identifying number, like T_MX */
-	char *	name;		/* Its symbolic name, like "MX" */
-	char *	humanname;	/* Its fun name, like "mail exchanger" */
-};
-
 /*
  * Global defines and variables for resolver stub.
  */
-#define	MAXNS			3	/* max # name servers we'll track */
-#define	MAXDFLSRCH		3	/* # default domain levels to try */
-#define	MAXDNSRCH		6	/* max # domains in search path */
-#define	LOCALDOMAINPARTS	2	/* min levels in name that is "local" */
+# define MAXNS			3	/* max # name servers we'll track */
+# define MAXDFLSRCH		3	/* # default domain levels to try */
+# define MAXDNSRCH		6	/* max # domains in search path */
+# define LOCALDOMAINPARTS	2	/* min levels in name that is "local" */
 
-#define	RES_TIMEOUT		5	/* min. seconds between retries */
-#define	MAXRESOLVSORT		10	/* number of net to sort on */
-#define	RES_MAXNDOTS		15	/* should reflect bit field size */
-#define	RES_MAXRETRANS		30	/* only for resolv.conf/RES_OPTIONS */
-#define	RES_MAXRETRY		5	/* only for resolv.conf/RES_OPTIONS */
-#define	RES_DFLRETRY		2	/* Default #/tries. */
-#define	RES_MAXTIME		65535	/* Infinity, in milliseconds. */
+# define RES_TIMEOUT		5	/* min. seconds between retries */
+# define MAXRESOLVSORT		10	/* number of net to sort on */
+# define RES_MAXNDOTS		15	/* should reflect bit field size */
+# define RES_MAXRETRANS		30	/* only for resolv.conf/RES_OPTIONS */
+# define RES_MAXRETRY		5	/* only for resolv.conf/RES_OPTIONS */
+# define RES_DFLRETRY		2	/* Default #/tries. */
+# define RES_MAXTIME		65535	/* Infinity, in milliseconds. */
 
 struct __res_state {
 	int	retrans;	 	/* retransmition time interval */
@@ -130,7 +109,7 @@ struct __res_state {
 	int	nscount;		/* number of name servers */
 	struct sockaddr_in
 		nsaddr_list[MAXNS];	/* address of name server */
-#define	nsaddr	nsaddr_list[0]		/* for backward compatibility */
+# define nsaddr	nsaddr_list[0]		/* for backward compatibility */
 	u_short	id;			/* current message id */
 	char	*dnsrch[MAXDNSRCH+1];	/* components of domain to search */
 	char	defdname[256];		/* default domain (deprecated) */
@@ -161,6 +140,35 @@ struct __res_state {
 };
 
 typedef struct __res_state *res_state;
+# undef __need_res_state
+#endif
+
+#ifdef _RESOLV_H_
+/*
+ * Revision information.  This is the release date in YYYYMMDD format.
+ * It can change every day so the right thing to do with it is use it
+ * in preprocessor commands such as "#if (__RES > 19931104)".  Do not
+ * compare for equality; rather, use it to determine whether your resolver
+ * is new enough to contain a certain feature.
+ */
+
+#define	__RES	19991006
+
+/*
+ * Resolver configuration file.
+ * Normally not present, but may contain the address of the
+ * inital name server(s) to query and the domain search list.
+ */
+
+#ifndef _PATH_RESCONF
+#define _PATH_RESCONF        "/etc/resolv.conf"
+#endif
+
+struct res_sym {
+	int	number;		/* Identifying number, like T_MX */
+	char *	name;		/* Its symbolic name, like "MX" */
+	char *	humanname;	/* Its fun name, like "mail exchanger" */
+};
 
 /*
  * Resolver flags (used to be discrete per-module statics ints).
@@ -374,5 +382,6 @@ int		res_nmkquery __P((res_state,
 int		res_nsend __P((res_state, const u_char *, int, u_char *, int));
 void		res_nclose __P((res_state));
 __END_DECLS
+#endif
 
 #endif /* !_RESOLV_H_ */
diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h
index 0f63799524..08785a818e 100644
--- a/sysdeps/generic/ldsodefs.h
+++ b/sysdeps/generic/ldsodefs.h
@@ -35,6 +35,7 @@
 #include <dl-lookupcfg.h>
 #include <bits/libc-lock.h>
 #include <hp-timing.h>
+#include <tls.h>
 
 __BEGIN_DECLS
 
@@ -286,6 +287,11 @@ struct rtld_global
   EXTERN hp_timing_t _dl_hp_timing_overhead;
 #endif
 
+#ifdef USE_TLS
+  /* Offset of the TLS block for ld.so from the thread-pointer.  */
+  EXTERN size_t _rtld_tlsoffset;
+#endif
+
   /* Name of the shared object to be profiled (if any).  */
   EXTERN const char *_dl_profile;
   /* Map of shared object to be profiled.  */
diff --git a/sysdeps/generic/tls.h b/sysdeps/generic/tls.h
new file mode 100644
index 0000000000..3820162ae8
--- /dev/null
+++ b/sysdeps/generic/tls.h
@@ -0,0 +1,22 @@
+/* Definition for thread-local data handling.  Generic version.
+   Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+/* By default no TLS support is available.  This is signaled by the
+   absence of the symbol USE_TLS.  */
+#undef USE_TLS
diff --git a/sysdeps/i386/dl-machine.h b/sysdeps/i386/dl-machine.h
index 69a0c5550e..f791fa3ffa 100644
--- a/sysdeps/i386/dl-machine.h
+++ b/sysdeps/i386/dl-machine.h
@@ -342,7 +342,7 @@ elf_machine_rel (struct link_map *map, const Elf32_Rel *reloc,
   else
 #endif
     {
-#ifdef RTLD_BOOTSTRAP
+#if defined RTLD_BOOTSTRAP && !defined USE_TLS
       Elf32_Addr value;
 
       assert (r_type == R_386_GLOB_DAT || r_type == R_386_JMP_SLOT);
@@ -352,7 +352,9 @@ elf_machine_rel (struct link_map *map, const Elf32_Rel *reloc,
 #else
       const Elf32_Sym *const refsym = sym;
       Elf32_Addr value = RESOLVE (&sym, version, r_type);
+# ifndef RTLD_BOOTSTRAP
       if (sym)
+# endif
 	value += sym->st_value;
 
       switch (r_type)
@@ -361,6 +363,40 @@ elf_machine_rel (struct link_map *map, const Elf32_Rel *reloc,
 	case R_386_JMP_SLOT:
 	  *reloc_addr = value;
 	  break;
+
+	  /* XXX Remove TLS relocations which are not needed.  */
+
+	case R_386_TLS_DTPMOD32:
+# ifdef RTLD_BOOTSTRAP
+	  /* During startup the dynamic linker is always the module
+	     with index 1.
+	     XXX If this relocation is necessary move before RESOLVE
+	     call.  */
+	  *reloc_addr = 1;
+# else
+	  /* XXX Implement.  RESOLVE must return the map from which we
+	     get the module ID.  */
+	  _exit (99);
+# endif
+	  break;
+	case R_386_TLS_DTPOFF32:
+# ifndef RTLD_BOOTSTRAP
+	  /* During relocation all TLS symbols are defined and used.
+	     Therefore the offset is already correct.  */
+	  *reloc_addr = sym->st_value;
+# endif
+	  break;
+	case R_386_TLS_TPOFF32:
+	  /* The offset is positive, backward from the thread pointer.  */
+# ifdef RTLD_BOOTSTRAP
+	  *reloc_addr = GL(rtld_tlsoffset) - sym->st_value;
+# else
+	  /* XXX Implement.  */
+	  _exit (98);
+# endif
+	  break;
+
+# ifndef RTLD_BOOTSTRAP
 	case R_386_32:
 	  *reloc_addr += value;
 	  break;
@@ -390,6 +426,7 @@ elf_machine_rel (struct link_map *map, const Elf32_Rel *reloc,
 	default:
 	  _dl_reloc_bad_type (map, r_type, 0);
 	  break;
+# endif
 	}
 #endif
     }
diff --git a/sysdeps/i386/elf/configure b/sysdeps/i386/elf/configure
index e12bf4a164..ca7f567bcb 100755
--- a/sysdeps/i386/elf/configure
+++ b/sysdeps/i386/elf/configure
@@ -9,16 +9,18 @@ if eval "test \"`echo '$''{'libc_cv_386_tls'+set}'`\" = set"; then
 else
   cat > conftest.s <<\EOF
 	.section ".tdata", "awT", @progbits
+	.globl foo
 foo:	.long	1
 	.section ".tbss", "awT", @nobits
-	.comm	bar,4,4
+	.globl bar
+bar:	.skip	4
 	.text
 baz:	leal	bar@TLSLDM(%ebx), %eax
 	leal	bar@DTPOFF(%eax), %edx
 	subl	foo@GOTTPOFF(%edx), %eax
 	subl	$bar@TPOFF, %eax
 EOF
-if { ac_try='${CC-cc} -c $CFLAGS conftest.s 1>&5'; { (eval echo configure:22: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; }; then
+if { ac_try='${CC-cc} -c $CFLAGS conftest.s 1>&5'; { (eval echo configure:24: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; }; then
   libc_cv_386_tls=yes
 else
   libc_cv_386_tls=no