public inbox for libc-hacker@sourceware.org
 help / color / mirror / Atom feed
* Re: [PATCH] IA-64 glibc TLS support
  2003-01-13  4:59 [PATCH] IA-64 glibc TLS support Jakub Jelinek
@ 2003-01-13  4:59 ` David Mosberger
  2003-01-13  4:59 ` Ulrich Drepper
  2003-01-14  7:28 ` new syscall stub for ia64 linux David Mosberger
  2 siblings, 0 replies; 10+ messages in thread
From: David Mosberger @ 2003-01-13  4:59 UTC (permalink / raw)
  To: Jakub Jelinek
  Cc: Ulrich Drepper, Roland McGrath, Richard Henderson, Glibc hackers

Hi Jakub,

  Jakub> Hi!  The following patch adds TLS support to IA-64.  Passed
  Jakub> make check with --with-tls --without-__thread (--with-tls
  Jakub> --with-__thread needs to wait until I fix one bug in ld).

I applied this patch and built libc with it and it worked fine
(cool!).  I then tried to add the new (flexible) syscall stub, which
requires a valid thread-pointer even for non-threaded applications.
Unfortunately, at the moment it looks like the thread-pointer does not
get setup for such apps (it stays NULL).  What's the right place to
get this initialized?

Thanks,

	--david

^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCH] IA-64 glibc TLS support
@ 2003-01-13  4:59 Jakub Jelinek
  2003-01-13  4:59 ` David Mosberger
                   ` (2 more replies)
  0 siblings, 3 replies; 10+ messages in thread
From: Jakub Jelinek @ 2003-01-13  4:59 UTC (permalink / raw)
  To: Ulrich Drepper, Roland McGrath, Richard Henderson; +Cc: Glibc hackers

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

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH] IA-64 glibc TLS support
  2003-01-13  4:59 [PATCH] IA-64 glibc TLS support Jakub Jelinek
  2003-01-13  4:59 ` David Mosberger
@ 2003-01-13  4:59 ` Ulrich Drepper
  2003-01-14  7:28 ` new syscall stub for ia64 linux David Mosberger
  2 siblings, 0 replies; 10+ messages in thread
From: Ulrich Drepper @ 2003-01-13  4:59 UTC (permalink / raw)
  To: Jakub Jelinek; +Cc: Roland McGrath, Richard Henderson, Glibc hackers

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Thread-local storage handling in the ELF dynamic linker.  IA-64
version.Jakub Jelinek wrote:

> The following patch adds TLS support to IA-64.

Thanks, I've applied it.

- -- 
- --------------.                        ,-.            444 Castro Street
Ulrich Drepper \    ,-----------------'   \ Mountain View, CA 94041 USA
Red Hat         `--' drepper at redhat.com `---------------------------
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.2.1 (GNU/Linux)

iD8DBQE+IS2E2ijCOnn/RHQRAjzSAKCNmUVKk3xB5ATpIkDpjOOrUVl4rgCfYXnZ
eKToP2Bgpxq9Skr6J+qFt30=
=/eit
-----END PGP SIGNATURE-----

^ permalink raw reply	[flat|nested] 10+ messages in thread

* new syscall stub for ia64 linux
  2003-01-13  4:59 [PATCH] IA-64 glibc TLS support Jakub Jelinek
  2003-01-13  4:59 ` David Mosberger
  2003-01-13  4:59 ` Ulrich Drepper
