This is the mail archive of the libc-hacker@sources.redhat.com mailing list for the glibc project.

Note that libc-hacker is a closed list. You may look at the archives of this list, but subscription and posting are not open.


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] IA-64 glibc TLS support


Hi!

The following patch adds TLS support to IA-64.
Passed make check with --with-tls --without-__thread (--with-tls
--with-__thread needs to wait until I fix one bug in ld).
For TLS_DTV_AT_TP arches (ie. IA-64 and Alpha ATM) it introduces a different
memory layout:
[ struct _pthread_descr_struct ] [ tcbhead_t ] [ TCB data ]
				 ^ TP points here
(on NPTL s/_pthread_descr_struct/pthread/).
The reason for this is that the ABI mandates the that TCB data
follow immediately above the 16 byte tcbhead_t (plus alignment for the
first PT_TLS), so pthread struct cannot be where it used to be.
Instead of using indirection through the private pointer in the
second void * of tcbhead_t, when the thread structure is placed
right below therad pointer, THREAD_[GS]ETMEM macros can still
read/write the structure members directly using negative offsets.

Also, it seems moving CHECK_STATIC_TLS before l_tls_offset
uses was forgotten. If it is not moved, even if the macro successfully
allocates the PT_TLS slot, the relocation will be still wrong (but
silently).

Richard, Alpha will need corresponding changes to at least alpha/tls.h.
Have not done them because I still don't have TLS capable Alpha gcc.

2003-01-11  Jakub Jelinek  <jakub@redhat.com>

	* elf/tls-macros.h [__ia64__] (__TLS_CALL_CLOBBERS): Define.
	[__ia64__] (TLS_LE, TLS_IE): Fix typos.  Add ;; at start of asm if
	gp is used early.
	[__ia64__] (TLS_LD, TLS_GD): Likewise.  Use __TLS_CALL_CLOBBERS.
	* elf/Makefile ($(objpfx)tst-tlsmod5.so, $(objpfx)tst-tlsmod6.so):
	Ensure libc.so in DT_NEEDED.
	* sysdeps/alpha/dl-machine.h (elf_machine_rela): Move
	CHECK_STATIC_TLS before l_tls_offset use.
	* sysdeps/i386/dl-machine.h (elf_machine_rel, elf_machine_rela):
	Likewise.
	* sysdeps/sh/dl-machine.h (elf_machine_rela): Likewise.
	* sysdeps/generic/dl-tls.c (_dl_allocate_tls_storage) [TLS_DTV_AT_TP]:
	Allocate TLS_PRE_TCB_SIZE bytes below result.
	(_dl_deallocate_tls) [TLS_DTV_AT_TP]: Adjust before freeing.
	* sysdeps/generic/libc-tls.c (__libc_setup_tls): If
	TLS_INIT_TP_EXPENSIVE is not defined, allocate even if no PT_TLS
	segment has been found.  If TLS_DTV_AT_TP, allocate TLS_PRE_TCB_SIZE
	bytes below result and add tcb_offset to memsz.
	* sysdeps/ia64/dl-tls.h (__tls_get_addr): New prototype.
	* sysdeps/ia64/dl-machine.h: Include tls.h.
	(elf_machine_type_class): Return ELF_RTYPE_CLASS_PLT for TLS relocs
	too.
	(elf_machine_rela): Assume if sym_map != NULL sym is non-NULL too.
	Handle R_IA64_DTPMOD*, R_IA64_DTPREL* and R_IA64_TPREL* relocations.
	* sysdeps/ia64/libc-tls.c: New file.
linuxthreads/
	* sysdeps/ia64/tls.h (tcbhead_t): Change into dtv_t *, void *.
	[HAVE_TLS_SUPPORT] (USE_TLS, TLS_INIT_TCB_SIZE, TLS_INIT_TCB_ALIGN,
	TLS_TCB_SIZE, TLS_PRE_TCB_SIZE, TLS_TCB_ALIGN, TLS_DTV_AT_TP,
	INSTALL_DTV, INSTALL_NEW_DTV, GET_DTV, TLS_INIT_TP, THREAD_SELF,
	INIT_THREAD_SELF): Define.
	[HAVE_TLS_SUPPORT]: Include descr.h.
	(NONTLS_INIT_TP): Point __thread_self at the end of dummy
	struct _pthread_descr_struct.
	* sysdeps/ia64/pt-machine.h (THREAD_GETMEM, THREAD_GETMEM_NC,
	THREAD_SETMEM, THREAD_SETMEM_NC): Define using THREAD_SELF,
	not __thread_self.
	* sysdeps/ia64/tcb-offsets.sym (MULTIPLE_THREADS_OFFSET): Adjust
	computation.
	* pthread.c (__pthread_initialize_minimal): Use tcbp, not self
	for TCB pointer.
	(__pthread_initialize_manager): Rename tcb to mgr.
	Use tcbp for TCB pointer, if TLS_DTV_AT_TP set mgr to sizeof (struct
	_pthread_descr) below tcbp, otherwise to tcbp.
	* manager.c (pthread_handle_create): If TLS_DTV_AT_TP, set
	new_thread to be below _dl_allocate_tls ().  Adjust new_thread back
	before freeing.  Fix clone arguments if report_events and USE_TLS.
	(pthread_free): Adjust th back before freeing.

