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] TLS support for s390*.


Hi Ulrich,
the following patch adds TLS support for s390 31-bit and 64-bit.

I had trouble with a test-case though. tst-tls9-static fails for 31
bit but succeeds for 64 bit. I debugged this (didn't want to sent
the patch with this odd behaviour) and found out that the test
case should fail for 64 bit as well !
tst-tls9-static does a dlopen on tst-tlsmod5.so which has a
DT_NEEDED for libc.so.6. For s390 the size of the TLS segment
of libc.so is 0x224 bytes. The surplus in the static TLS area
isn't big enough to dynamically load libc.so. It is initially set to
0x280 but the TCB alone has 0x200 bytes. Therefore it fails for
31 bit. The odd thing is that it succeeds on 64 bit. TLS segment
size of the 64 bit libc.so is 0x280, surplus is 0x2c0 bytes and the
TCB has 0x340 bytes. After some debugging it turned out that the
bug is in allocate_static_tls:

static bool
allocate_static_tls (struct link_map *map)
{
  size_t offset = roundup (GL(dl_tls_static_used), map->l_tls_align);
  if (offset + map->l_tls_blocksize > (GL(dl_tls_static_size)
# if TLS_TCB_AT_TP
                                       - TLS_TCB_SIZE
# elif TLS_DTV_AT_TP
  /* dl_tls_static_used includes the TCB at the beginning.  */
# else
#  error "Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined"
# endif
                                       ))
    return false;
  map->l_tls_offset = offset;
  GL(dl_tls_static_used) = offset + map->l_tls_blocksize;
  return true;
}

GL(dl_tls_static_size) has 0x2c0 bytes and TLS_TCB_SIZE has 0x340
bytes. The subtraction overflows and the result is something huge (all
numbers are unsigned). The TLS_TCB_SIZE should be added to the
left side of the comparison. This would make the tst-tls9-static test fail
for 64 bit as well which would be at least consistent with 31 bit.

That leaves the TLS ABI for s390 and the nptl patch. The ABI is done
from my point of view, the nptl patch will take some more time. Several
testcases still fail, the worst bug is a race condition in tst-fork1 I haven't
found yet.
What shall I do with the ABI and the nptl patch (after I found all the
remaining bugs)? Send them to the list or to you directly?

blue skies,
  Martin.

libc/ChangeLog:
2003-01-27  Martin Schwidefsky  <schwidefsky@de.ibm.com>

	* elf/elf.h: Add new s390 relocs.
	* elf/tls-macros.h: Add s390 versions.
	* sysdeps/s390/Versions [GLIBC_2.3] (ld): Export __tls_get_offset.
	* sysdeps/s390/dl-tls.h: New file.
	* sysdeps/s390/libc-tls.c: New file.
	* sysdeps/s390/s390-32/dl-machine.h (elf_machine_type_class): Add TLS
	relocs for class PLT.
	(elf_machine_rela): Handle TLS relocs.
	* sysdeps/s390/s390-64/dl-machine.h: Likewise.
	* sysdeps/s390/s390-32/elf/configure.in: Add TLS check.
	* sysdeps/s390/s390-64/elf/configure.in: Likewise.
	* sysdeps/s390/s390-32/elf/configure: Regenerate.
	* sysdeps/s390/s390-64/elf/configure: Likewise.
	* sysdeps/unix/sysv/linux/s390/s390-32/clone.S: Add support for
	CLONE_CHILD_*TID flags.
	* sysdeps/unix/sysv/linux/s390/s390-64/clone.S: Likewise.
	* sysdeps/unix/sysv/linux/s390/s390-64/mmap.S: Use branch with 32
	bit offset.
	* sysdeps/unix/sysv/linux/s390/s390-64/socket.S: Likewise.
	* sysdeps/unix/sysv/linux/s390/s390-64/syscall.S: Likewise.
	* sysdeps/unix/sysv/linux/s390/s390-32/sysdep.S (__syscall_error):
	Support USE___THREAD. Define RTLD_PRIVATE_ERRNO variant.
	* sysdeps/unix/sysv/linux/s390/s390-64/sysdep.S (__syscall_error):
	Likewise.
	* sysdeps/unix/sysv/linux/s390/s390-32/sysdep.h: 
	(SYSCALL_ERROR_LABEL): Move define next to SYSCALL_ERROR_HANDLER.
	(SYSCALL_ERROR_HANDLER): Add USE___THREAD and RTLD_PRIVATE_ERRNO
	variants.
	* sysdeps/unix/sysv/linux/s390/s390-64/sysdep.h: 
	(SYSCALL_ERROR_LABEL): Move define next to SYSCALL_ERROR_HANDLER. Use
	direct branch to syscall_error for !PIC and PIC && !_LIBC_REENTRANT.
	(SYSCALL_ERROR_HANDLER): Add USE___THREAD and RTLD_PRIVATE_ERRNO
	variants.

linuxthreads/ChangeLog:
2003-01-27  Martin Schwidefsky  <schwidefsky@de.ibm.com>

	* sysdeps/s390/s390-32/pt-machine.h (THREAD_SELF, INIT_THREAD_SELF):
	Define TLS versions.
	* sysdeps/s390/s390-64/pt-machine.h (THREAD_SELF, INIT_THREAD_SELF):
	Likewise.
	* sysdeps/s390/tls.h [HAVE_TLS_SUPPORT]	(USE_TLS, TLS_INIT_TCB_SIZE,
	TLS_INIT_TCB_ALIGN, TLS_TCB_SIZE, TLS_TCB_ALIGN, TLS_TCB_AT_TP,
	INSTALL_DTV, INSTALL_NEW_DTV, GET_DTV, TLS_INIT_TP, THREAD_DTV):
	Define.
	* sysdeps/unix/sysv/linux/s390/s390-64/sysdep-cancel.h (PSEUDO): Use
	branch with 32 bit offset.
	* sysdeps/unix/sysv/linux/s390/s390-64/vfork.S: Likewise.

diff -urN libc/elf/elf.h libc-s390/elf/elf.h
--- libc/elf/elf.h	Wed Dec 18 04:43:38 2002
+++ libc-s390/elf/elf.h	Sat Jan 25 18:15:17 2003
@@ -2228,36 +2228,83 @@
 
 /* Additional s390 relocs */
 
-#define R_390_NONE	0	       /* No reloc.  */
-#define R_390_8		1	       /* Direct 8 bit.	 */
-#define R_390_12	2	       /* Direct 12 bit.  */
-#define R_390_16	3	       /* Direct 16 bit.  */
-#define R_390_32	4	       /* Direct 32 bit.  */
-#define R_390_PC32	5	       /* PC relative 32 bit.  */
-#define R_390_GOT12	6	       /* 12 bit GOT offset.  */
-#define R_390_GOT32	7	       /* 32 bit GOT offset.  */
-#define R_390_PLT32	8	       /* 32 bit PC relative PLT address.  */
-#define R_390_COPY	9	       /* Copy symbol at runtime.  */
-#define R_390_GLOB_DAT	10	       /* Create GOT entry.  */
-#define R_390_JMP_SLOT	11	       /* Create PLT entry.  */
-#define R_390_RELATIVE	12	       /* Adjust by program base.  */
-#define R_390_GOTOFF	13	       /* 32 bit offset to GOT.	 */
-#define R_390_GOTPC	14	       /* 32 bit PC relative offset to GOT.  */
-#define R_390_GOT16	15	       /* 16 bit GOT offset.  */
-#define R_390_PC16	16	       /* PC relative 16 bit.  */
-#define R_390_PC16DBL	17	       /* PC relative 16 bit shifted by 1.  */
-#define R_390_PLT16DBL	18	       /* 16 bit PC rel. PLT shifted by 1.  */
-#define R_390_PC32DBL	19	       /* PC relative 32 bit shifted by 1.  */
-#define R_390_PLT32DBL	20	       /* 32 bit PC rel. PLT shifted by 1.  */
-#define R_390_GOTPCDBL	21	       /* 32 bit PC rel. GOT shifted by 1.  */
-#define R_390_64	22	       /* Direct 64 bit.  */
-#define R_390_PC64	23	       /* PC relative 64 bit.  */
-#define R_390_GOT64	24	       /* 64 bit GOT offset.  */
-#define R_390_PLT64	25	       /* 64 bit PC relative PLT address.  */
-#define R_390_GOTENT	26	       /* 32 bit PC rel. to GOT entry >> 1. */
+#define R_390_NONE		0	/* No reloc.  */
+#define R_390_8			1	/* Direct 8 bit.  */
+#define R_390_12		2	/* Direct 12 bit.  */
+#define R_390_16		3	/* Direct 16 bit.  */
+#define R_390_32		4	/* Direct 32 bit.  */
+#define R_390_PC32		5	/* PC relative 32 bit.	*/
+#define R_390_GOT12		6	/* 12 bit GOT offset.  */
+#define R_390_GOT32		7	/* 32 bit GOT offset.  */
+#define R_390_PLT32		8	/* 32 bit PC relative PLT address.  */
+#define R_390_COPY		9	/* Copy symbol at runtime.  */
+#define R_390_GLOB_DAT		10	/* Create GOT entry.  */
+#define R_390_JMP_SLOT		11	/* Create PLT entry.  */
+#define R_390_RELATIVE		12	/* Adjust by program base.  */
+#define R_390_GOTOFF32		13	/* 32 bit offset to GOT.	 */
+#define R_390_GOTPC		14	/* 32 bit PC relative offset to GOT.  */
+#define R_390_GOT16		15	/* 16 bit GOT offset.  */
+#define R_390_PC16		16	/* PC relative 16 bit.	*/
+#define R_390_PC16DBL		17	/* PC relative 16 bit shifted by 1.  */
+#define R_390_PLT16DBL		18	/* 16 bit PC rel. PLT shifted by 1.  */
+#define R_390_PC32DBL		19	/* PC relative 32 bit shifted by 1.  */
+#define R_390_PLT32DBL		20	/* 32 bit PC rel. PLT shifted by 1.  */
+#define R_390_GOTPCDBL		21	/* 32 bit PC rel. GOT shifted by 1.  */
+#define R_390_64		22	/* Direct 64 bit.  */
+#define R_390_PC64		23	/* PC relative 64 bit.	*/
+#define R_390_GOT64		24	/* 64 bit GOT offset.  */
+#define R_390_PLT64		25	/* 64 bit PC relative PLT address.  */
+#define R_390_GOTENT		26	/* 32 bit PC rel. to GOT entry >> 1. */
+#define R_390_GOTOFF16		27	/* 16 bit offset to GOT. */
+#define R_390_GOTOFF64		28	/* 64 bit offset to GOT. */
+#define R_390_GOTPLT12		29	/* 12 bit offset to jump slot.	*/
+#define R_390_GOTPLT16		30	/* 16 bit offset to jump slot.	*/
+#define R_390_GOTPLT32		31	/* 32 bit offset to jump slot.	*/
+#define R_390_GOTPLT64		32	/* 64 bit offset to jump slot.	*/
+#define R_390_GOTPLTENT		33	/* 32 bit rel. offset to jump slot.  */
+#define R_390_PLTOFF16		34	/* 16 bit offset from GOT to PLT. */
+#define R_390_PLTOFF32		35	/* 32 bit offset from GOT to PLT. */
+#define R_390_PLTOFF64		36	/* 16 bit offset from GOT to PLT. */
+#define R_390_TLS_LOAD		37	/* Tag for load insn in TLS code.  */
+#define R_390_TLS_GDCALL	38	/* Tag for function call in general
+					   dynamic TLS code. */
+#define R_390_TLS_LDCALL	39	/* Tag for function call in local
+					   dynamic TLS code. */
+#define R_390_TLS_GD32		40	/* Direct 32 bit for general dynamic
+					   thread local data.  */
+#define R_390_TLS_GD64		41	/* Direct 64 bit for general dynamic
+					  thread local data.  */
+#define R_390_TLS_GOTIE12	42	/* 12 bit GOT offset for static TLS
+					   block offset.  */
+#define R_390_TLS_GOTIE32	43	/* 32 bit GOT offset for static TLS
+					   block offset.  */
+#define R_390_TLS_GOTIE64	44	/* 64 bit GOT offset for static TLS
+					   block offset. */
+#define R_390_TLS_LDM32		45	/* Direct 32 bit for local dynamic
+					   thread local data in LE code.  */
+#define R_390_TLS_LDM64		46	/* Direct 64 bit for local dynamic
+					   thread local data in LE code.  */
+#define R_390_TLS_IE32		47	/* 32 bit address of GOT entry for
+					   negated static TLS block offset.  */
+#define R_390_TLS_IE64		48	/* 64 bit address of GOT entry for
+					   negated static TLS block offset.  */
+#define R_390_TLS_IEENT		49	/* 32 bit rel. offset to GOT entry for
+					   negated static TLS block offset.  */
+#define R_390_TLS_LE32		50	/* 32 bit negated offset relative to
+					   static TLS block.  */
+#define R_390_TLS_LE64		51	/* 64 bit negated offset relative to
+					   static TLS block.  */
+#define R_390_TLS_LDO32		52	/* 32 bit offset relative to TLS
+					   block.  */
+#define R_390_TLS_LDO64		53	/* 64 bit offset relative to TLS
+					   block.  */
+#define R_390_TLS_DTPMOD	54	/* ID of module containing symbol.  */
+#define R_390_TLS_DTPOFF	55	/* Offset in TLS block.	 */
+#define R_390_TLS_TPOFF		56	/* Negated offset in static TLS
+					   block.  */
 
 /* Keep this the last entry.  */