@ 2003-01-14  7:28 ` David Mosberger
  2003-01-14  8:15   ` Ulrich Drepper
  2003-01-18  6:27   ` David Mosberger
  2 siblings, 2 replies; 10+ messages in thread
From: David Mosberger @ 2003-01-14  7:28 UTC (permalink / raw)
  To: Jakub Jelinek; +Cc: Glibc hackers

Below is a draft patch to add support to libc for the new syscall stub
I'd like to start using on ia64 linux.  The main change here is that
the syscall stub will do an indirect call via a "sysinfo" pointer
picked up from the thread-control-block.  By default, "sysinfo" points
to a _dl_sysinfo_break(), which does an old-style "break 0x100000"
syscall.  With newer kernels, this will get redefined via AT_SYSINFO
to an entry-point in the kernel's gate page, which does a light-weight
entry into the kernel.

Since it is extremely unpleasant to have to syscall stubs change, I'd
like the tp-offset of the "sysinfo" pointer to be set in stone.  The
ia64 ABI reserves the positive offsets off the thread-pointer for its
own purposes, so I'd like to propose an offset of -8.  In the patch
below, I did this by moving the "p_header" in _pthread_desc_struct to
the end of the structure (if TLS_TCB_AT_TP is not defined).

Most of the other changes should be pretty obvious.  One rather ugly
hack though is that in libc-start.c, I had to reverse the order of
DL_SYSDEP_OSCHEC() and __pthread_initialize_minimal(): the former
calls uname() and with the new syscall stub, the thread-pointer needs
to be valid before a system call can be invoked.  If this isn't
acceptable, suggestions for improvements would be welcome.

Thanks,

	--david

PS: No ChangeLog since I just want to get feedback at this point---the
    patch isn't ready for prime-time yet.

PPS: Relative to what was discussed on the linux-ia64 mailing list,
    I changed the syscall stub slightly: r9 got replaced by r11, because
    some system calls (e.g., pipe()) use r9 to return a second return
    value.  r11 should be safe that way.

Index: linuxthreads/descr.h
===================================================================
RCS file: /cvs/glibc/libc/linuxthreads/descr.h,v
retrieving revision 1.8
diff -u -r1.8 descr.h
--- linuxthreads/descr.h	28 Dec 2002 10:14:16 -0000	1.8
+++ linuxthreads/descr.h	14 Jan 2003 07:09:56 -0000
@@ -109,6 +109,7 @@
 
 struct _pthread_descr_struct {
   /* XXX Remove this union for IA-64 style TLS module */
+#if TLS_TCB_AT_TP
   union {
     struct {
       void *tcb;		/* Pointer to the TCB.  This is not always
@@ -122,6 +123,9 @@
     } data;
     void *__padding[16];
   } p_header;
+#else
+  /* New elements must be added at the beginning.  */
+#endif
   pthread_descr p_nextlive, p_prevlive;
                                 /* Double chaining of active threads */
   pthread_descr p_nextwaiting;  /* Next element in the queue holding the thr */
@@ -180,7 +184,23 @@
 #endif
   size_t p_alloca_cutoff;	/* Maximum size which should be allocated
 				   using alloca() instead of malloc().  */
+#if TLS_TCB_AT_TP
   /* New elements must be added at the end.  */
+#else
+  union {
+    struct {
+      void *reserved[11];	/* reserve for future use */
+      void *tcb;		/* XXX do we really need this? */
+      union dtv *dtvp;		/* XXX do we really need this? */
+      pthread_descr self;	/* XXX do we really need this? */
+      int multiple_threads;
+#ifdef NEED_DL_SYSINFO
+      uintptr_t sysinfo;
+#endif
+    } data;
+    void *__padding[16];
+  } p_header __attribute__ ((aligned(32)));
+#endif
 } __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.
Index: linuxthreads/sysdeps/ia64/tcb-offsets.sym
===================================================================
RCS file: /cvs/glibc/libc/linuxthreads/sysdeps/ia64/tcb-offsets.sym,v
retrieving revision 1.2
diff -u -r1.2 tcb-offsets.sym
--- linuxthreads/sysdeps/ia64/tcb-offsets.sym	12 Jan 2003 08:39:41 -0000	1.2
+++ linuxthreads/sysdeps/ia64/tcb-offsets.sym	14 Jan 2003 07:09:56 -0000
@@ -2,3 +2,9 @@
 #include <tls.h>
 
 MULTIPLE_THREADS_OFFSET offsetof (struct _pthread_descr_struct, p_header.data.multiple_threads) - sizeof (struct _pthread_descr_struct)
+
+#ifdef HAVE_TLS_SUPPORT
+
+SYSINFO_OFFSET		offsetof (struct _pthread_descr_struct, p_header.data.sysinfo) - sizeof (struct _pthread_descr_struct)
+
+#endif
Index: linuxthreads/sysdeps/ia64/tls.h
===================================================================
RCS file: /cvs/glibc/libc/linuxthreads/sysdeps/ia64/tls.h,v
retrieving revision 1.3
diff -u -r1.3 tls.h
--- linuxthreads/sysdeps/ia64/tls.h	12 Jan 2003 08:38:42 -0000	1.3
+++ linuxthreads/sysdeps/ia64/tls.h	14 Jan 2003 07:09:56 -0000
@@ -20,10 +20,13 @@
 #ifndef _TLS_H
 #define _TLS_H
 
+#include <dl-sysdep.h>
+
 #ifndef __ASSEMBLER__
 
 # include <pt-machine.h>
 # include <stddef.h>
+# include <stdint.h>
 
 /* Type for the dtv.  */
 typedef union dtv
@@ -83,8 +86,10 @@
 /* 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)
+#  define TLS_INIT_TP(tcbp, secondcall)			\
+  (__thread_self = (tcbp),				\
+   THREAD_SELF->p_header.data.sysinfo = GL(dl_sysinfo),	\
+   NULL)
 
 /* Return the address of the dtv for the current thread.  */
 #  define THREAD_DTV() \
@@ -114,6 +119,7 @@
     static struct _pthread_descr_struct nontls_init_tp			\
       = { .p_header.data.multiple_threads = 0 };			\
     __thread_self = ((__typeof (__thread_self)) &nontls_init_tp) + 1;	\
+    THREAD_SELF->p_header.data.sysinfo = GL(dl_sysinfo);		\
   } while (0)
 
 #endif
Index: linuxthreads/sysdeps/unix/sysv/linux/ia64/dl-sysdep.h
===================================================================
RCS file: linuxthreads/sysdeps/unix/sysv/linux/ia64/dl-sysdep.h
diff -N linuxthreads/sysdeps/unix/sysv/linux/ia64/dl-sysdep.h
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ linuxthreads/sysdeps/unix/sysv/linux/ia64/dl-sysdep.h	14 Jan 2003 07:09:56 -0000
@@ -0,0 +1,43 @@
+/* System-specific settings for dynamic linker code.  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.  */
+
+#ifndef _DL_SYSDEP_H
+#define _DL_SYSDEP_H	1
+
+#define NEED_DL_SYSINFO
+
+#ifndef __ASSEMBLER__
+/* Don't declare this as a function---we want it's entry-point, not
+   it's function descriptor... */
+extern int _dl_sysinfo_break attribute_hidden;
+# define DL_SYSINFO_DEFAULT ((uintptr_t) &_dl_sysinfo_break)
+# define DL_SYSINFO_IMPLEMENTATION			\
+  asm (".text\n\t"					\
+       ".hidden _dl_sysinfo_break\n\t"			\
+       ".proc _dl_sysinfo_break\n\t"			\
+       "_dl_sysinfo_break:\n\t"				\
+       ".prologue\n\t"					\
+       ".altrp b6\n\t"					\
+       ".body\n\t"					\
+       "break 0x100000;\n\t"				\
+       "br.ret.sptk.many b6;\n\t"			\
+       ".endp _dl_sysinfo_break");
+#endif
+
+#endif	/* dl-sysdep.h */
Index: sysdeps/generic/libc-start.c
===================================================================
RCS file: /cvs/glibc/libc/sysdeps/generic/libc-start.c,v
retrieving revision 1.35
diff -u -r1.35 libc-start.c
--- sysdeps/generic/libc-start.c	28 Dec 2002 09:14:52 -0000	1.35
+++ sysdeps/generic/libc-start.c	14 Jan 2003 07:09:56 -0000
@@ -83,14 +83,6 @@
   ++auxvec;
   _dl_aux_init ((ElfW(auxv_t) *) auxvec);
 # endif
-# ifdef DL_SYSDEP_OSCHECK
-  if (!__libc_multiple_libcs)
-    {
-      /* This needs to run to initiliaze _dl_osversion before TLS
-	 setup might check it.  */
-      DL_SYSDEP_OSCHECK (__libc_fatal);
-    }
-# endif
 
   /* Initialize the thread library at least a bit since the libgcc
      functions are using thread functions if these are available and
@@ -101,6 +93,15 @@
   if (__pthread_initialize_minimal)
 # endif
     __pthread_initialize_minimal ();
+
+# ifdef DL_SYSDEP_OSCHECK
+  if (!__libc_multiple_libcs)
+    {
+      /* This needs to run to initiliaze _dl_osversion before TLS
+	 setup might check it.  */
+      DL_SYSDEP_OSCHECK (__libc_fatal);
+    }
+# endif
 
   /* Some security at this point.  Prevent starting a SUID binary where
      the standard file descriptors are not opened.  We have to do this
Index: sysdeps/unix/sysv/linux/ia64/sysdep.h
===================================================================
RCS file: /cvs/glibc/libc/sysdeps/unix/sysv/linux/ia64/sysdep.h,v
retrieving revision 1.10
diff -u -r1.10 sysdep.h
--- sysdeps/unix/sysv/linux/ia64/sysdep.h	9 Jan 2003 04:09:25 -0000	1.10
+++ sysdeps/unix/sysv/linux/ia64/sysdep.h	14 Jan 2003 07:09:57 -0000
@@ -23,6 +23,7 @@
 
 #include <sysdeps/unix/sysdep.h>
 #include <sysdeps/ia64/sysdep.h>
+#include <tls.h>
 
 /* For Linux we can use the system call table in the header file
 	/usr/include/asm/unistd.h
@@ -89,9 +90,30 @@
 	cmp.eq p6,p0=-1,r10;			\
 (p6)	br.cond.spnt.few __syscall_error;
 
+#if defined HAVE_TLS_SUPPORT && (!defined NOT_IN_libc || defined IS_IN_libpthread)
+
+/* Use the lightweight stub only if (a) we have a suitably modern
+   thread-control block (HAVE_TLS_SUPPORT) and (b) we're not compiling
+   the runtime loader (which might do syscalls before being fully
+   relocated). */
+
+#define DO_CALL(num)				\
+	.prologue;				\
+        adds r2 = SYSINFO_OFFSET, r13;;		\
+        ld8 r2 = [r2];				\
+	.save ar.pfs, r11;			\
+        mov r11 = ar.pfs;;			\
+	.body;					\
+	mov r15 = num;				\
+        mov b7 = r2;				\
+        br.call.sptk.many b6 = b7;;		\
+	.restore sp;				\
+        mov ar.pfs = r11
+#else
 #define DO_CALL(num)				\
 	mov r15=num;				\
 	break __BREAK_SYSCALL;
+#endif
 
 #undef PSEUDO_END
 #define PSEUDO_END(name)	.endp C_SYMBOL_NAME(name);

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: new syscall stub for ia64 linux
  2003-01-14  7:28 ` new syscall stub for ia64 linux David Mosberger