--- libc/elf/tls-macros.h.jj	Wed Nov 20 22:02:41 2002
+++ libc/elf/tls-macros.h	Fri Jan 10 12:27:29 2003
@@ -243,47 +243,59 @@ register void *__gp __asm__("$29");
 
 # define TLS_LE(x) \
   ({ void *__l;								      \
-     asm ("ld8 r2=tp\n\t"						      \
+     asm ("mov r2=r13\n\t"						      \
          ";;\n\t"							      \
-         "addl %0=@tpre1(" #x "),r2\n\t"				      \
+         "addl %0=@tprel(" #x "),r2\n\t"				      \
          : "=r" (__l) : : "r2"  ); __l; })
 
 # define TLS_IE(x) \
   ({ void *__l;								      \
-     asm ("addl r16=@ltoff(@tprel(" #x ")),gp\n\t"			      \
+     asm (";;\n\t"							      \
+	 "addl r16=@ltoff(@tprel(" #x ")),gp\n\t"			      \
          ";;\n\t"							      \
          "ld8 r17=[r16]\n\t"						      \
          ";;\n\t"							      \
-         "add %0=tp,r17\n\t"						      \
+         "add %0=r13,r17\n\t"						      \
          : "=r" (__l) : : "r16", "r17" ); __l; })
 
+# define __TLS_CALL_CLOBBERS \
+  "r2", "r3", "r8", "r9", "r10", "r11", "r14", "r15", "r16", "r17",	      \
+  "r18", "r19", "r20", "r21", "r22", "r23", "r24", "r25", "r26",	      \
+  "r27", "r28", "r29", "r30", "r31",					      \
+  "p6", "p7", "p8", "p9", "p10", "p11", "p12", "p13", "p14", "p15",	      \
+  "f6", "f7", "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15",	      \
+  "b6", "b7",								      \
+  "out0", "out1", "out2", "out3", "out4", "out5", "out6", "out7"
+
 # define TLS_LD(x) \
   ({ void *__l;								      \
-     asm ("mov loc0=gp\n\t"						      \
+     asm (";;\n\t"							      \
+	 "mov loc0=gp\n\t"						      \
          "addl r16=@ltoff(@dtpmod(" #x ")),gp\n\t"			      \
          "addl out1=@dtprel(" #x "),r0\n\t"				      \
          ";;\n\t"							      \
          "ld8 out0=[r16]\n\t"						      \
-         "br.callrp=__tls_get_addr"					      \
+         "br.call.sptk.many b0=__tls_get_addr"				      \
          ";;\n\t"							      \
          "mov gp=loc0\n\t"						      \
          "mov %0=r8\n\t"						      \
-         : "=r" (__l) : : "r16" , "loc0" , "out0" , "out1" , "r8" );	      \
+         : "=r" (__l) : : "loc0", __TLS_CALL_CLOBBERS);			      \
      __l; })
 
 # define TLS_GD(x) \
   ({ void *__l;								      \
-     asm ("mov loc0=gp\n\t"						      \
+     asm (";;\n\t"							      \
+	 "mov loc0=gp\n\t"						      \
          "addl r16=@ltoff(@dtpmod(" #x ")),gp\n\t"			      \
          "addl r17=@ltoff(@dtprel(" #x ")),gp\n\t"			      \
          ";;\n\t"							      \
          "ld8 out0=[r16]\n\t"						      \
          "ld8 out1=[r17]\n\t"						      \
-         "br.callrp=__tls_get_addr"					      \
+         "br.call.sptk.many b0=__tls_get_addr"				      \
          ";;\n\t"							      \
          "mov gp=loc0\n\t"						      \
          "mov %0=r8\n\t"						      \
-          : "=r" (__l) : : "r16", "r17" , "loc0" , "out0", "out1" , "r8");    \
+          : "=r" (__l) : : "loc0", __TLS_CALL_CLOBBERS);		      \
      __l; })
 
 #else
--- libc/elf/Makefile.jj	Mon Dec 30 16:11:39 2002
+++ libc/elf/Makefile	Fri Jan 10 13:00:34 2003
@@ -363,6 +363,9 @@ $(objpfx)reldep6mod2.so: $(objpfx)reldep
 $(objpfx)reldep6mod3.so: $(objpfx)reldep6mod2.so
 $(objpfx)reldep6mod4.so: $(objpfx)reldep6mod1.so
 $(objpfx)tst-tlsmod3.so: $(objpfx)tst-tlsmod2.so
+# For tst-tls9-static, make sure the modules it dlopens have libc.so in DT_NEEDED
+$(objpfx)tst-tlsmod5.so: $(common-objpfx)libc.so
+$(objpfx)tst-tlsmod6.so: $(common-objpfx)libc.so
 $(objpfx)reldep8mod3.so: $(objpfx)reldep8mod1.so $(objpfx)reldep8mod2.so
 
 LDFLAGS-tst-tlsmod5.so = -nostdlib
--- libc/linuxthreads/sysdeps/ia64/tls.h.jj	Sat Dec 28 17:12:57 2002
+++ libc/linuxthreads/sysdeps/ia64/tls.h	Thu Jan  9 18:03:37 2003
@@ -1,5 +1,5 @@
 /* Definitions for thread-local data handling.  linuxthreads/IA-64 version.
-   Copyright (C) 2002 Free Software Foundation, Inc.
+   Copyright (C) 2002, 2003 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
@@ -33,35 +33,91 @@ typedef union dtv
 } dtv_t;
 
 
-/* FIXME: Only temporary.  When TLS is supported on IA-64,
-   pthread_descr struct needs to be immediately below r13 and
-   at r13 a struct { dtv_t *dtv; void *private; }.  */
 typedef struct
 {
-  void *tcb;		/* Pointer to the TCB.  Not necessary the
-			   thread descriptor used by libpthread.  */
   dtv_t *dtv;
-  void *self;		/* Pointer to the thread descriptor.  */
-  int multiple_threads;
+  void *private;
 } tcbhead_t;
 
 #else /* __ASSEMBLER__ */
 # include <tcb-offsets.h>
 #endif /* __ASSEMBLER__ */
 
-#undef USE_TLS
+#ifdef HAVE_TLS_SUPPORT
 
-#if USE_TLS
+/* Signal that TLS support is available.  */
+# define USE_TLS        1
+
+# ifndef __ASSEMBLER__
+/* 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 (tcbhead_t)
+
+/* This is the size we need before TCB.  */
+#  define TLS_PRE_TCB_SIZE sizeof (struct _pthread_descr_struct)
+
+/* Alignment requirements for the TCB.  */
+#  define TLS_TCB_ALIGN __alignof__ (struct _pthread_descr_struct)
+
+/* The DTV is allocated at the TP; the TCB is placed elsewhere.  */
+#  define TLS_DTV_AT_TP 1
+
+/* Install the dtv pointer.  The pointer passed is to the element with
+   index -1 which contain the length.  */
+#  define INSTALL_DTV(tcbp, dtvp) \
+  ((tcbhead_t *) (tcbp))->dtv = (dtvp) + 1
+
+/* Install new dtv for current thread.  */
+#  define INSTALL_NEW_DTV(DTV) \
+  (((tcbhead_t *)__thread_self)->dtv = (DTV))
+
+/* Return dtv of given thread descriptor.  */
+#  define GET_DTV(tcbp) \
+  (((tcbhead_t *) (tcbp))->dtv)
+
+/* 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(tcbp, secondcall) \
+  (__thread_self = (tcbp), NULL)
+
+/* Return the address of the dtv for the current thread.  */
+#  define THREAD_DTV() \
+  (((tcbhead_t *)__thread_self)->dtv)
+
+/* Return the thread descriptor for the current thread.  */
+#  undef THREAD_SELF
+#  define THREAD_SELF (__thread_self - 1)
+
+#  undef INIT_THREAD_SELF
+#  define INIT_THREAD_SELF(descr, nr) \
+  (__thread_self = (struct _pthread_descr_struct *)(descr) + 1)
+
+/* Get the thread descriptor definition.  */
+#  include <linuxthreads/descr.h>
+
+# endif
 
 #else
 
-#define NONTLS_INIT_TP \
-  do { 								\
-    static const tcbhead_t nontls_init_tp			\
-      = { .multiple_threads = 0 };				\
-    __thread_self = (__typeof (__thread_self)) &nontls_init_tp;	\
+# ifndef __ASSEMBLER__
+/* Get the thread descriptor definition.  */
+#  include <linuxthreads/descr.h>
+
+#  define NONTLS_INIT_TP \
+  do { 									\
+    static struct _pthread_descr_struct nontls_init_tp			\
+      = { .p_header.data.multiple_threads = 0 };			\
+    __thread_self = ((__typeof (__thread_self)) &nontls_init_tp) + 1;	\
   } while (0)
 
+#endif
+
 #endif /* USE_TLS */
 
 #endif	/* tls.h */
--- libc/linuxthreads/sysdeps/ia64/pt-machine.h.jj	Mon Aug 26 18:39:43 2002
+++ libc/linuxthreads/sysdeps/ia64/pt-machine.h	Thu Jan  9 18:03:37 2003
@@ -1,6 +1,6 @@
 /* Machine-dependent pthreads configuration and inline functions.
    IA-64 version.
-   Copyright (C) 1999, 2000, 2002 Free Software Foundation, Inc.
+   Copyright (C) 1999, 2000, 2002, 2003 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
@@ -64,10 +64,10 @@ register struct _pthread_descr_struct *_
 
 
 /* Access to data in the thread descriptor is easy.  */
-#define THREAD_GETMEM(descr, member) __thread_self->member
-#define THREAD_GETMEM_NC(descr, member) __thread_self->member
-#define THREAD_SETMEM(descr, member, value) __thread_self->member = (value)
-#define THREAD_SETMEM_NC(descr, member, value) __thread_self->member = (value)
+#define THREAD_GETMEM(descr, member) THREAD_SELF->member
+#define THREAD_GETMEM_NC(descr, member) THREAD_SELF->member
+#define THREAD_SETMEM(descr, member, value) THREAD_SELF->member = (value)
+#define THREAD_SETMEM_NC(descr, member, value) THREAD_SELF->member = (value)
 
 
 /* Memory barrier */
--- libc/linuxthreads/sysdeps/ia64/tcb-offsets.sym.jj	Sat Dec 28 17:14:19 2002
+++ libc/linuxthreads/sysdeps/ia64/tcb-offsets.sym	Thu Jan  9 18:03:37 2003
@@ -1,4 +1,4 @@
 #include <sysdep.h>
 #include <tls.h>
 
-MULTIPLE_THREADS_OFFSET		offsetof (tcbhead_t, multiple_threads)
+MULTIPLE_THREADS_OFFSET offsetof (struct _pthread_descr_struct, p_header.data.multiple_threads) - sizeof (struct _pthread_descr_struct)
--- libc/linuxthreads/pthread.c.jj	Thu Jan  2 19:32:00 2003
+++ libc/linuxthreads/pthread.c	Fri Jan 10 18:05:28 2003
@@ -307,6 +307,8 @@ __pthread_initialize_minimal(void)
 # elif !USE___THREAD
   if (__builtin_expect (GL(dl_tls_max_dtv_idx) == 0, 0))
     {
+      tcbhead_t *tcbp;
+
       /* There is no actual TLS being used, so the thread register
 	 was not initialized in the dynamic linker.  */
 
@@ -318,7 +320,7 @@ __pthread_initialize_minimal(void)
       __libc_malloc_pthread_startup (true);
 
       if (__builtin_expect (_dl_tls_setup (), 0)
-	  || __builtin_expect ((self = _dl_allocate_tls (NULL)) == NULL, 0))
+	  || __builtin_expect ((tcbp = _dl_allocate_tls (NULL)) == NULL, 0))
 	{
 	  static const char msg[] = "\
 cannot allocate TLS data structures for initial thread\n";
@@ -326,7 +328,7 @@ cannot allocate TLS data structures for 
 					    msg, sizeof msg - 1));
 	  abort ();
 	}
-      const char *lossage = TLS_INIT_TP (self, 0);
+      const char *lossage = TLS_INIT_TP (tcbp, 0);
       if (__builtin_expect (lossage != NULL, 0))
 	{
 	  static const char msg[] = "cannot set up thread-local storage: ";
@@ -343,7 +345,7 @@ cannot allocate TLS data structures for 
 	 the hooks might not work with that block from the plain malloc.
 	 So we record this block as unfreeable just as the dynamic linker
 	 does when it allocates the DTV before the libc malloc exists.  */
-      GL(dl_initial_dtv) = GET_DTV (self);
+      GL(dl_initial_dtv) = GET_DTV (tcbp);
 
       __libc_malloc_pthread_startup (false);
     }
@@ -558,7 +560,10 @@ int __pthread_initialize_manager(void)
   int pid;
   struct pthread_request request;
   int report_events;
-  pthread_descr tcb;
+  pthread_descr mgr;
+#ifdef USE_TLS
+  tcbhead_t *tcbp;
+#endif
 
   __pthread_multiple_threads = 1;
   __pthread_main_thread->p_header.data.multiple_threads = 1;
@@ -588,31 +593,39 @@ int __pthread_initialize_manager(void)
 
 #ifdef USE_TLS
   /* Allocate memory for the thread descriptor and the dtv.  */
-  __pthread_handles[1].h_descr = manager_thread = tcb
-    = _dl_allocate_tls (NULL);
-  if (tcb == NULL) {
+  tcbp  = _dl_allocate_tls (NULL);
+  if (tcbp == NULL) {
     free(__pthread_manager_thread_bos);
     __libc_close(manager_pipe[0]);
     __libc_close(manager_pipe[1]);
     return -1;
   }
 
+# if TLS_TCB_AT_TP
+  mgr = (pthread_descr) tcbp;
+# elif TLS_DTV_AT_TP
+  /* pthread_descr is located right below tcbhead_t which _dl_allocate_tls
+     returns.  */
+  mgr = (pthread_descr) tcbp - 1;
+# endif
+  __pthread_handles[1].h_descr = manager_thread = mgr;
+
   /* Initialize the descriptor.  */
-  tcb->p_header.data.tcb = tcb;
-  tcb->p_header.data.self = tcb;
-  tcb->p_header.data.multiple_threads = 1;
-  tcb->p_lock = &__pthread_handles[1].h_lock;
+  mgr->p_header.data.tcb = tcbp;
+  mgr->p_header.data.self = mgr;
+  mgr->p_header.data.multiple_threads = 1;
+  mgr->p_lock = &__pthread_handles[1].h_lock;
 # ifndef HAVE___THREAD
-  tcb->p_errnop = &tcb->p_errno;
+  mgr->p_errnop = &mgr->p_errno;
 # endif
-  tcb->p_start_args = (struct pthread_start_args) PTHREAD_START_ARGS_INITIALIZER(__pthread_manager);
-  tcb->p_nr = 1;
+  mgr->p_start_args = (struct pthread_start_args) PTHREAD_START_ARGS_INITIALIZER(__pthread_manager);
+  mgr->p_nr = 1;
 # if __LT_SPINLOCK_INIT != 0
   self->p_resume_count = (struct pthread_atomic) __ATOMIC_INITIALIZER;
 # endif
-  tcb->p_alloca_cutoff = PTHREAD_STACK_MIN / 4;
+  mgr->p_alloca_cutoff = PTHREAD_STACK_MIN / 4;
 #else
-  tcb = &__pthread_manager_thread;
+  mgr = &__pthread_manager_thread;
 #endif
 
   __pthread_manager_request = manager_pipe[1]; /* writing end */
@@ -649,24 +662,24 @@ int __pthread_initialize_manager(void)
       if ((mask & (__pthread_threads_events.event_bits[idx] | event_bits))
 	  != 0)
 	{
-	  __pthread_lock(tcb->p_lock, NULL);
+	  __pthread_lock(mgr->p_lock, NULL);
 
 #ifdef NEED_SEPARATE_REGISTER_STACK
 	  pid = __clone2(__pthread_manager_event,
 			 (void **) __pthread_manager_thread_bos,
 			 THREAD_MANAGER_STACK_SIZE,
 			 CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND,
-			 tcb);
+			 mgr);
 #elif _STACK_GROWS_UP
 	  pid = __clone(__pthread_manager_event,
 			(void **) __pthread_manager_thread_bos,
 			CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND,
-			tcb);
+			mgr);
 #else
 	  pid = __clone(__pthread_manager_event,
 			(void **) __pthread_manager_thread_tos,
 			CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND,
-			tcb);
+			mgr);
 #endif
 
 	  if (pid != -1)