-#define R_390_NUM	27
+#define R_390_NUM		57
 
 /* CRIS relocations.  */
 #define R_CRIS_NONE		0
diff -urN libc/elf/tls-macros.h libc-s390/elf/tls-macros.h
--- libc/elf/tls-macros.h	Mon Jan 13 10:33:08 2003
+++ libc-s390/elf/tls-macros.h	Sat Jan 25 18:15:17 2003
@@ -298,6 +298,196 @@
           : "=r" (__l) : : "loc0", __TLS_CALL_CLOBBERS);		      \
      __l; })
 
+#elif defined __s390x__
+
+# define TLS_LE(x) \
+  ({ unsigned long __offset;						      \
+     asm ("bras %0,1f\n"						      \
+	  "0:\t.quad " #x "@ntpoff\n"					      \
+	  "1:\tlg %0,0(%0)"						      \
+	  : "=a" (__offset) : : "cc" );					      \
+     (int *) (__builtin_thread_pointer() + __offset); })
+
+# ifdef PIC
+#  define TLS_IE(x) \
+  ({ unsigned long __offset;						      \
+     asm ("bras %0,1f\n"						      \
+	  "0:\t.quad " #x "@gotntpoff\n"				      \
+	  "1:\tlg %0,0(%0)\n\t"						      \
+	  "lg %0,0(%0,%%r12):tls_load:" #x				      \
+	  : "=&a" (__offset) : : "cc" );				      \
+     (int *) (__builtin_thread_pointer() + __offset); })
+# else
+#  define TLS_IE(x) \
+  ({ unsigned long  __offset;						      \
+     asm ("bras %0,1f\n"						      \
+	  "0:\t.quad " #x "@indntpoff\n"				      \
+	  "1:\t lg %0,0(%0)\n\t"					      \
+	  "lg %0,0(%0):tls_load:" #x					      \
+	  : "=&a" (__offset) : : "cc" );				      \
+     (int *) (__builtin_thread_pointer() + __offset); })
+# endif
+
+# ifdef PIC
+#  define TLS_LD(x) \
+  ({ unsigned long __offset, __save12;					      \
+     asm ("bras %0,1f\n"						      \
+	  "0:\t.quad " #x "@tlsldm\n\t"					      \
+	  ".quad " #x "@dtpoff\n"					      \
+	  "1:\tlgr %1,%%r12\n\t"					      \
+          "larl %%r12,_GLOBAL_OFFSET_TABLE_\n\t"			      \
+          "lg %%r2,0(%0)\n\t"						      \
+	  "brasl %%r14,__tls_get_offset@plt:tls_ldcall:" #x "\n\t"	      \
+	  "lg %0,8(%0)\n\t"						      \
+	  "algr %0,%%r2\n\t"						      \
+          "lgr %%r12,%1"						      \
+	  : "=&a" (__offset), "=&a" (__save12)				      \
+          : : "cc", "0", "1", "2", "3", "4", "5" );			      \
+     (int *) (__builtin_thread_pointer() + __offset); })
+# else
+#  define TLS_LD(x) \
+  ({ unsigned long __offset;						      \
+     asm ("bras %0,1f\n"						      \
+	  "0:\t.quad " #x "@tlsldm\n\t"					      \
+	  ".quad " #x "@dtpoff\n"					      \
+	  "1:\tlarl %%r12,_GLOBAL_OFFSET_TABLE_\n\t"			      \
+          "lg %%r2,0(%0)\n\t"						      \
+	  "brasl %%r14,__tls_get_offset@plt:tls_ldcall:" #x "\n\t"	      \
+	  "lg %0,8(%0)\n\t"						      \
+	  "algr %0,%%r2"						      \
+	  : "=&a" (__offset) : : "cc", "0", "1", "2", "3", "4", "5", "12" );  \
+     (int *) (__builtin_thread_pointer() + __offset); })
+# endif
+
+# ifdef PIC
+#  define TLS_GD(x) \
+  ({ unsigned long __offset, __save12;					      \
+     asm ("bras %0,1f\n"						      \
+	  "0:\t.quad " #x "@tlsgd\n"					      \
+	  "1:\tlgr %1,%%r12\n\t"					      \
+	  "larl %%r12,_GLOBAL_OFFSET_TABLE_\n\t"			      \
+          "lg %%r2,0(%0)\n\t"						      \
+	  "brasl %%r14,__tls_get_offset@plt:tls_gdcall:" #x "\n\t"	      \
+          "lgr %0,%%r2\n\t"						      \
+          "lgr %%r12,%1"						      \
+	  : "=&a" (__offset), "=&a" (__save12)				      \
+          : : "cc", "0", "1", "2", "3", "4", "5" );			      \
+     (int *) (__builtin_thread_pointer() + __offset); })
+# else
+#  define TLS_GD(x) \
+  ({ unsigned long __offset;						      \
+     asm ("bras %0,1f\n"						      \
+	  "0:\t.quad " #x "@tlsgd\n"					      \
+	  "1:\tlarl %%r12,_GLOBAL_OFFSET_TABLE_\n\t"			      \
+	  "lg %%r2,0(%0)\n\t"						      \
+	  "brasl %%r14,__tls_get_offset@plt:tls_gdcall:" #x "\n\t"	      \
+          "lgr %0,%%r2"							      \
+	  : "=&a" (__offset) : : "cc", "0", "1", "2", "3", "4", "5", "12" );  \
+     (int *) (__builtin_thread_pointer() + __offset); })
+# endif
+
+#elif defined __s390__
+
+# define TLS_LE(x) \
+  ({ unsigned long __offset;						      \
+     asm ("bras %0,1f\n"						      \
+	  "0:\t.long " #x "@ntpoff\n"					      \
+	  "1:\tl %0,0(%0)"						      \
+	  : "=a" (__offset) : : "cc" );					      \
+     (int *) (__builtin_thread_pointer() + __offset); })
+
+# ifdef PIC
+#  define TLS_IE(x) \
+  ({ unsigned long __offset;						      \
+     asm ("bras %0,1f\n"						      \
+	  "0:\t.long " #x "@gotntpoff\n"				      \
+	  "1:\tl %0,0(%0)\n\t"						      \
+	  "l %0,0(%0,%%r12):tls_load:" #x				      \
+	  : "=&a" (__offset) : : "cc" );				      \
+     (int *) (__builtin_thread_pointer() + __offset); })
+# else
+#  define TLS_IE(x) \
+  ({ unsigned long  __offset;						      \
+     asm ("bras %0,1f\n"						      \
+	  "0:\t.long " #x "@indntpoff\n"				      \
+	  "1:\t l %0,0(%0)\n\t"						      \
+	  "l %0,0(%0):tls_load:" #x					      \
+	  : "=&a" (__offset) : : "cc" );				      \
+     (int *) (__builtin_thread_pointer() + __offset); })
+# endif
+
+# ifdef PIC
+#  define TLS_LD(x) \
+  ({ unsigned long __offset, __save12;					      \
+     asm ("bras %0,1f\n"						      \
+	  "0:\t.long _GLOBAL_OFFSET_TABLE_-0b\n\t"			      \
+	  ".long __tls_get_offset@plt-0b\n\t"				      \
+	  ".long " #x "@tlsldm\n\t"					      \
+	  ".long " #x "@dtpoff\n"					      \
+	  "1:\tlr %1,%%r12\n\t"						      \
+          "l %%r12,0(%0)\n\t"						      \
+          "la %%r12,0(%%r12,%0)\n\t"					      \
+	  "l %%r1,4(%0)\n\t"						      \
+	  "l %%r2,8(%0)\n\t"						      \
+	  "bas %%r14,0(%%r1,%0):tls_ldcall:" #x "\n\t"			      \
+	  "l %0,12(%0)\n\t"						      \
+	  "alr %0,%%r2\n\t"						      \
+          "lr %%r12,%1"							      \
+	  : "=&a" (__offset), "=&a" (__save12)				      \
+          : : "cc", "0", "1", "2", "3", "4", "5" );			      \
+     (int *) (__builtin_thread_pointer() + __offset); })
+# else
+#  define TLS_LD(x) \
+  ({ unsigned long __offset;						      \
+     asm ("bras %0,1f\n"						      \
+	  "0:\t.long _GLOBAL_OFFSET_TABLE_\n\t"				      \
+	  ".long __tls_get_offset@plt\n\t"				      \
+	  ".long " #x "@tlsldm\n\t"					      \
+	  ".long " #x "@dtpoff\n"					      \
+	  "1:\tl %%r12,0(%0)\n\t"					      \
+	  "l %%r1,4(%0)\n\t"						      \
+	  "l %%r2,8(%0)\n\t"						      \
+	  "bas %%r14,0(%%r1):tls_ldcall:" #x "\n\t"			      \
+	  "l %0,12(%0)\n\t"						      \
+	  "alr %0,%%r2"							      \
+	  : "=&a" (__offset) : : "cc", "0", "1", "2", "3", "4", "5", "12" );  \
+     (int *) (__builtin_thread_pointer() + __offset); })
+# endif
+
+# ifdef PIC
+#  define TLS_GD(x) \
+  ({ unsigned long __offset, __save12;					      \
+     asm ("bras %0,1f\n"						      \
+	  "0:\t.long _GLOBAL_OFFSET_TABLE_-0b\n\t"			      \
+	  ".long __tls_get_offset@plt-0b\n\t"				      \
+	  ".long " #x "@tlsgd\n"					      \
+	  "1:\tlr %1,%%r12\n\t"						      \
+          "l %%r12,0(%0)\n\t"						      \
+          "la %%r12,0(%%r12,%0)\n\t"					      \
+	  "l %%r1,4(%0)\n\t"						      \
+	  "l %%r2,8(%0)\n\t"						      \
+	  "bas %%r14,0(%%r1,%0):tls_gdcall:" #x "\n\t"			      \
+          "lr %0,%%r2\n\t"						      \
+          "lr %%r12,%1"							      \
+	  : "=&a" (__offset), "=&a" (__save12)				      \
+          : : "cc", "0", "1", "2", "3", "4", "5" );			      \
+     (int *) (__builtin_thread_pointer() + __offset); })
+# else
+#  define TLS_GD(x) \
+  ({ unsigned long __offset;						      \
+     asm ("bras %0,1f\n"						      \
+	  "0:\t.long _GLOBAL_OFFSET_TABLE_\n\t"				      \
+	  ".long __tls_get_offset@plt\n\t"				      \
+	  ".long " #x "@tlsgd\n"					      \
+	  "1:\tl %%r12,0(%0)\n\t"					      \
+	  "l %%r1,4(%0)\n\t"						      \
+	  "l %%r2,8(%0)\n\t"						      \
+	  "bas %%r14,0(%%r1):tls_gdcall:" #x "\n\t"			      \
+          "lr %0,%%r2"							      \
+	  : "=&a" (__offset) : : "cc", "0", "1", "2", "3", "4", "5", "12" );  \
+     (int *) (__builtin_thread_pointer() + __offset); })
+# endif
+
 #else
 # error "No support for this architecture so far."
 #endif