@ 2003-01-14  8:15   ` Ulrich Drepper
  2003-01-14 11:13     ` Jakub Jelinek
  2003-01-18  6:27   ` David Mosberger
  1 sibling, 1 reply; 10+ messages in thread
From: Ulrich Drepper @ 2003-01-14  8:15 UTC (permalink / raw)
  To: davidm; +Cc: Jakub Jelinek, Glibc hackers

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

David Mosberger wrote:

> --- linuxthreads/descr.h	28 Dec 2002 10:14:16 -0000	1.8
> +++ linuxthreads/descr.h	14 Jan 2003 07:09:56 -0000
> @@ -109,6 +109,7 @@
>  
>  struct _pthread_descr_struct {
>    /* XXX Remove this union for IA-64 style TLS module */
> +#if TLS_TCB_AT_TP
>    union {
>      struct {
>        void *tcb;		/* Pointer to the TCB.  This is not always
> @@ -122,6 +123,9 @@
>      } data;
>      void *__padding[16];
>    } p_header;
> +#else
> +  /* New elements must be added at the beginning.  */
> +#endif
>    pthread_descr p_nextlive, p_prevlive;
>                                  /* Double chaining of active threads */
>    pthread_descr p_nextwaiting;  /* Next element in the queue holding the thr */
> @@ -180,7 +184,23 @@
>  #endif
>    size_t p_alloca_cutoff;	/* Maximum size which should be allocated
>  				   using alloca() instead of malloc().  */
> +#if TLS_TCB_AT_TP
>    /* New elements must be added at the end.  */
> +#else
> +  union {
> +    struct {
> +      void *reserved[11];	/* reserve for future use */
> +      void *tcb;		/* XXX do we really need this? */
> +      union dtv *dtvp;		/* XXX do we really need this? */
> +      pthread_descr self;	/* XXX do we really need this? */
> +      int multiple_threads;
> +#ifdef NEED_DL_SYSINFO
> +      uintptr_t sysinfo;
> +#endif
> +    } data;
> +    void *__padding[16];
> +  } p_header __attribute__ ((aligned(32)));
> +#endif
>  } __attribute__ ((aligned(32))); /* We need to align the structure so that

This change makes no sense.  The initial comment about removing the
union on ia64 is there because of the requirement that tp points a
location containing the DTV pointer, followed by some other 8 bytes.
I.e., the dtv pointer in the union is not necessary.

How and where the thread descriptor (not TCB in ia64 speak) is stored
remains to be seen.  I haven't looked closely enough to see what Jakub did.

- -- 
- --------------.                        ,-.            444 Castro Street
Ulrich Drepper \    ,-----------------'   \ Mountain View, CA 94041 USA
Red Hat         `--' drepper at redhat.com `---------------------------
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.2.1 (GNU/Linux)