@@ -675,18 +688,18 @@ int __pthread_initialize_manager(void)
 	         the newly created thread's data structure.  We cannot let
 	         the new thread do this since we don't know whether it was
 	         already scheduled when we send the event.  */
-	      tcb->p_eventbuf.eventdata = tcb;
-	      tcb->p_eventbuf.eventnum = TD_CREATE;
-	      __pthread_last_event = tcb;
-	      tcb->p_tid = 2* PTHREAD_THREADS_MAX + 1;
-	      tcb->p_pid = pid;
+	      mgr->p_eventbuf.eventdata = mgr;
+	      mgr->p_eventbuf.eventnum = TD_CREATE;
+	      __pthread_last_event = mgr;
+	      mgr->p_tid = 2* PTHREAD_THREADS_MAX + 1;
+	      mgr->p_pid = pid;
 
 	      /* Now call the function which signals the event.  */
 	      __linuxthreads_create_event ();
 	    }
 
 	  /* Now restart the thread.  */
-	  __pthread_unlock(tcb->p_lock);
+	  __pthread_unlock(mgr->p_lock);
 	}
     }
 
@@ -695,13 +708,13 @@ int __pthread_initialize_manager(void)
 #ifdef NEED_SEPARATE_REGISTER_STACK
       pid = __clone2(__pthread_manager, (void **) __pthread_manager_thread_bos,
 		     THREAD_MANAGER_STACK_SIZE,
-		     CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND, tcb);
+		     CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND, mgr);
 #elif _STACK_GROWS_UP
       pid = __clone(__pthread_manager, (void **) __pthread_manager_thread_bos,
-		    CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND, tcb);
+		    CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND, mgr);
 #else
       pid = __clone(__pthread_manager, (void **) __pthread_manager_thread_tos,
-		    CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND, tcb);
+		    CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND, mgr);
 #endif
     }
   if (__builtin_expect (pid, 0) == -1) {
@@ -710,8 +723,8 @@ int __pthread_initialize_manager(void)
     __libc_close(manager_pipe[1]);
     return -1;
   }