diff -urN libc/linuxthreads/sysdeps/s390/s390-32/pt-machine.h libc-s390/linuxthreads/sysdeps/s390/s390-32/pt-machine.h
--- libc/linuxthreads/sysdeps/s390/s390-32/pt-machine.h	Tue Aug 27 00:39:54 2002
+++ libc-s390/linuxthreads/sysdeps/s390/s390-32/pt-machine.h	Sat Jan 25 18:15:17 2003
@@ -58,6 +58,13 @@
 #define CURRENT_STACK_FRAME  stack_pointer
 register char * stack_pointer __asm__ ("15");
 
+#ifdef USE_TLS
+/* Return the thread descriptor for the current thread.  */
+# define THREAD_SELF ((pthread_descr) __builtin_thread_pointer ())
+
+/* Initialize the thread-unique value.  */
+#define INIT_THREAD_SELF(descr, nr) __builtin_set_thread_pointer (descr)
+#else
 /* Return the thread descriptor for the current thread.
    S/390 registers uses access register 0 as "thread register".  */
 #define THREAD_SELF  ({                                                       \
@@ -70,6 +77,7 @@
 #define INIT_THREAD_SELF(descr, nr)  ({                                       \
   __asm__ ("sar %%a0,%0" : : "d" (descr) );                                   \
 })
+#endif
 
 /* Access to data in the thread descriptor is easy.  */
 #define THREAD_GETMEM(descr, member) THREAD_SELF->member
diff -urN libc/linuxthreads/sysdeps/s390/s390-64/pt-machine.h libc-s390/linuxthreads/sysdeps/s390/s390-64/pt-machine.h
--- libc/linuxthreads/sysdeps/s390/s390-64/pt-machine.h	Tue Aug 27 00:39:43 2002
+++ libc-s390/linuxthreads/sysdeps/s390/s390-64/pt-machine.h	Sat Jan 25 18:15:17 2003
@@ -58,6 +58,13 @@
 #define CURRENT_STACK_FRAME  stack_pointer
 register char * stack_pointer __asm__ ("15");
 
+#ifdef USE_TLS
+/* Return the thread descriptor for the current thread.  */
+# define THREAD_SELF ((pthread_descr) __builtin_thread_pointer ())
+
+/* Initialize the thread-unique value.  */
+#define INIT_THREAD_SELF(descr, nr) __builtin_set_thread_pointer (descr)
+#else
 /* Return the thread descriptor for the current thread.
    64 bit S/390 uses access register 0 and 1 as "thread register".  */
 #define THREAD_SELF  ({                                                       \
@@ -76,6 +83,7 @@
            "   sar  %%a0,0\n"                                                 \
            : : "d" (descr) : "0" );                                           \
 })
+#endif
 
 /* Access to data in the thread descriptor is easy.  */
 #define THREAD_GETMEM(descr, member) THREAD_SELF->member
diff -urN libc/linuxthreads/sysdeps/s390/tls.h libc-s390/linuxthreads/sysdeps/s390/tls.h
--- libc/linuxthreads/sysdeps/s390/tls.h	Sun Jan  5 06:10:50 2003
+++ libc-s390/linuxthreads/sysdeps/s390/tls.h	Sat Jan 25 18:15:17 2003
@@ -45,19 +45,99 @@
 # include <tcb-offsets.h>
 #endif /* __ASSEMBLER__ */
 
-#undef USE_TLS
+/* We can support TLS only if the floating-stack support is available.
+   However, we want to compile in the support and test at runtime whether
+   the running kernel can support it or not.  To avoid bothering with the
+   TLS support code at all, use configure --without-tls.
 
-#if USE_TLS
+   We need USE_TLS to be consistently defined, for ldsodefs.h conditionals.
+   But some of the code below can cause problems in building libpthread
+   (e.g. useldt.h will defined FLOATING_STACKS when it shouldn't).  */
 
-#else
+#if defined HAVE_TLS_SUPPORT \
+    && (defined FLOATING_STACKS || !defined IS_IN_libpthread)
 