iD8DBQE+I8cG2ijCOnn/RHQRAhodAJ9s8zd0QmsxpetaU7nHJpIm4K+ojACgmAMV
gwWE1ChHecZwiyoSasdsNUg=
=BmXx
-----END PGP SIGNATURE-----

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: new syscall stub for ia64 linux
  2003-01-14  8:15   ` Ulrich Drepper
@ 2003-01-14 11:13     ` Jakub Jelinek
  0 siblings, 0 replies; 10+ messages in thread
From: Jakub Jelinek @ 2003-01-14 11:13 UTC (permalink / raw)
  To: Ulrich Drepper; +Cc: davidm, Glibc hackers

On Tue, Jan 14, 2003 at 08:15:02AM +0000, Ulrich Drepper wrote:
> This change makes no sense.  The initial comment about removing the
> union on ia64 is there because of the requirement that tp points a
> location containing the DTV pointer, followed by some other 8 bytes.
> I.e., the dtv pointer in the union is not necessary.
> 
> How and where the thread descriptor (not TCB in ia64 speak) is stored
> remains to be seen.  I haven't looked closely enough to see what Jakub did.

I left p_header as is on IA-64 because I did not want to conditionalize
all setters in the first phase.
It makes sense to have some kind of p_header at the end on DTV arches,
which need to contain at least multiple_threads and this sysinfo on IA-64.

	Jakub

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: new syscall stub for ia64 linux
  2003-01-14  7:28 ` new syscall stub for ia64 linux David Mosberger
  2003-01-14  8:15   ` Ulrich Drepper