-  tcb->p_tid = 2* PTHREAD_THREADS_MAX + 1;
-  tcb->p_pid = pid;
+  mgr->p_tid = 2* PTHREAD_THREADS_MAX + 1;
+  mgr->p_pid = pid;
   /* Make gdb aware of new thread manager */
   if (__builtin_expect (__pthread_threads_debug, 0) && __pthread_sig_debug > 0)
     {
--- libc/linuxthreads/manager.c.jj	Tue Dec 17 20:17:09 2002
+++ libc/linuxthreads/manager.c	Fri Jan 10 18:04:51 2003
@@ -590,6 +588,10 @@ static int pthread_handle_create(pthread
   new_thread = _dl_allocate_tls (NULL);
   if (new_thread == NULL)
     return EAGAIN;
+# if TLS_DTV_AT_TP
+  /* pthread_descr is right below TP.  */
+  --new_thread;
+# endif
 #else
   /* Prevent warnings.  */
   new_thread = NULL;
@@ -607,6 +609,9 @@ static int pthread_handle_create(pthread
       if (sseg >= PTHREAD_THREADS_MAX)
 	{
 #ifdef USE_TLS
+# if TLS_DTV_AT_TP
+	  ++new_thread;
+# endif
 	  _dl_deallocate_tls (new_thread, true);
 #endif
 	  return EAGAIN;
@@ -631,7 +636,11 @@ static int pthread_handle_create(pthread
   new_thread_id = sseg + pthread_threads_counter;
   /* Initialize the thread descriptor.  Elements which have to be
      initialized to zero already have this value.  */
+#if defined USE_TLS && TLS_DTV_AT_TP
+  new_thread->p_header.data.tcb = new_thread + 1;
+#else
   new_thread->p_header.data.tcb = new_thread;
+#endif
   new_thread->p_header.data.self = new_thread;
   new_thread->p_header.data.multiple_threads = 1;
   new_thread->p_tid = new_thread_id;
@@ -711,15 +720,15 @@ static int pthread_handle_create(pthread
 	   other, to get less paging and fewer mmaps.  */
 	  pid = __clone2(pthread_start_thread_event,
   		 (void **)new_thread_bottom,
-			 (char *)new_thread - new_thread_bottom,
+			 (char *)stack_addr - new_thread_bottom,
 			 CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND |
 			 __pthread_sig_cancel, new_thread);
 #elif _STACK_GROWS_UP
-	  pid = __clone(pthread_start_thread_event, (void **) new_thread_bottom,
+	  pid = __clone(pthread_start_thread_event, (void *) new_thread_bottom,
 			CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND |
 			__pthread_sig_cancel, new_thread);
 #else
-	  pid = __clone(pthread_start_thread_event, (void **) new_thread,
+	  pid = __clone(pthread_start_thread_event, stack_addr,
 			CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND |
 			__pthread_sig_cancel, new_thread);
 #endif
@@ -794,6 +803,9 @@ static int pthread_handle_create(pthread
 #endif
       }
 #ifdef USE_TLS
+# if TLS_DTV_AT_TP
+    ++new_thread;
+# endif
     _dl_deallocate_tls (new_thread, true);
 #endif
     __pthread_handles[sseg].h_descr = NULL;
@@ -881,6 +893,9 @@ static void pthread_free(pthread_descr t
       munmap(guardaddr, stacksize + guardsize);
 
 #ifdef USE_TLS
+# if TLS_DTV_AT_TP
+      ++th;
+# endif
       _dl_deallocate_tls (th, true);
 #endif
     }
--- libc/sysdeps/alpha/dl-machine.h.jj	Thu Nov  7 21:19:00 2002
+++ libc/sysdeps/alpha/dl-machine.h	Thu Jan  9 18:03:37 2003
@@ -1,5 +1,5 @@
 /* Machine-dependent ELF dynamic relocation inline functions.  Alpha version.
-   Copyright (C) 1996-2001, 2002 Free Software Foundation, Inc.
+   Copyright (C) 1996-2002, 2003 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Richard Henderson <rth@tamu.edu>.
 
@@ -610,8 +610,8 @@ elf_machine_rela (struct link_map *map,
 #else
 	  if (sym_map)
 	    {
-	      *reloc_addr = sym_value - sym_map->l_tls_offset;
 	      CHECK_STATIC_TLS (map, sym_map);
+	      *reloc_addr = sym_value - sym_map->l_tls_offset;
 	    }
 #endif
 	}
--- libc/sysdeps/generic/dl-tls.c.jj	Fri Jan  3 15:47:25 2003
+++ libc/sysdeps/generic/dl-tls.c	Fri Jan 10 18:05:55 2003
@@ -282,9 +282,18 @@ internal_function
 _dl_allocate_tls_storage (void)
 {
   void *result;
+  size_t size = GL(dl_tls_static_size);
+
+# if TLS_DTV_AT_TP
+  /* Memory layout is:
+     [ TLS_PRE_TCB_SIZE ] [ TLS_TCB_SIZE ] [ TLS blocks ]
+			  ^ This should be returned.  */
+  size += (TLS_PRE_TCB_SIZE + GL(dl_tls_static_align) - 1)
+	  & ~(GL(dl_tls_static_align) - 1);
+# endif
 
   /* Allocate a correctly aligned chunk of memory.  */
-  result = __libc_memalign (GL(dl_tls_static_align), GL(dl_tls_static_size));
+  result = __libc_memalign (GL(dl_tls_static_align), size);
   if (__builtin_expect (result != NULL, 0))
     {
       /* Allocate the DTV.  */
@@ -292,12 +301,20 @@ _dl_allocate_tls_storage (void)
 
 # if TLS_TCB_AT_TP
       /* The TCB follows the TLS blocks.  */
-      result = (char *) result + GL(dl_tls_static_size) - TLS_TCB_SIZE;
-# endif
+      result = (char *) result + size - TLS_TCB_SIZE;
 
       /* Clear the TCB data structure.  We can't ask the caller (i.e.
 	 libpthread) to do it, because we will initialize the DTV et al.  */
       memset (result, 0, TLS_TCB_SIZE);
+# elif TLS_DTV_AT_TP
+      result = (char *) result + size - GL(dl_tls_static_size);
+
+      /* Clear the TCB data structure and TLS_PRE_TCB_SIZE bytes before it.
+	 We can't ask the caller (i.e. libpthread) to do it, because we will
+	 initialize the DTV et al.  */
+      memset ((char *) result - TLS_PRE_TCB_SIZE, 0,
+	      TLS_PRE_TCB_SIZE + TLS_TCB_SIZE);
+# endif
 
       result = allocate_dtv (result);
       if (result == NULL)
@@ -405,6 +422,10 @@ _dl_deallocate_tls (void *tcb, bool deal
 # if TLS_TCB_AT_TP
       /* The TCB follows the TLS blocks.  Back up to free the whole block.  */
       tcb -= GL(dl_tls_static_size) - TLS_TCB_SIZE;
+# elif TLS_DTV_AT_TP
+      /* Back up the TLS_PRE_TCB_SIZE bytes.  */
+      tcb -= (TLS_PRE_TCB_SIZE + GL(dl_tls_static_align) - 1)
+	     & ~(GL(dl_tls_static_align) - 1);
 # endif
       free (tcb);
     }
--- libc/sysdeps/generic/libc-tls.c.jj	Sat Dec 28 04:15:39 2002
+++ libc/sysdeps/generic/libc-tls.c	Fri Jan 10 18:01:07 2003
@@ -1,5 +1,5 @@
 /* Initialization code for TLS in statically linked application.
-   Copyright (C) 2002 Free Software Foundation, Inc.
+   Copyright (C) 2002, 2003 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
@@ -134,15 +134,16 @@ __libc_setup_tls (size_t tcbsize, size_t
 	  break;
 	}
 
+#ifdef TLS_INIT_TP_EXPENSIVE
   if (memsz == 0 && tcbsize <= TLS_INIT_TCB_SIZE)
     {
       /* We do not need a TLS block and no thread descriptor.  */
-#ifdef NONTLS_INIT_TP
+# ifdef NONTLS_INIT_TP
       NONTLS_INIT_TP;
-#endif
+# endif
       return;
     }
-
+#endif
 
   /* We have to set up the TCB block which also (possibly) contains
      'errno'.  Therefore we avoid 'malloc' which might touch 'errno'.
@@ -157,8 +158,10 @@ __libc_setup_tls (size_t tcbsize, size_t
   tcb_offset = roundup (memsz + GL(dl_tls_static_size), tcbalign);
   tlsblock = __sbrk (tcb_offset + tcbsize + max_align);
 # elif TLS_DTV_AT_TP
-  tlsblock = __sbrk (roundup (tcbsize, align) + memsz + max_align
-		     + GL(dl_tls_static_size));
+  tcb_offset = roundup (tcbsize, align ?: 1);
+  tlsblock = __sbrk (tcb_offset + memsz + max_align
+		     + TLS_PRE_TCB_SIZE + GL(dl_tls_static_size));
+  tlsblock += TLS_PRE_TCB_SIZE;
 # 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.  */
@@ -179,7 +182,6 @@ __libc_setup_tls (size_t tcbsize, size_t
 			   - roundup (memsz, align ?: 1));
   static_map.l_tls_offset = roundup (memsz, align ?: 1);
 # elif TLS_DTV_AT_TP
-  tcb_offset = roundup (tcbsize, align);
   static_dtv[2].pointer = (char *) tlsblock + tcb_offset;
   static_map.l_tls_offset = tcb_offset;
 # else
@@ -222,6 +224,8 @@ __libc_setup_tls (size_t tcbsize, size_t
 
 # if TLS_TCB_AT_TP
   memsz += tcbsize;
+# elif TLS_DTV_AT_TP
+  memsz += tcb_offset;
 # endif
 
   init_static_tls (memsz, MAX (TLS_TCB_ALIGN, max_align));
--- libc/sysdeps/i386/dl-machine.h.jj	Fri Nov 15 17:51:19 2002
+++ libc/sysdeps/i386/dl-machine.h	Thu Jan  9 18:03:37 2003
@@ -1,5 +1,5 @@
 /* Machine-dependent ELF dynamic relocation inline functions.  i386 version.
-   Copyright (C) 1995,96,97,98,99,2000,2001,2002 Free Software Foundation, Inc.
+   Copyright (C) 1995-2002, 2003 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
@@ -445,8 +445,8 @@ elf_machine_rel (struct link_map *map, c
 	     block we subtract the offset from that of the TLS block.  */
 	  if (sym != NULL)
 	    {
-	      *reloc_addr += sym_map->l_tls_offset - sym->st_value;
 	      CHECK_STATIC_TLS (map, sym_map);
+	      *reloc_addr += sym_map->l_tls_offset - sym->st_value;
 	    }
 # endif
 	  break;
@@ -460,8 +460,8 @@ elf_machine_rel (struct link_map *map, c
 	     thread pointer.  */
 	  if (sym != NULL)
 	    {
-	      *reloc_addr += sym->st_value - sym_map->l_tls_offset;
 	      CHECK_STATIC_TLS (map, sym_map);
+	      *reloc_addr += sym->st_value - sym_map->l_tls_offset;
 	    }
 # endif
 	  break;
@@ -555,20 +555,20 @@ elf_machine_rela (struct link_map *map, 
 	     It is a positive value which will be subtracted from the
 	     thread pointer.  To get the variable position in the TLS
 	     block we subtract the offset from that of the TLS block.  */
+	  CHECK_STATIC_TLS (map, sym_map);
 	  *reloc_addr
 	    = (sym == NULL ? 0 : sym_map->l_tls_offset - sym->st_value)
 	      + reloc->r_addend;
-	  CHECK_STATIC_TLS (map, sym_map);
 	  break;
 	case R_386_TLS_TPOFF:
 	  /* The offset is negative, forward from the thread pointer.  */
 	  /* We know the offset of object the symbol is contained in.
 	     It is a negative value which will be added to the
 	     thread pointer.  */
+	  CHECK_STATIC_TLS (map, sym_map);
 	  *reloc_addr
 	    = (sym == NULL ? 0 : sym->st_value - sym_map->l_tls_offset)
 	      + reloc->r_addend;
-	  CHECK_STATIC_TLS (map, sym_map);
 	  break;
 # endif	/* use TLS */
 # ifndef RESOLVE_CONFLICT_FIND_MAP
--- libc/sysdeps/ia64/dl-tls.h.jj	Wed Feb 27 13:53:55 2002
+++ libc/sysdeps/ia64/dl-tls.h	Thu Jan  9 18:03:37 2003
@@ -1,5 +1,5 @@
 /* Thread-local storage handling in the ELF dynamic linker.  IA-64 version.
-   Copyright (C) 2002 Free Software Foundation, Inc.
+   Copyright (C) 2002, 2003 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
@@ -26,3 +26,5 @@
 
 /* We have no tls_index type.  */
 #define DONT_USE_TLS_INDEX	1
+
+extern void *__tls_get_addr (size_t m, size_t offset);
--- libc/sysdeps/ia64/dl-machine.h.jj	Wed Oct  2 16:24:21 2002
+++ libc/sysdeps/ia64/dl-machine.h	Thu Jan  9 18:03:37 2003
@@ -1,5 +1,5 @@
 /* Machine-dependent ELF dynamic relocation inline functions.  IA-64 version.
-   Copyright (C) 1995,1996,1997,2000,2001,2002 Free Software Foundation, Inc.
+   Copyright (C) 1995-1997, 2000-2002, 2003 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
@@ -26,7 +26,7 @@
 #include <string.h>
 #include <link.h>
 #include <errno.h>
-
+#include <tls.h>
 
 /* Translate a processor specific dynamic tag to the index
    in l_info array.  */
@@ -448,14 +448,22 @@ elf_machine_runtime_setup (struct link_m
 #define RTLD_START_SPECIAL_INIT /* nothing */
 #endif
 
-/* ELF_RTYPE_CLASS_PLT iff TYPE describes relocation of a PLT entry, so
-   PLT entries should not be allowed to define the value.
+/* ELF_RTYPE_CLASS_PLT iff TYPE describes relocation of a PLT entry or TLS
+   variable, so undefined references should not be allowed to define the
+   value.
    ELF_RTYPE_CLASS_NOCOPY iff TYPE should not be allowed to resolve to one
    of the main executable's symbols, as for a COPY reloc, which we don't
    use.  */
-/* ??? Ignore IPLTMSB for now.  */
+/* ??? Ignore *MSB for now.  */
+#if defined USE_TLS && (!defined RTLD_BOOTSTRAP || USE___THREAD)
+#define elf_machine_type_class(type) \
+  (((type) == R_IA64_IPLTLSB || (type) == R_IA64_DTPMOD64LSB		      \
+    || (type) == R_IA64_DTPREL64LSB || (type) == R_IA64_TPREL64LSB)	      \
+   * ELF_RTYPE_CLASS_PLT)
+#else
 #define elf_machine_type_class(type) \
   (((type) == R_IA64_IPLTLSB) * ELF_RTYPE_CLASS_PLT)
+#endif
 
 /* A reloc type used for ld.so cmdline arg lookups to reject PLT entries.  */
 #define ELF_MACHINE_JMP_SLOT	 R_IA64_IPLTLSB
@@ -557,8 +565,7 @@ elf_machine_rela (struct link_map *map,
       /* RESOLVE_MAP() will return NULL if it fail to locate the symbol.  */
       if ((sym_map = RESOLVE_MAP (&sym, version, r_type)))
         {
-	  value = sym ? sym_map->l_addr + sym->st_value : 0;
-	  value += reloc->r_addend;
+	  value = sym_map->l_addr + sym->st_value + reloc->r_addend;
 
 	  if (R_IA64_TYPE (r_type) == R_IA64_TYPE (R_IA64_DIR64LSB))
 	    ;/* No adjustment.  */
@@ -571,6 +578,26 @@ elf_machine_rela (struct link_map *map,
 	    value = __ia64_make_fptr (sym_map, sym, value);
 	  else if (R_IA64_TYPE (r_type) == R_IA64_TYPE (R_IA64_PCREL64LSB))
 	    value -= (Elf64_Addr) reloc_addr & -16;
+#if defined USE_TLS && (!defined RTLD_BOOTSTRAP || defined USE___THREAD)
+	  else if (R_IA64_TYPE (r_type) == R_IA64_TYPE (R_IA64_DTPMOD64LSB))
+# ifdef RTLD_BOOTSTRAP
+	    /* During startup the dynamic linker is always index 1.  */
+	    value = 1;
+# else	      
+	    /* Get the information from the link map returned by the
+	       resolv function.  */
+	    value = sym_map->l_tls_modid;
+	  else if (R_IA64_TYPE (r_type) == R_IA64_TYPE (R_IA64_DTPREL64LSB))
+	    value -= sym_map->l_addr;
+# endif
+	  else if (R_IA64_TYPE (r_type) == R_IA64_TYPE (R_IA64_TPREL64LSB))
+	    {
+# ifndef RTLD_BOOTSTRAP
+	      CHECK_STATIC_TLS (map, sym_map);
+# endif
+	      value += sym_map->l_tls_offset - sym_map->l_addr;
+	    }
+#endif
 	  else
 	    assert (! "unexpected dynamic reloc type");
 	}
--- libc/sysdeps/ia64/libc-tls.c.jj	Fri Jan 10 13:10:50 2003
+++ libc/sysdeps/ia64/libc-tls.c	Fri Jan 10 13:16:54 2003
@@ -0,0 +1,37 @@
+/* Thread-local storage handling in the ELF dynamic linker.  IA-64 version.
+   Copyright (C) 2003 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.  */
+
+#include <sysdeps/generic/libc-tls.c>
+
+#if USE_TLS
+
+/* On IA-64, as it lacks linker optimizations, __tls_get_addr can be
+   called even in statically linked binaries.
+   In this case module must be always 1 and PT_TLS segment
+   exist in the binary, otherwise it would not link.  */
+
+void *
+__tls_get_addr (size_t m, size_t offset)
+{
+  dtv_t *dtv = THREAD_DTV ();
+  return (char *) dtv[1].pointer + offset;
+}
+
+#endif
+
--- libc/sysdeps/sh/dl-machine.h.jj	Thu Oct 17 08:09:46 2002
+++ libc/sysdeps/sh/dl-machine.h	Thu Jan  9 18:03:37 2003
@@ -1,5 +1,5 @@
 /* Machine-dependent ELF dynamic relocation inline functions.  SH version.
-   Copyright (C) 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
+   Copyright (C) 1999, 2000, 2001, 2002, 2003 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
@@ -579,10 +579,10 @@ elf_machine_rela (struct link_map *map, 
 	     It is a positive value which will be added to the thread
 	     pointer.  To get the variable position in the TLS block
 	     we add the offset from that of the TLS block.  */
+	  CHECK_STATIC_TLS (map, sym_map);
 	  *reloc_addr
 	    = ((sym == NULL ? 0 : sym_map->l_tls_offset + sym->st_value)
 	       + reloc->r_addend);
-	  CHECK_STATIC_TLS (map, sym_map);
 # endif
 	  break;
 #endif	/* use TLS */

	Jakub


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