-#define NONTLS_INIT_TP \
+/* Signal that TLS support is available.  */
+# define USE_TLS	1
+
+# ifndef __ASSEMBLER__
+/* Get system call information.  */
+#  include <sysdep.h>
+
+
+/* Get the thread descriptor definition.  */
+#  include <linuxthreads/descr.h>
+
+/* This is the size of the initial TCB.  */
+#  define TLS_INIT_TCB_SIZE sizeof (tcbhead_t)
+
+/* Alignment requirements for the initial TCB.  */
+#  define TLS_INIT_TCB_ALIGN __alignof__ (tcbhead_t)
+
+/* This is the size of the TCB.  */
+#  define TLS_TCB_SIZE sizeof (struct _pthread_descr_struct)
+
+/* Alignment requirements for the TCB.  */
+#  define TLS_TCB_ALIGN __alignof__ (struct _pthread_descr_struct)
+
+/* The TCB can have any size and the memory following the address the
+   thread pointer points to is unspecified.  Allocate the TCB there.  */
+#  define TLS_TCB_AT_TP	1
+
+
+/* Install the dtv pointer.  The pointer passed is to the element with
+   index -1 which contain the length.  */
+#  define INSTALL_DTV(descr, dtvp) \
+  ((tcbhead_t *) (descr))->dtv = (dtvp) + 1
+
+/* Install new dtv for current thread.  */
+#  define INSTALL_NEW_DTV(dtv) \
+  (((tcbhead_t *) __builtin_thread_pointer ())->dtv = (dtv))
+
+/* Return dtv of given thread descriptor.  */
+#  define GET_DTV(descr) \
+  (((tcbhead_t *) (descr))->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.
+
+   The value of this macro is null if successful, or an error string.  */
+#  define TLS_INIT_TP(descr, secondcall)				      \
+  ({									      \
+    void *_descr = (descr);						      \
+    tcbhead_t *head = _descr;						      \
+									      \
+    head->tcb = _descr;							      \
+    /* For now the thread descriptor is at the same address.  */	      \
+    head->self = _descr;						      \
+									      \
+    __builtin_set_thread_pointer (_descr);				      \
+    0;									      \
+  })
+
+/* Return the address of the dtv for the current thread.  */
+#  define THREAD_DTV() \
+  (((tcbhead_t *) __builtin_thread_pointer ())->dtv)
+
+# endif /* __ASSEMBLER__ */
+
+#else	/* HAVE_TLS_SUPPORT && (FLOATING_STACKS || !IS_IN_libpthread) */
+
+# ifndef __ASSEMBLER__
+
+/* Get the thread descriptor definition.  */
+#  include <linuxthreads/descr.h>
+
+#  define NONTLS_INIT_TP \
   do { 								\
     static const tcbhead_t nontls_init_tp			\
       = { .multiple_threads = 0 };				\
     INIT_THREAD_SELF (&nontls_init_tp, 0);			\
   } while (0)
 
-#endif /* USE_TLS */
+# endif /* __ASSEMBLER__ */
+
+#endif	/* HAVE_TLS_SUPPORT && (FLOATING_STACKS || !IS_IN_libpthread) */
 
 #endif	/* tls.h */
diff -urN libc/linuxthreads/sysdeps/unix/sysv/linux/s390/s390-64/sysdep-cancel.h libc-s390/linuxthreads/sysdeps/unix/sysv/linux/s390/s390-64/sysdep-cancel.h
--- libc/linuxthreads/sysdeps/unix/sysv/linux/s390/s390-64/sysdep-cancel.h	Tue Jan 14 09:52:46 2003
+++ libc-s390/linuxthreads/sysdeps/unix/sysv/linux/s390/s390-64/sysdep-cancel.h	Sat Jan 25 18:15:17 2003
@@ -51,7 +51,7 @@
 L(pseudo_check):							      \
 	lghi	%r4,-4095;						      \
 	clgr	%r2,%r4;						      \
-	jnl	SYSCALL_ERROR_LABEL;					      \
+	jgnl	SYSCALL_ERROR_LABEL;					      \
 L(pseudo_end):
 
 # ifdef IS_IN_libpthread
diff -urN libc/linuxthreads/sysdeps/unix/sysv/linux/s390/s390-64/vfork.S libc-s390/linuxthreads/sysdeps/unix/sysv/linux/s390/s390-64/vfork.S
--- libc/linuxthreads/sysdeps/unix/sysv/linux/s390/s390-64/vfork.S	Sun Jan 12 23:58:37 2003
+++ libc-s390/linuxthreads/sysdeps/unix/sysv/linux/s390/s390-64/vfork.S	Sat Jan 25 18:15:17 2003
@@ -36,7 +36,7 @@
 	/* Check for error.  */
 	lghi	%r4,-4095
 	clgr	%r2,%r4
-	jnl	SYSCALL_ERROR_LABEL
+	jgnl	SYSCALL_ERROR_LABEL
 
 	/* Normal return.  */
 	br	%r14
diff -urN libc/sysdeps/s390/Versions libc-s390/sysdeps/s390/Versions
--- libc/sysdeps/s390/Versions	Thu Jan  1 01:00:00 1970
+++ libc-s390/sysdeps/s390/Versions	Sat Jan 25 18:15:17 2003
@@ -0,0 +1,6 @@
+ld {
+  GLIBC_2.3 {
+    # runtime interface to TLS
+    __tls_get_offset;
+  }
+}
\ No newline at end of file
diff -urN libc/sysdeps/s390/dl-tls.h libc-s390/sysdeps/s390/dl-tls.h
--- libc/sysdeps/s390/dl-tls.h	Thu Jan  1 01:00:00 1970
+++ libc-s390/sysdeps/s390/dl-tls.h	Sat Jan 25 18:15:17 2003
@@ -0,0 +1,73 @@
+/* Thread-local storage handling in the ELF dynamic linker.  s390 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.  */
+
+
+/* Type used for the representation of TLS information in the GOT.  */
+typedef struct
+{
+  unsigned long int ti_module;
+  unsigned long int ti_offset;
+} tls_index;
+
+
+#ifdef SHARED
+/* This is the prototype for the GNU version.  */
+extern void *__tls_get_addr (tls_index *ti) attribute_hidden;
+extern unsigned long __tls_get_offset (unsigned long got_offset);
+
+/* The special thing about the s390 TLS ABI is that we do not have the
+   standard __tls_get_addr function but the __tls_get_offset function
+   which differs in two important aspects:
+   1) __tls_get_offset gets a got offset instead of a pointer to the
+      tls_index structure
+   2) __tls_get_offset returns the offset of the requested variable to
+      the thread descriptor instead of a pointer to the variable.
+ */
+#if defined __s390x__
+asm("\n\
+	.text\n\
+	.globl __tls_get_offset\n\
+	.type __tls_get_offset, @function\n\
+	.align 4\n\
+__tls_get_offset:\n\
+	la	%r2,0(%r2,%r12)\n\
+	jg	__tls_get_addr\n\
+");
+#elif defined __s390__
+asm("\n\
+	.text\n\
+	.globl __tls_get_offset\n\
+	.type __tls_get_offset, @function\n\
+	.align 4\n\
+__tls_get_offset:\n\
+	basr	%r3,0\n\
+0:	la	%r2,0(%r2,%r12)\n\
+	l	%r4,1f-0b(%r3)\n\
+	b	0(%r4,%r3)\n\
+1:	.long	__tls_get_addr - 0b\n\
+");
+#endif
+
+#define GET_ADDR_OFFSET \
+  (ti->ti_offset - (unsigned long) __builtin_thread_pointer ())
+
+#define __TLS_GET_ADDR(__ti) \
+  (__tls_get_addr(__ti) + (unsigned long) __builtin_thread_pointer ())
+
+#endif
diff -urN libc/sysdeps/s390/libc-tls.c libc-s390/sysdeps/s390/libc-tls.c
--- libc/sysdeps/s390/libc-tls.c	Thu Jan  1 01:00:00 1970
+++ libc-s390/sysdeps/s390/libc-tls.c	Sat Jan 25 18:15:17 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 s390, the literal pool entry that refers to __tls_get_offset
+   is not removed, even if all branches that use the literal pool
+   entry gets removed by TLS optimizations. To get binaries
+   statically linked __tls_get_offset is defined here but
+   aborts if it is used.  */
+
+void *
+__tls_get_offset (size_t m, size_t offset)
+{
+  abort ();
+}
+
+#endif
+
diff -urN libc/sysdeps/s390/s390-32/dl-machine.h libc-s390/sysdeps/s390/s390-32/dl-machine.h
--- libc/sysdeps/s390/s390-32/dl-machine.h	Fri Mar  1 10:43:37 2002
+++ libc-s390/sysdeps/s390/s390-32/dl-machine.h	Sat Jan 25 18:15:17 2003
@@ -312,13 +312,22 @@
 #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.  */
-#define elf_machine_type_class(type) \
+#ifdef USE_TLS
+# define elf_machine_type_class(type) \
+  ((((type) == R_390_JMP_SLOT || (type) == R_390_TLS_DTPMOD		      \
+     || (type) == R_390_TLS_DTPOFF || (type) == R_390_TLS_TPOFF)	      \
+    * ELF_RTYPE_CLASS_PLT)						      \
+   | (((type) == R_390_COPY) * ELF_RTYPE_CLASS_COPY))
+#else
+# define elf_machine_type_class(type) \
   ((((type) == R_390_JMP_SLOT) * ELF_RTYPE_CLASS_PLT)	\
    | (((type) == R_390_COPY) * ELF_RTYPE_CLASS_COPY))
+#endif
 
 /* A reloc type used for ld.so cmdline arg lookups to reject PLT entries.  */
 #define ELF_MACHINE_JMP_SLOT    R_390_JMP_SLOT
@@ -372,25 +381,90 @@
 {
   const unsigned int r_type = ELF32_R_TYPE (reloc->r_info);
 
+#if !defined RTLD_BOOTSTRAP || !defined HAVE_Z_COMBRELOC
   if (__builtin_expect (r_type == R_390_RELATIVE, 0))
-    *reloc_addr = map->l_addr + reloc->r_addend;
-#ifndef RTLD_BOOTSTRAP
-  else if (__builtin_expect (r_type == R_390_NONE, 0))
-    return;
+    {
+# if !defined RTLD_BOOTSTRAP && !defined HAVE_Z_COMBRELOC
+      /* This is defined in rtld.c, but nowhere in the static libc.a;
+	 make the reference weak so static programs can still link.
+	 This declaration cannot be done when compiling rtld.c
+	 (i.e. #ifdef RTLD_BOOTSTRAP) because rtld.c contains the
+	 common defn for _dl_rtld_map, which is incompatible with a
+	 weak decl in the same file.  */
+#  ifndef SHARED
+      weak_extern (GL(dl_rtld_map));
+#  endif
+      if (map != &GL(dl_rtld_map)) /* Already done in rtld itself.  */
+# endif
+	*reloc_addr = map->l_addr + reloc->r_addend;
+    }
+  else
 #endif
+  if (__builtin_expect (r_type == R_390_NONE, 0))
+    return;
   else
     {
       const Elf32_Sym *const refsym = sym;
+#if defined USE_TLS && !defined RTLD_BOOTSTRAP
+      struct link_map *sym_map = RESOLVE_MAP (&sym, version, r_type);
+      Elf32_Addr value = sym == NULL ? 0 : sym_map->l_addr + sym->st_value;
+#else
       Elf32_Addr value = RESOLVE (&sym, version, r_type);
+
+# ifndef RTLD_BOOTSTRAP
       if (sym)
+# endif
 	value += sym->st_value;
+#endif /* use TLS and !RTLD_BOOTSTRAP */
 
       switch (r_type)
 	{
 	case R_390_GLOB_DAT:
 	case R_390_JMP_SLOT:
-	  *reloc_addr = value;
+	  *reloc_addr = value + reloc->r_addend;
 	  break;
+
+#if defined USE_TLS && (!defined RTLD_BOOTSTRAP || USE___THREAD)
+	case R_390_TLS_DTPMOD:
+# ifdef RTLD_BOOTSTRAP
+	  /* During startup the dynamic linker is always the module
+	     with index 1.
+	     XXX If this relocation is necessary move before RESOLVE
+	     call.  */
+	  *reloc_addr = 1;
+# else
+	  /* Get the information from the link map returned by the
+	     resolv function.  */
+	  if (sym_map != NULL)
+	    *reloc_addr = sym_map->l_tls_modid;
+# endif
+	  break;
+	case R_390_TLS_DTPOFF:
+# ifndef RTLD_BOOTSTRAP
+	  /* During relocation all TLS symbols are defined and used.
+	     Therefore the offset is already correct.  */
+	  if (sym != NULL)
+	    *reloc_addr = sym->st_value + reloc->r_addend;
+# endif
+	  break;
+	case R_390_TLS_TPOFF:
+	  /* The offset is negative, forward from the thread pointer.  */
+# ifdef RTLD_BOOTSTRAP
+	  *reloc_addr = sym->st_value + reloc->r_addend - map->l_tls_offset;
+# else
+	  /* We know the offset of the object the symbol is contained in.
+	     It is a negative value which will be added to the
+	     thread pointer.  */
+	  if (sym != NULL)
+	    {
+	      *reloc_addr = (sym->st_value + reloc->r_addend
+			     - sym_map->l_tls_offset);
+	      CHECK_STATIC_TLS (map, sym_map);
+	    }
+#endif
+	  break;
+#endif  /* use TLS */
+
 #ifndef RTLD_BOOTSTRAP
 	case R_390_COPY:
 	  if (sym == NULL)
diff -urN libc/sysdeps/s390/s390-32/elf/configure libc-s390/sysdeps/s390/s390-32/elf/configure
--- libc/sysdeps/s390/s390-32/elf/configure	Thu Jan  1 01:00:00 1970
+++ libc-s390/sysdeps/s390/s390-32/elf/configure	Sat Jan 25 18:15:17 2003
@@ -0,0 +1,52 @@
+# This file is generated from configure.in by Autoconf.  DO NOT EDIT!
+ # Local configure fragment for sysdeps/s390/elf.
+
+if test "$usetls" != no; then
+# Check for support of thread-local storage handling in assembler and
+# linker.
+echo "$as_me:$LINENO: checking for s390 TLS support" >&5
+echo $ECHO_N "checking for s390 TLS support... $ECHO_C" >&6
+if test "${libc_cv_390_tls+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat > conftest.s <<\EOF
+	.section ".tdata", "awT", @progbits
+foo:	.long	25
+	.text
+	.long	foo@TLSGD
+	.long	foo@TLSLDM
+	.long	foo@DTPOFF
+	.long	foo@NTPOFF
+	.long	foo@GOTNTPOFF
+	.long	foo@INDNTPOFF
+	l	%r1,foo@GOTNTPOFF(%r12)
+	l	%r1,0(%r1):tls_load:foo
+	bas	%r14,0(%r1,%r13):tls_gdcall:foo
+	bas	%r14,0(%r1,%r13):tls_ldcall:foo
+EOF
+if { ac_try='${CC-cc} -c $CFLAGS conftest.s 1>&5'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  libc_cv_390_tls=yes
+else
+  libc_cv_390_tls=no
+fi
+rm -f conftest*
+fi
+echo "$as_me:$LINENO: result: $libc_cv_390_tls" >&5
+echo "${ECHO_T}$libc_cv_390_tls" >&6
+if test $libc_cv_390_tls = yes; then
+  cat >>confdefs.h <<\_ACEOF
+#define HAVE_TLS_SUPPORT 1
+_ACEOF
+
+fi
+fi
+
+cat >>confdefs.h <<\_ACEOF
+#define PI_STATIC_AND_HIDDEN 1
+_ACEOF
+
diff -urN libc/sysdeps/s390/s390-32/elf/configure.in libc-s390/sysdeps/s390/s390-32/elf/configure.in
--- libc/sysdeps/s390/s390-32/elf/configure.in	Thu Jan  1 01:00:00 1970
+++ libc-s390/sysdeps/s390/s390-32/elf/configure.in	Sat Jan 25 18:15:17 2003
@@ -0,0 +1,37 @@
+GLIBC_PROVIDES dnl See aclocal.m4 in the top level source directory.
+# Local configure fragment for sysdeps/s390/elf.
+
+if test "$usetls" != no; then
+# Check for support of thread-local storage handling in assembler and
+# linker.
+AC_CACHE_CHECK(for s390 TLS support, libc_cv_390_tls, [dnl
+cat > conftest.S <<\EOF
+	.section ".tdata", "awT", @progbits
+foo:	.long	25
+	.text
+	.long	foo@TLSGD
+	.long	foo@TLSLDM
+	.long	foo@DTPOFF
+	.long	foo@NTPOFF
+	.long	foo@GOTNTPOFF
+	.long	foo@INDNTPOFF
+	l	%r1,foo@GOTNTPOFF(%r12)
+	l	%r1,0(%r1):tls_load:foo
+	bas	%r14,0(%r1,%r13):tls_gdcall:foo
+	bas	%r14,0(%r1,%r13):tls_ldcall:foo
+EOF
+dnl
+if AC_TRY_COMMAND(${CC-cc} -S $CFLAGS conftest.S 1>&AS_MESSAGE_LOG_FD); then
+  libc_cv_390_tls=yes
+else
+  libc_cv_390_tls=no
+fi
+rm -f conftest*])
+if test $libc_cv_390_tls = yes; then
+  AC_DEFINE(HAVE_TLS_SUPPORT)
+fi
+fi
+
+dnl It is always possible to access static and hidden symbols in an
+dnl position independent way.
+AC_DEFINE(PI_STATIC_AND_HIDDEN)
diff -urN libc/sysdeps/s390/s390-64/dl-machine.h libc-s390/sysdeps/s390/s390-64/dl-machine.h
--- libc/sysdeps/s390/s390-64/dl-machine.h	Wed Aug 28 23:21:23 2002
+++ libc-s390/sysdeps/s390/s390-64/dl-machine.h	Sat Jan 25 18:15:17 2003
@@ -284,13 +284,22 @@
 #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.  */
-#define elf_machine_type_class(type) \
+#ifdef USE_TLS
+# define elf_machine_type_class(type) \
+  ((((type) == R_390_JMP_SLOT || (type) == R_390_TLS_DTPMOD		      \
+     || (type) == R_390_TLS_DTPOFF || (type) == R_390_TLS_TPOFF)	      \
+    * ELF_RTYPE_CLASS_PLT)						      \
+   | (((type) == R_390_COPY) * ELF_RTYPE_CLASS_COPY))
+#else
+# define elf_machine_type_class(type) \
   ((((type) == R_390_JMP_SLOT) * ELF_RTYPE_CLASS_PLT)	\
    | (((type) == R_390_COPY) * ELF_RTYPE_CLASS_COPY))
+#endif
 
 /* A reloc type used for ld.so cmdline arg lookups to reject PLT entries.  */
 #define ELF_MACHINE_JMP_SLOT	R_390_JMP_SLOT
@@ -340,18 +349,41 @@
 {
   const unsigned int r_type = ELF64_R_TYPE (reloc->r_info);
 
+#if !defined RTLD_BOOTSTRAP || !defined HAVE_Z_COMBRELOC
   if (__builtin_expect (r_type == R_390_RELATIVE, 0))
-    *reloc_addr = map->l_addr + reloc->r_addend;
-#ifndef RTLD_BOOTSTRAP
-  else if (__builtin_expect (r_type == R_390_NONE, 0))
-    return;
+    {
+# if !defined RTLD_BOOTSTRAP && !defined HAVE_Z_COMBRELOC
+      /* This is defined in rtld.c, but nowhere in the static libc.a;
+	 make the reference weak so static programs can still link.
+	 This declaration cannot be done when compiling rtld.c
+	 (i.e. #ifdef RTLD_BOOTSTRAP) because rtld.c contains the
+	 common defn for _dl_rtld_map, which is incompatible with a
+	 weak decl in the same file.  */
+#  ifndef SHARED
+      weak_extern (GL(dl_rtld_map));
+#  endif
+      if (map != &GL(dl_rtld_map)) /* Already done in rtld itself.  */
+# endif
+	*reloc_addr = map->l_addr + reloc->r_addend;
+    }
+  else
 #endif
+  if (__builtin_expect (r_type == R_390_NONE, 0))
+    return;
   else
     {
       const Elf64_Sym *const refsym = sym;
+#if defined USE_TLS && !defined RTLD_BOOTSTRAP
+      struct link_map *sym_map = RESOLVE_MAP (&sym, version, r_type);
+      Elf64_Addr value = sym == NULL ? 0 : sym_map->l_addr + sym->st_value;
+#else
       Elf64_Addr value = RESOLVE (&sym, version, r_type);
+
+# ifndef RTLD_BOOTSTRAP
       if (sym)
+# endif
 	value += sym->st_value;
+#endif /* use TLS and !RTLD_BOOTSTRAP */
 
       switch (r_type)
 	{
@@ -359,6 +391,48 @@
 	case R_390_JMP_SLOT:
 	  *reloc_addr = value + reloc->r_addend;
 	  break;
+
+#if defined USE_TLS && (!defined RTLD_BOOTSTRAP || USE___THREAD)
+	case R_390_TLS_DTPMOD:
+# ifdef RTLD_BOOTSTRAP
+	  /* During startup the dynamic linker is always the module
+	     with index 1.
+	     XXX If this relocation is necessary move before RESOLVE
+	     call.  */
+	  *reloc_addr = 1;
+# else
+	  /* Get the information from the link map returned by the
+	     resolv function.  */
+	  if (sym_map != NULL)
+	    *reloc_addr = sym_map->l_tls_modid;
+# endif
+	  break;
+	case R_390_TLS_DTPOFF:
+# ifndef RTLD_BOOTSTRAP
+	  /* During relocation all TLS symbols are defined and used.
+	     Therefore the offset is already correct.  */
+	  if (sym != NULL)
+	    *reloc_addr = sym->st_value + reloc->r_addend;
+# endif
+	  break;
+	case R_390_TLS_TPOFF:
+	  /* The offset is negative, forward from the thread pointer.  */
+# ifdef RTLD_BOOTSTRAP
+	  *reloc_addr = sym->st_value + reloc->r_addend - map->l_tls_offset;
+# else
+	  /* We know the offset of the object the symbol is contained in.
+	     It is a negative value which will be added to the
+	     thread pointer.  */
+	  if (sym != NULL)
+	    {
+	      *reloc_addr = (sym->st_value + reloc->r_addend
+			     - sym_map->l_tls_offset);
+	      CHECK_STATIC_TLS (map, sym_map);
+	    }
+#endif
+	  break;
+#endif  /* use TLS */
+
 #ifndef RTLD_BOOTSTRAP
 	case R_390_COPY:
 	  if (sym == NULL)
@@ -439,7 +513,7 @@
 		      Elf64_Addr l_addr, const Elf64_Rela *reloc)
 {
   Elf64_Addr *const reloc_addr = (void *) (l_addr + reloc->r_offset);
-  const unsigned int r_type = ELF32_R_TYPE (reloc->r_info);
+  const unsigned int r_type = ELF64_R_TYPE (reloc->r_info);
   /* Check for unexpected PLT reloc type.  */
   if (__builtin_expect (r_type == R_390_JMP_SLOT, 1))
     {
diff -urN libc/sysdeps/s390/s390-64/elf/configure libc-s390/sysdeps/s390/s390-64/elf/configure
--- libc/sysdeps/s390/s390-64/elf/configure	Thu Jan  1 01:00:00 1970
+++ libc-s390/sysdeps/s390/s390-64/elf/configure	Sat Jan 25 18:15:17 2003
@@ -0,0 +1,52 @@
+# This file is generated from configure.in by Autoconf.  DO NOT EDIT!
+ # Local configure fragment for sysdeps/s390/elf.
+
+if test "$usetls" != no; then
+# Check for support of thread-local storage handling in assembler and
+# linker.
+echo "$as_me:$LINENO: checking for s390 TLS support" >&5
+echo $ECHO_N "checking for s390 TLS support... $ECHO_C" >&6
+if test "${libc_cv_390_tls+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat > conftest.s <<\EOF
+	.section ".tdata", "awT", @progbits
+foo:	.long	25
+	.text
+	.quad	foo@TLSGD
+	.quad	foo@TLSLDM
+	.quad	foo@DTPOFF
+	.quad	foo@NTPOFF
+	.quad	foo@GOTNTPOFF
+	.quad	foo@INDNTPOFF
+	lg	%r1,foo@GOTNTPOFF(%r12)
+	lg	%r1,0(%r1):tls_load:foo
+	brasl	%r14,__tls_get_offset@plt:tls_gdcall:foo
+	brasl	%r14,__tls_get_offset@plt:tls_ldcall:foo
+EOF
+if { ac_try='${CC-cc} -c $CFLAGS conftest.s 1>&5'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  libc_cv_390_tls=yes
+else
+  libc_cv_390_tls=no
+fi
+rm -f conftest*
+fi
+echo "$as_me:$LINENO: result: $libc_cv_390_tls" >&5
+echo "${ECHO_T}$libc_cv_390_tls" >&6
+if test $libc_cv_390_tls = yes; then
+  cat >>confdefs.h <<\_ACEOF
+#define HAVE_TLS_SUPPORT 1
+_ACEOF
+
+fi
+fi
+
+cat >>confdefs.h <<\_ACEOF
+#define PI_STATIC_AND_HIDDEN 1
+_ACEOF
+
diff -urN libc/sysdeps/s390/s390-64/elf/configure.in libc-s390/sysdeps/s390/s390-64/elf/configure.in
--- libc/sysdeps/s390/s390-64/elf/configure.in	Thu Jan  1 01:00:00 1970
+++ libc-s390/sysdeps/s390/s390-64/elf/configure.in	Sat Jan 25 18:15:17 2003
@@ -0,0 +1,37 @@
+GLIBC_PROVIDES dnl See aclocal.m4 in the top level source directory.
+# Local configure fragment for sysdeps/s390/elf.
+
+if test "$usetls" != no; then
+# Check for support of thread-local storage handling in assembler and
+# linker.
+AC_CACHE_CHECK(for s390 TLS support, libc_cv_390_tls, [dnl
+cat > conftest.S <<\EOF
+	.section ".tdata", "awT", @progbits
+foo:	.long	25
+	.text
+	.quad	foo@TLSGD
+	.quad	foo@TLSLDM
+	.quad	foo@DTPOFF
+	.quad	foo@NTPOFF
+	.quad	foo@GOTNTPOFF
+	.quad	foo@INDNTPOFF
+	lg	%r1,foo@GOTNTPOFF(%r12)
+	lg	%r1,0(%r1):tls_load:foo
+	brasl	%r14,__tls_get_offset@plt:tls_gdcall:foo
+	brasl	%r14,__tls_get_offset@plt:tls_ldcall:foo
+EOF
+dnl
+if AC_TRY_COMMAND(${CC-cc} -S $CFLAGS conftest.S 1>&AS_MESSAGE_LOG_FD); then
+  libc_cv_390_tls=yes
+else
+  libc_cv_390_tls=no
+fi
+rm -f conftest*])
+if test $libc_cv_390_tls = yes; then
+  AC_DEFINE(HAVE_TLS_SUPPORT)
+fi
+fi
+
+dnl It is always possible to access static and hidden symbols in an
+dnl position independent way.
+AC_DEFINE(PI_STATIC_AND_HIDDEN)
diff -urN libc/sysdeps/unix/sysv/linux/s390/s390-32/clone.S libc-s390/sysdeps/unix/sysv/linux/s390/s390-32/clone.S
--- libc/sysdeps/unix/sysv/linux/s390/s390-32/clone.S	Thu Feb  7 18:33:41 2002
+++ libc-s390/sysdeps/unix/sysv/linux/s390/s390-32/clone.S	Sat Jan 25 18:15:17 2003
@@ -24,20 +24,24 @@
 #define _ERRNO_H	1
 #include <bits/errno.h>
 
-/*int __clone(int (*fn)(void *arg), void *child_stack, int flags, void *arg);*/
-/* sys_clone(void *child_stack, unsigned long flags) */
+/* int __clone(int (*fn)(void *arg), void *child_stack, int flags, void *arg,
+               void *tls, pid_t *parent_tid, pid_t *child_tid);  */
+/* sys_clone  (void *child_stack, unsigned long flags,
+               pid_t *parent_tid, pid_t *child_tid, void *tls);  */
 
 	.text
 ENTRY(__clone)
 	/* Sanity check arguments & move registers */
+	lr	%r0,%r5			/* move *arg out of the way */
 	ltr     %r1,%r2			/* no NULL function pointers */
 	lhi     %r2,-EINVAL
 	jz      SYSCALL_ERROR_LABEL
 	ltr     %r3,%r3			/* no NULL stack pointers */
 	jz      SYSCALL_ERROR_LABEL
-	/* move child_stack and flags, then call SVC */
+	/* set up registers, then call SVC */
 	lr      %r2,%r3
 	lr      %r3,%r4
+	lm	%r4,%r5,96(%r15)
 	svc     SYS_ify(clone)
 	ltr     %r2,%r2			/* check return code */
 	jm      SYSCALL_ERROR_LABEL
@@ -45,10 +49,10 @@
 	br      %r14
 
 thread_start:
-	/* fn is in gpr 1, arg in gpr 5 */
-	lr      %r2,%r5         /* set first parameter to void *arg */
-	sr      %r11,%r11	/* terminate the stack frame */
+	/* fn is in gpr 1, arg in gpr 0 */
+	lr      %r2,%r0         /* set first parameter to void *arg */
 	ahi     %r15,-96        /* make room on the stack for the save area */
+	xc	0(4,%r15),0(%r15)
 	basr    %r14,%r1        /* jump to fn */
 #ifdef PIC
 	basr    %r12,0
diff -urN libc/sysdeps/unix/sysv/linux/s390/s390-32/sysdep.S libc-s390/sysdeps/unix/sysv/linux/s390/s390-32/sysdep.S
--- libc/sysdeps/unix/sysv/linux/s390/s390-32/sysdep.S	Fri Oct 11 12:51:29 2002
+++ libc-s390/sysdeps/unix/sysv/linux/s390/s390-32/sysdep.S	Sat Jan 25 18:15:17 2003
@@ -1,4 +1,4 @@
-/* Copyright (C) 2000, 2001, 2002 Free Software Foundation, Inc.
+/* Copyright (C) 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
    Contributed by Martin Schwidefsky (schwidefsky@de.ibm.com).
    This file is part of the GNU C Library.
 
@@ -31,59 +31,94 @@
 	.text
 ENTRY(__syscall_error)
 #ifndef PIC
-#ifndef _LIBC_REENTRANT
-	lcr     %r2,%r2
-	basr    %r1,0
-.L0:    l       %r1,.L1-.L0(%r1)
-	st      %r2,0(0,%r1)
-	lhi     %r2,-1
-	br      %r14
-.L1:    .long  errno
-#else
-	stm     %r11,%r15,44(%r15)
-	lr      %r0,%r15
-	ahi     %r15,-96
-	st      %r0,0(%r15)
-	lcr     %r11,%r2
-	basr    %r13,0
-.L0:	l       %r1,.L1-.L0(%r13)
-	basr    %r14,%r1
-	st      %r11,0(%r2)
-	lhi     %r2,-1
-	l       %r15,0(%r15)
-	lm      %r11,%r15,44(%r15)
-	br      %r14
-.L1:	.long  __errno_location
+# if USE___THREAD
+#  ifndef NOT_IN_libc
+#   define SYSCALL_ERROR_ERRNO __libc_errno
+#  else
+#   define SYSCALL_ERROR_ERRNO errno
+#  endif
+	basr	%r1,0
+0:	l	%r1,1f-0b(%r1)
+	ear	%r3,%a0
+	lcr	%r2,%r2
+	st	%r2,0(%r1,%r3)
+	lhi	%r2,-1
+	br	%r14
+1:	.long	SYSCALL_ERROR_ERRNO@ntpoff
+# elif !defined _LIBC_REENTRANT
+	basr	%r1,0
+0:	l	%r1,1f-0b(%r1)
+	lcr	%r2,%r2
+	st	%r2,0(%r1)
+	lhi	%r2,-1
+	br	%r14
+1:	.long  errno
+# else
+	stm	%r13,%r15,52(%r15)
+	lr	%r0,%r15
+	ahi	%r15,-96
+	lcr	%r13,%r2
+	st	%r0,0(%r15)
+	basr	%r1,0
+0:	l	%r1,1f-0b(%r1)
+	basr	%r14,%r1
+	st	%r13,0(%r2)
+	lm	%r13,%r15,148(%r15)
+	lhi	%r2,-1
+	br	%r14
+1:	.long  __errno_location
 #endif
 #else
-#ifndef _LIBC_REENTRANT
-	basr    %r1,0
-.L0:    al      %r1,.L1-.L0(%r1)
-	l       %r1,errno@GOT12(%r1)
-	lcr     %r2,%r2
-	st      %r2,0(0,%r1)
-	lhi     %r2,-1
-	br      %r14
-.L1:    .long   _GLOBAL_OFFSET_TABLE_-0b
-#else
-	stm     %r11,%r15,44(%r15)
-	lr      %r0,%r15
-	ahi     %r15,-96
-	st      %r0,0(%r15)
-	lcr     %r11,%r2
-	basr    %r13,0
-.L0:	l       %r12,.L1-.L0(%r13)
-	ar      %r12,%r13
-	l       %r14,.L2-.L0(%r13)
-	bas     %r14,0(%r14,%r13)
-	st      %r11,0(0,%r2)
-	lhi     %r2,-1
-	l       %r15,0(%r15)
-	lm      %r11,%r15,44(%r15)
-	br      %r14
-.L1:	.long _GLOBAL_OFFSET_TABLE_ - .L0
-.L2:    .long __errno_location@PLT - .L0
-#endif
+# if RTLD_PRIVATE_ERRNO
+	basr	%r1,0
+0:	al	%r1,1f-0b(%r1)
+	lcr	%r2,%r2
+	st	%r2,0(%r1)
+	lhi	%r2,-1
+	br	%r14
+1:	.long	errno - 0b
+# elif USE___THREAD
+#  ifndef NOT_IN_libc
+#   define SYSCALL_ERROR_ERRNO __libc_errno
+#  else
+#   define SYSCALL_ERROR_ERRNO errno
+#  endif
+	basr	%r1,0
+0:	al	%r1,1f-0b(%r1)
+	ear	%r3,%a0
+	l	%r1,SYSCALL_ERROR_ERRNO@gotntpoff(%r1)
+	lcr	%r2,%r2
+	st	%r2,0(%r1,%r3)
+	lhi	%r2,-1
+	br	%r14
+1:	.long	_GLOBAL_OFFSET_TABLE_-0b
+# elif !defined _LIBC_REENTRANT
+	basr	%r1,0
+0:	al	%r1,1f-0b(%r1)
+	l	%r1,errno@GOT(%r1)
+	lcr	%r2,%r2
+	st	%r2,0(0,%r1)
+	lhi	%r2,-1
+	br	%r14
+1:	.long	_GLOBAL_OFFSET_TABLE_-0b
+# else
+	stm	%r11,%r15,44(%r15)
+	lr	%r0,%r15
+	ahi	%r15,-96
+	lcr	%r11,%r2
+	st	%r0,0(%r15)
+	basr	%r13,0
+0:	l	%r12,1f-0b(%r13)
+	l	%r1,2f-0b(%r13)
+	la	%r12,0(%r12,%r13)
+	bas	%r14,0(%r1,%r13)
+	st	%r11,0(%r2)
+	lm	%r11,%r15,140(%r15)
+	lhi	%r2,-1
+	br	%r14
+1:	.long _GLOBAL_OFFSET_TABLE_-0b
+2:	.long __errno_location@PLT-0b
+# endif
 #endif
 
 END (__syscall_error)
diff -urN libc/sysdeps/unix/sysv/linux/s390/s390-32/sysdep.h libc-s390/sysdeps/unix/sysv/linux/s390/s390-32/sysdep.h
--- libc/sysdeps/unix/sysv/linux/s390/s390-32/sysdep.h	Mon Jan 20 20:04:56 2003
+++ libc-s390/sysdeps/unix/sysv/linux/s390/s390-32/sysdep.h	Sat Jan 25 18:15:17 2003
@@ -45,8 +45,6 @@
    number.  Linus said he will make sure the no syscall returns a value
    in -1 .. -4095 as a valid result so we can savely test with -4095.  */
 
-#define SYSCALL_ERROR_LABEL 0f
-
 #undef PSEUDO
 #define	PSEUDO(name, syscall_name, args)				      \
   .text;                                                                      \
@@ -54,42 +52,70 @@
     DO_CALL (syscall_name, args);                                             \
     lhi  %r4,-4095 ;                                                          \
     clr  %r2,%r4 ;		                                              \
-    jnl  SYSCALL_ERROR_LABEL ;                                                \
-  L(pseudo_end):
+    jnl  SYSCALL_ERROR_LABEL
 
 #undef PSEUDO_END
 #define PSEUDO_END(name)						      \
   SYSCALL_ERROR_HANDLER;						      \
   END (name)
 
-#ifndef _LIBC_REENTRANT
 #ifndef PIC
-#define SYSCALL_ERROR_HANDLER                                                 \
-0:  lcr     %r2,%r2 ;                                                         \
-    basr    %r1,0 ;                                                           \
-1:  l       %r1,2f-1b(%r1)                                                    \
-    st      %r2,0(%r1)                                                        \
-    lhi     %r2,-1                                                            \
-    br      %r14                                                              \
-2:  .long   errno
+# define SYSCALL_ERROR_LABEL 0f
+# define SYSCALL_ERROR_HANDLER \
+0:  basr  %r1,0;							      \
+1:  l     %r1,2f-1b(%r1);						      \
+    br    %r1;								      \
+2:  .long syscall_error
 #else
-#define SYSCALL_ERROR_HANDLER						      \
-0:  basr    %r1,0 ;                                                           \
-1:  al      %r1,2f-1b(%r1) ;                                                  \
-    l       %r1,errno@GOT12(%r1) ;                                            \
-    lcr     %r2,%r2 ;							      \
-    st      %r2,0(%r1) ;						      \
-    lhi     %r2,-1 ;                                                          \
-    br      %r14 ;                                                            \
-2:  .long   _GLOBAL_OFFSET_TABLE_-1b
+# if RTLD_PRIVATE_ERRNO
+#  define SYSCALL_ERROR_LABEL 0f
+#  define SYSCALL_ERROR_HANDLER \
+0:  basr  %r1,0;							      \
+1:  al    %r1,2f-1b(%r1);						      \
+    lcr   %r2,%r2;							      \
+    st    %r2,0(%r1);							      \
+    lhi   %r2,-1;							      \
+    br    %r14;								      \
+2:  .long errno-1b
+# elif defined _LIBC_REENTRANT
+#  if USE___THREAD
+#   ifndef NOT_IN_libc
+#    define SYSCALL_ERROR_ERRNO __libc_errno
+#   else
+#    define SYSCALL_ERROR_ERRNO errno
+#   endif
+#   define SYSCALL_ERROR_LABEL 0f
+#   define SYSCALL_ERROR_HANDLER \
+0:  lcr   %r0,%r2;							      \
+    basr  %r1,0;							      \
+1:  al    %r1,2f-1b(%r1);						      \
+    l     %r1,SYSCALL_ERROR_ERRNO@gotntpoff(%r1)			      \
+    ear   %r2,%a0							      \
+    st    %r0,0(%r1,%r2);						      \
+    lhi   %r2,-1;							      \
+    br    %r14;								      \
+2:  .long _GLOBAL_OFFSET_TABLE_-1b
+#  else
+#   define SYSCALL_ERROR_LABEL 0f
+#   define SYSCALL_ERROR_HANDLER \
+0:  basr  %r1,0;							      \
+1:  al    %r1,2f-1b(%r1);						      \
+    br    %r1;								      \
+2:  .long syscall_error@plt-1b
+#  endif
+# else
+#  define SYSCALL_ERROR_LABEL 0f
+#  define SYSCALL_ERROR_HANDLER \
+0:  basr  %r1,0;							      \
+1:  al    %r1,2f-1b(%r1);						      \
+    l     %r1,errno@GOT(%r1);						      \
+    lcr   %r2,%r2;							      \
+    st    %r2,0(%r1);							      \
+    lhi   %r2,-1;							      \
+    br    %r14;								      \
+2:  .long _GLOBAL_OFFSET_TABLE_-1b
+# endif /* _LIBC_REENTRANT */
 #endif /* PIC */
-#else
-#define SYSCALL_ERROR_HANDLER                                                 \
-0:  basr    %r1,0 ;                                                           \
-1:  al      %r1,2f-1b(%r1) ;                                                  \
-    br      %r1 ;                                                             \
-2:  .long   __syscall_error@PLT-1b
-#endif /* _LIBC_REENTRANT */
 
 /* Linux takes system call arguments in registers:
 
diff -urN libc/sysdeps/unix/sysv/linux/s390/s390-64/clone.S libc-s390/sysdeps/unix/sysv/linux/s390/s390-64/clone.S
--- libc/sysdeps/unix/sysv/linux/s390/s390-64/clone.S	Thu Feb  7 18:33:42 2002
+++ libc-s390/sysdeps/unix/sysv/linux/s390/s390-64/clone.S	Sat Jan 25 18:15:17 2003
@@ -25,32 +25,40 @@
 #define _ERRNO_H	1
 #include <bits/errno.h>
 
+/* int __clone(int (*fn)(void *arg), void *child_stack, int flags, void *arg,
+               void *tls, pid_t *parent_tid, pid_t *child_tid);  */
+/* sys_clone  (void *child_stack, unsigned long flags,
+               pid_t *parent_tid, pid_t *child_tid, void *tls);  */
+
 	.text
 ENTRY(__clone)
 	/* Sanity check arguments & move registers */
+	lgr	%r0,%r5			/* move *arg out of the way */
 	ltgr	%r1,%r2			/* no NULL function pointers */
 	lghi	%r2,-EINVAL
-	jz	SYSCALL_ERROR_LABEL
+	jgz	SYSCALL_ERROR_LABEL
 	ltgr	%r3,%r3			/* no NULL stack pointers */
-	jz	SYSCALL_ERROR_LABEL
-	/* move child_stack and flags, then call SVC */
+	jgz	SYSCALL_ERROR_LABEL
+	/* set up registers, then call SVC */
 	lgr	%r2,%r3
 	lgr	%r3,%r4
+	lmg	%r4,%r5,160(%r15)
 	svc	SYS_ify(clone)
 	ltgr	%r2,%r2			/* check return code */
-	jm	SYSCALL_ERROR_LABEL
+	jgm	SYSCALL_ERROR_LABEL
 	jz	thread_start
 	br	%r14
 
 thread_start:
-	/* fn is in gpr 1, arg in gpr 5 */
-	lgr	%r2,%r5		/* set first parameter to void *arg */
-	sgr	%r11,%r11	/* terminate the stack frame */
+	/* fn is in gpr 1, arg in gpr 0 */
+	lgr	%r2,%r0		/* set first parameter to void *arg */
 	aghi	%r15,-160	/* make room on the stack for the save area */
+	xc	0(8,%r15),0(%r15)
 	basr	%r14,%r1	/* jump to fn */
 #ifdef PIC
-	larl	%r12,_GLOBAL_OFFSET_TABLE_
-#endif
 	jg	_exit@PLT	/* branch to _exit -> thread termination */
+#else
+	jg	_exit		/* branch to _exit -> thread termination */
+#endif
 PSEUDO_END (__clone)
 weak_alias (__clone, clone)
diff -urN libc/sysdeps/unix/sysv/linux/s390/s390-64/mmap.S libc-s390/sysdeps/unix/sysv/linux/s390/s390-64/mmap.S
--- libc/sysdeps/unix/sysv/linux/s390/s390-64/mmap.S	Thu Feb  7 18:35:50 2002
+++ libc-s390/sysdeps/unix/sysv/linux/s390/s390-64/mmap.S	Sat Jan 25 18:15:17 2003
@@ -55,7 +55,7 @@
         /* Check gpr 2 for error.  */ 
         lghi    %r0,-4096
         clgr    %r2,%r0
-        jnl     SYSCALL_ERROR_LABEL
+        jgnl    SYSCALL_ERROR_LABEL
 
         /* Successful; return the syscall's value.  */
         br      %r14
diff -urN libc/sysdeps/unix/sysv/linux/s390/s390-64/socket.S libc-s390/sysdeps/unix/sysv/linux/s390/s390-64/socket.S
--- libc/sysdeps/unix/sysv/linux/s390/s390-64/socket.S	Sun Jan  5 08:04:04 2003
+++ libc-s390/sysdeps/unix/sysv/linux/s390/s390-64/socket.S	Sat Jan 25 18:15:17 2003
@@ -93,7 +93,7 @@
 	/* gpr2 is < 0 if there was an error.  */
         lghi    %r0,-125 
         clgr    %r2,%r0
-        jnl     SYSCALL_ERROR_LABEL
+        jgnl    SYSCALL_ERROR_LABEL
  
 	/* Successful; return the syscall's value.  */
 	br      %r14
diff -urN libc/sysdeps/unix/sysv/linux/s390/s390-64/syscall.S libc-s390/sysdeps/unix/sysv/linux/s390/s390-64/syscall.S
--- libc/sysdeps/unix/sysv/linux/s390/s390-64/syscall.S	Fri Jul  6 06:56:20 2001
+++ libc-s390/sysdeps/unix/sysv/linux/s390/s390-64/syscall.S	Sat Jan 25 18:15:17 2003
@@ -45,7 +45,7 @@
 
 	lghi   %r0,-4095
 	clgr   %r2,%r0		   /* Check R2 for error.  */
-	jnl    SYSCALL_ERROR_LABEL
+	jgnl   SYSCALL_ERROR_LABEL
 	br     %r14		   /* Return to caller.	 */
 .L1:	.word  0x0A00		   /* Opcode for SVC 0.	 */
 PSEUDO_END (syscall)
diff -urN libc/sysdeps/unix/sysv/linux/s390/s390-64/sysdep.S libc-s390/sysdeps/unix/sysv/linux/s390/s390-64/sysdep.S
--- libc/sysdeps/unix/sysv/linux/s390/s390-64/sysdep.S	Fri Oct 11 12:51:15 2002
+++ libc-s390/sysdeps/unix/sysv/linux/s390/s390-64/sysdep.S	Sat Jan 25 18:15:17 2003
@@ -1,4 +1,4 @@
-/* Copyright (C) 2001, 2002 Free Software Foundation, Inc.
+/* Copyright (C) 2001, 2002, 2003 Free Software Foundation, Inc.
    Contributed by Martin Schwidefsky (schwidefsky@de.ibm.com).
    This file is part of the GNU C Library.
 
@@ -29,47 +29,84 @@
 #undef CALL_MCOUNT
 #define CALL_MCOUNT
 
-        .text
+.text
 ENTRY(__syscall_error)
 #ifndef PIC
-#ifndef _LIBC_REENTRANT
-	lcr     %r2,%r2
-	larl    %r1,errno
-	st      %r2,0(%r1)
-	lghi    %r2,-1
-	br      %r14
-#else
-        stmg    %r13,%r15,104(%r15)
-        lgr     %r0,%r15
-        aghi    %r15,-160
-        lcr     %r13,%r2
-        stg     %r0,0(%r15)
-	brasl   %r14,__errno_location
-	st      %r13,0(%r2)
-	lmg     %r13,%r15,264(%r15)
-	lghi    %r2,-1
-	br      %r14
+# if USE___THREAD
+#  ifndef NOT_IN_libc
+#   define SYSCALL_ERROR_ERRNO __libc_errno
+#  else
+#   define SYSCALL_ERROR_ERRNO errno
+#  endif
+	basr	%r1,0
+0:	lg	%r1,1f-0b(%r1)
+	ear	%r3,%a0
+	sllg	%r3,%r3,32
+	ear	%r3,%a1
+	lcr	%r2,%r2
+	st	%r2,0(%r1,%r3)
+	lghi	%r2,-1
+	br	%r14
+1:	.quad	SYSCALL_ERROR_ERRNO@ntpoff
+# elif !defined _LIBC_REENTRANT
+	larl	%r1,errno
+	lcr	%r2,%r2
+	st	%r2,0(%r1)
+	lghi	%r2,-1
+	br	%r14
+# else
+	stmg	%r13,%r15,104(%r15)
+	lgr	%r0,%r15
+	aghi	%r15,-160
+	lcr	%r13,%r2
+	stg	%r0,0(%r15)
+	brasl	%r14,__errno_location
+	st	%r13,0(%r2)
+	lmg	%r13,%r15,264(%r15)
+	lghi	%r2,-1
+	br	%r14
 #endif
 #else
-#ifndef _LIBC_REENTRANT
-	larl    %r1,_GLOBAL_OFFSET_TABLE_
-	lg      %r1,errno@GOT(%r1)
-	lcr     %r2,%r2
-	st      %r2,0(%r1)
-	lghi    %r2,-1
-	br      %r14
-#else
-        stmg    %r13,%r15,104(%r15)
-        lgr     %r0,%r15
-        aghi    %r15,-160
-        lcr     %r13,%r2
-        stg     %r0,0(%r15)
-	brasl   %r14,__errno_location@PLT
-	st      %r13,0(%r2)
-	lmg     %r13,%r15,264(%r15)
-	lghi    %r2,-1
-	br      %r14
-#endif
+# if RTLD_PRIVATE_ERRNO
+	larl	%r1,errno
+	lcr	%r2,%r2
+	st	%r2,0(%r1)
+	lghi	%r2,-1
+	br	%r14
+# elif USE___THREAD
+#  ifndef NOT_IN_libc
+#   define SYSCALL_ERROR_ERRNO __libc_errno
+#  else
+#   define SYSCALL_ERROR_ERRNO errno
+#  endif
+	larl	%r1,_GLOBAL_OFFSET_TABLE_
+	lg	%r1,SYSCALL_ERROR_ERRNO@gotntpoff(%r1)
+	ear	%r3,%a0
+	sllg	%r3,%r3,32
+	ear	%r3,%a1
+	lcr	%r2,%r2
+	st	%r2,0(%r1,%r3)
+	lghi	%r2,-1
+	br	%r14
+# elif !defined _LIBC_REENTRANT
+	larl	%r1,_GLOBAL_OFFSET_TABLE_
+	lg	%r1,errno@GOT(%r1)
+	lcr	%r2,%r2
+	st	%r2,0(%r1)
+	lghi	%r2,-1
+	br	%r14	
+# else
+	stmg	%r13,%r15,104(%r15)
+	lgr	%r0,%r15
+	aghi	%r15,-160
+	lcr	%r13,%r2
+	stg	%r0,0(%r15)
+	brasl	%r14,__errno_location@PLT
+	st	%r13,0(%r2)
+	lmg	%r13,%r15,264(%r15)
+	lghi	%r2,-1
+	br	%r14
+# endif
 #endif
 
 END (__syscall_error)
diff -urN libc/sysdeps/unix/sysv/linux/s390/s390-64/sysdep.h libc-s390/sysdeps/unix/sysv/linux/s390/s390-64/sysdep.h
--- libc/sysdeps/unix/sysv/linux/s390/s390-64/sysdep.h	Mon Jan 20 20:04:56 2003
+++ libc-s390/sysdeps/unix/sysv/linux/s390/s390-64/sysdep.h	Sat Jan 25 18:15:17 2003
@@ -46,8 +46,6 @@
    number.  Linus said he will make sure the no syscall returns a value
    in -1 .. -4095 as a valid result so we can savely test with -4095.  */
 
-#define SYSCALL_ERROR_LABEL 0f
-
 #undef PSEUDO
 #define	PSEUDO(name, syscall_name, args)				      \
   .text;								      \
@@ -55,35 +53,58 @@
     DO_CALL (syscall_name, args);					      \
     lghi %r4,-4095 ;							      \
     clgr %r2,%r4 ;							      \
-    jnl SYSCALL_ERROR_LABEL ;						      \
-  L(pseudo_end):
+    jgnl SYSCALL_ERROR_LABEL
 
 #undef PSEUDO_END
 #define PSEUDO_END(name)						      \
   SYSCALL_ERROR_HANDLER;						      \
   END (name)
 
-#ifndef _LIBC_REENTRANT
 #ifndef PIC
-#define SYSCALL_ERROR_HANDLER						      \
-0:  lcr	    %r2,%r2 ;							      \
-    larl    %r1,errno ;							      \
-    st	    %r2,0(%r1) ;						      \
-    lghi    %r2,-1 ;							      \
-    br	    %r14
+# define SYSCALL_ERROR_LABEL syscall_error
+# define SYSCALL_ERROR_HANDLER
 #else
-#define SYSCALL_ERROR_HANDLER						      \
-0:  larl    %r1,_GLOBAL_OFFSET_TABLE_ ;					      \
-    lg	    %r1,errno@GOT(%r1) ;					      \
-    lcr	    %r2,%r2 ;							      \
-    st	    %r2,0(%r1) ;						      \
-    lghi    %r2,-1 ;							      \
-    br	    %r14
+# if RTLD_PRIVATE_ERRNO
+#  define SYSCALL_ERROR_LABEL 0f
+#  define SYSCALL_ERROR_HANDLER \
+0:  larl  %r1,errno;							      \
+    lcr   %r2,%r2;							      \
+    st    %r2,0(%r1);							      \
+    lghi  %r2,-1;							      \
+    br    %r14
+# elif defined _LIBC_REENTRANT
+#  if USE___THREAD
+#   ifndef NOT_IN_libc
+#    define SYSCALL_ERROR_ERRNO __libc_errno
+#   else
+#    define SYSCALL_ERROR_ERRNO errno
+#   endif
+#   define SYSCALL_ERROR_LABEL 0f
+#   define SYSCALL_ERROR_HANDLER \
+0:  lcr   %r0,%r2;							      \
+    larl  %r1,SYSCALL_ERROR_ERRNO@indntpoff;				      \
+    lg    %r1,0(%r1);							      \
+    ear   %r2,%a0;							      \
+    sllg  %r2,%r2,32;							      \
+    ear   %r2,%a1;							      \
+    st    %r0,0(%r1,%r2);						      \
+    lghi   %r2,-1;							      \
+    br    %r14
+#  else
+#   define SYSCALL_ERROR_LABEL syscall_error@plt
+#   define SYSCALL_ERROR_HANDLER
+#  endif
+# else
+#  define SYSCALL_ERROR_LABEL 0f
+#  define SYSCALL_ERROR_HANDLER \
+0:  larl  %r1,_GLOBAL_OFFSET_TABLE_;					      \
+    lg    %r1,errno@GOT(%r1);						      \
+    lcr   %r2,%r2;							      \
+    st    %r2,0(%r1);							      \
+    lghi  %r2,-1;							      \
+    br    %r14
+# endif /* _LIBC_REENTRANT */
 #endif /* PIC */
-#else
-#define SYSCALL_ERROR_HANDLER						      \
-0:  jg	    __syscall_error@PLT
-#endif /* _LIBC_REENTRANT */
 
 /* Linux takes system call arguments in registers:
 


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