@ 2003-01-18  6:27   ` David Mosberger
  2003-01-18  6:30     ` Ulrich Drepper
  1 sibling, 1 reply; 10+ messages in thread
From: David Mosberger @ 2003-01-18  6:27 UTC (permalink / raw)
  To: davidm; +Cc: Glibc hackers

I don't think anybody gave me feedback on this question:

>>>>> On Mon, 13 Jan 2003 23:28:30 -0800, David Mosberger <davidm@linux.hpl.hp.com> said:

  David> One rather ugly hack though is that in libc-start.c, I had to
  David> reverse the order of DL_SYSDEP_OSCHEC() and
  David> __pthread_initialize_minimal(): the former calls uname() and
  David> with the new syscall stub, the thread-pointer needs to be
  David> valid before a system call can be invoked.  If this isn't
  David> acceptable, suggestions for improvements would be welcome.

Is this an OK thing to do?

	--david

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: new syscall stub for ia64 linux
  2003-01-18  6:27   ` David Mosberger
@ 2003-01-18  6:30     ` Ulrich Drepper
  2003-01-18  7:52       ` David Mosberger
  0 siblings, 1 reply; 10+ messages in thread
From: Ulrich Drepper @ 2003-01-18  6:30 UTC (permalink / raw)
  To: davidm; +Cc: Glibc hackers

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

David Mosberger wrote:

> Is this an OK thing to do?

On x86 ld.so doesn't use the new syscall mechanism yet.  Once we have a
feature bitmap which is available through AT_SYSINFO the uname syscall
can go and we can use the new syscall stuff everywhere.  Do the same for
ia64 for now.

- -- 
- --------------.                        ,-.            444 Castro Street
Ulrich Drepper \    ,-----------------'   \ Mountain View, CA 94041 USA
Red Hat         `--' drepper at redhat.com `---------------------------
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.2.1 (GNU/Linux)

iD8DBQE+KPSS2ijCOnn/RHQRAiDxAJ9B4C/s39abz/KogCGmdCLz4kSoLwCgpv8A
VpRXSTdnHWnk7xvIQpxxPhQ=
=FkjX
-----END PGP SIGNATURE-----

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: new syscall stub for ia64 linux
  2003-01-18  6:30     ` Ulrich Drepper
@ 2003-01-18  7:52       ` David Mosberger
  2003-01-18  8:00         ` Ulrich Drepper
  0 siblings, 1 reply; 10+ messages in thread
From: David Mosberger @ 2003-01-18  7:52 UTC (permalink / raw)
  To: Ulrich Drepper; +Cc: davidm, Glibc hackers

>>>>> On Fri, 17 Jan 2003 22:30:37 -0800, Ulrich Drepper <drepper@redhat.com> said:

  Uli> -----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1

  Uli> David Mosberger wrote:

  >> Is this an OK thing to do?

  Uli> On x86 ld.so doesn't use the new syscall mechanism yet.  Once
  Uli> we have a feature bitmap which is available through AT_SYSINFO
  Uli> the uname syscall can go and we can use the new syscall stuff
  Uli> everywhere.  Do the same for ia64 for now.

I'm not sure I understand how this is supposed to work.  Do you mean
that a word in the AT_SYSINFO page would give you a feature-bitmap?
If so, how does that work with old kernels (where you don't get
AT_SYSINFO) at all, but you still need to know the kernel revision?

BTW: On ia64, the gate page that AT_SYSINFO points to is
"execute-only", so we can't read stuff directly off of it.  Of course
we could have a read-only page, but I don't see the point of wasting a
page given that we can now do (simple) syscalls in ~35 cycles.

	--david

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: new syscall stub for ia64 linux
  2003-01-18  7:52       ` David Mosberger
@ 2003-01-18  8:00         ` Ulrich Drepper
  0 siblings, 0 replies; 10+ messages in thread
From: Ulrich Drepper @ 2003-01-18  8:00 UTC (permalink / raw)
  To: davidm; +Cc: Glibc hackers

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

David Mosberger wrote:

> I'm not sure I understand how this is supposed to work.  Do you mean
> that a word in the AT_SYSINFO page would give you a feature-bitmap?

It will over time be more than a word but yes, that's the plan.


> If so, how does that work with old kernels (where you don't get
> AT_SYSINFO) at all, but you still need to know the kernel revision?

We'll see.  Perhaps the new syscall stuff won't be used in ld.so unless
you can assume at least a kernel version recent enough to support
AT_SYSINFO.


> BTW: On ia64, the gate page that AT_SYSINFO points to is
> "execute-only", so we can't read stuff directly off of it.

This is an architecture detail.  I cannot tell you more now since we
haven't yet reached an agreement with Linus.

- -- 
- --------------.                        ,-.            444 Castro Street
Ulrich Drepper \    ,-----------------'   \ Mountain View, CA 94041 USA
Red Hat         `--' drepper at redhat.com `---------------------------
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.2.1 (GNU/Linux)

iD8DBQE+KQmz2ijCOnn/RHQRAphbAJ92kgllxtc8BdeuCf6LmZs5yDgl4QCffwU1
gNIYbit16ZE1CvsfPNYleRc=
=/iL1
-----END PGP SIGNATURE-----

^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2003-01-18  8:00 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2003-01-13  4:59 [PATCH] IA-64 glibc TLS support Jakub Jelinek
2003-01-13  4:59 ` David Mosberger
2003-01-13  4:59 ` Ulrich Drepper
2003-01-14  7:28 ` new syscall stub for ia64 linux David Mosberger
2003-01-14  8:15   ` Ulrich Drepper
2003-01-14 11:13     ` Jakub Jelinek
2003-01-18  6:27   ` David Mosberger
2003-01-18  6:30     ` Ulrich Drepper
2003-01-18  7:52       ` David Mosberger
2003-01-18  8:00         ` Ulrich Drepper

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).