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


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

PPC32 TLS support first cut


Here is a first cut at TLS support in glibc for ppc32.  It compiles
and passes all the tests when configured for TLS support.

I haven't checked that it is still OK when configured without TLS
support.  I suspect I probably broke it by removing the THREAD_GETMEM
etc. definitions from pt-machine.h (they conflict with the ones in
tls.h).

For the moment I am testing __local_multiple_threads in
sysdep-candel.h for the TLS case because I couldn't get
tcb-offsets.sym to do what I want just yet.  Ultimately it would be
better to use an offset from r2 for the multiple_threads test in the
TLS case as well as the non-TLS case.

Also I probably have the TPREL16_* relocations wrong, since I copied
ppc64, which gets these relocs wrong according to Roland.

Comments welcome.

Regards,
Paul.

diff -urN cvs/libc/elf/elf.h libc/elf/elf.h
--- cvs/libc/elf/elf.h	2003-02-26 11:47:45.000000000 +1100
+++ libc/elf/elf.h	2003-02-26 12:02:38.000000000 +1100
@@ -1881,8 +1881,39 @@
 #define R_PPC_SECTOFF_LO	34
 #define R_PPC_SECTOFF_HI	35
 #define R_PPC_SECTOFF_HA	36
+
+/* Relocations for TLS support */
+#define R_PPC_TLS		67
+#define R_PPC_DTPMOD32		68
+#define R_PPC_TPREL16		69
+#define R_PPC_TPREL16_LO	70
+#define R_PPC_TPREL16_HI	71
+#define R_PPC_TPREL16_HA	72
+#define R_PPC_TPREL32		73
+#define R_PPC_DTPREL16		74
+#define R_PPC_DTPREL16_LO	75
+#define R_PPC_DTPREL16_HI	76
+#define R_PPC_DTPREL16_HA	77
+#define R_PPC_DTPREL32		78
+#define R_PPC_GOT_TLSGD16	79
+#define R_PPC_GOT_TLSGD16_LO	80
+#define R_PPC_GOT_TLSGD16_HI	81
+#define R_PPC_GOT_TLSGD16_HA	82
+#define R_PPC_GOT_TLSLD16	83
+#define R_PPC_GOT_TLSLD16_LO	84
+#define R_PPC_GOT_TLSLD16_HI	85
+#define R_PPC_GOT_TLSLD16_HA	86
+#define R_PPC_GOT_TPREL16	87
+#define R_PPC_GOT_TPREL16_LO	88
+#define R_PPC_GOT_TPREL16_HI	89
+#define R_PPC_GOT_TPREL16_HA	90
+#define R_PPC_GOT_DTPREL16	91
+#define R_PPC_GOT_DTPREL16_LO	92
+#define R_PPC_GOT_DTPREL16_HI	93
+#define R_PPC_GOT_DTPREL16_HA	94
+
 /* Keep this the last entry.  */
-#define R_PPC_NUM		37
+#define R_PPC_NUM		95
 
 /* PowerPC64 relocations defined by the ABIs */
 #define R_PPC64_NONE    R_PPC_NONE
diff -urN cvs/libc/elf/tls-macros.h libc/elf/tls-macros.h
--- cvs/libc/elf/tls-macros.h	2003-02-26 11:47:45.000000000 +1100
+++ libc/elf/tls-macros.h	2003-02-28 17:42:07.000000000 +1100
@@ -623,6 +623,53 @@
      (int *) (__builtin_thread_pointer() + __offset); })
 # endif
 
+#elif defined __powerpc__ && !defined __powerpc64__
+
+# define __TLS_CALL_CLOBBERS						\
+	"0", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12",	\
+	"lr", "ctr", "cr0", "cr1", "cr5", "cr6", "cr7"
+
+/* PowerPC32 Local Exec TLS access.  */
+# define TLS_LE(x)				\
+  ({ int *__result;				\
+     asm ("addi %0,2," #x "@tprel"		\
+	  : "=r" (__result));			\
+     __result; })
+
+/* PowerPC32 Initial Exec TLS access.  */
+# define TLS_IE(x)					\
+  ({ int *__result;					\
+     asm ("bl _GLOBAL_OFFSET_TABLE_ at local-4\n\t"	\
+	  "mflr %0\n\t"					\
+	  "lwz %0," #x "@got at tprel(%0)\n\t"		\
+	  "add %0,%0," #x "@tls"			\
+	  : "=b" (__result) :				\
+	  : "lr");					\
+     __result; })
+
+/* PowerPC32 Local Dynamic TLS access.  */
+# define TLS_LD(x)					\
+  ({ int *__result;					\
+     asm ("bl _GLOBAL_OFFSET_TABLE_ at local-4\n\t"	\
+	  "mflr 3\n\t"					\
+	  "addi 3,3," #x "@got at tlsld\n\t"		\
+	  "bl __tls_get_addr at plt\n\t"			\
+	  "addi %0,3," #x "@dtprel"			\
+	  : "=r" (__result) :				\
+	  : __TLS_CALL_CLOBBERS);			\
+     __result; })
+
+/* PowerPC32 General Dynamic TLS access.  */
+# define TLS_GD(x)					\
+  ({ register int *__result __asm__ ("r3");		\
+     asm ("bl _GLOBAL_OFFSET_TABLE_ at local-4\n\t"	\
+	  "mflr 3\n\t"					\
+	  "addi 3,3," #x "@got at tlsgd\n\t"		\
+	  "bl __tls_get_addr at plt"			\
+	  : :						\
+	  : __TLS_CALL_CLOBBERS);			\
+     __result; })
+
 #elif defined __powerpc__ && defined __powerpc64__
 
 /* PowerPC64 Local Exec TLS access.  */
diff -urN cvs/libc/linuxthreads/sysdeps/powerpc/powerpc32/pt-machine.h libc/linuxthreads/sysdeps/powerpc/powerpc32/pt-machine.h
--- cvs/libc/linuxthreads/sysdeps/powerpc/powerpc32/pt-machine.h	2003-02-18 11:15:16.000000000 +1100
+++ libc/linuxthreads/sysdeps/powerpc/powerpc32/pt-machine.h	2003-02-28 22:00:33.000000000 +1100
@@ -57,16 +57,6 @@
 /* Initialize the thread-unique value.  */
 #define INIT_THREAD_SELF(descr, nr)  (__thread_self = (descr))
 
-/* Access to data in the thread descriptor is easy.  */
-#define THREAD_GETMEM(descr, member) \
-  ((void) (descr), THREAD_SELF->member)
-#define THREAD_GETMEM_NC(descr, member) \
-  ((void) (descr), THREAD_SELF->member)
-#define THREAD_SETMEM(descr, member, value) \
-  ((void) (descr), THREAD_SELF->member = (value))
-#define THREAD_SETMEM_NC(descr, member, value) \
-  ((void) (descr), THREAD_SELF->member = (value))
-
 /* Compare-and-swap for semaphores. */
 /* note that test-and-set(x) is the same as !compare-and-swap(x, 0, 1) */
 
diff -urN cvs/libc/linuxthreads/sysdeps/powerpc/tls.h libc/linuxthreads/sysdeps/powerpc/tls.h
--- cvs/libc/linuxthreads/sysdeps/powerpc/tls.h	2003-02-28 08:39:22.000000000 +1100
+++ libc/linuxthreads/sysdeps/powerpc/tls.h	2003-02-28 22:05:02.000000000 +1100
@@ -67,12 +67,12 @@
 /* This is the size we need before TCB.  */
 #  define TLS_PRE_TCB_SIZE	sizeof (struct _pthread_descr_struct)
 
-/* The following assumes that TP (R13) is points to the end of the
+/* The following assumes that TP (R2 or R13) is points to the end of the
    TCB + 0x7000 (per the ABI).  This implies that TCB address is
-   R13-(TLS_TCB_SIZE + 0x7000).  As we define TLS_DTV_AT_TP we can
+   TP-(TLS_TCB_SIZE + 0x7000).  As we define TLS_DTV_AT_TP we can
    assume that the pthread_descr is allocated immediately ahead of the
    TCB.  This implies that the pthread_descr address is
-   R13-(TLS_PRE_TCB_SIZE + TLS_TCB_SIZE + 0x7000).  */
+   TP-(TLS_PRE_TCB_SIZE + TLS_TCB_SIZE + 0x7000).  */
 #  define TLS_TCB_OFFSET	0x7000
 
 /* The DTV is allocated at the TP; the TCB is placed elsewhere.  */
diff -urN cvs/libc/linuxthreads/sysdeps/unix/sysv/linux/powerpc/powerpc32/sysdep-cancel.h libc/linuxthreads/sysdeps/unix/sysv/linux/powerpc/powerpc32/sysdep-cancel.h
--- cvs/libc/linuxthreads/sysdeps/unix/sysv/linux/powerpc/powerpc32/sysdep-cancel.h	2003-02-18 11:15:16.000000000 +1100
+++ libc/linuxthreads/sysdeps/unix/sysv/linux/powerpc/powerpc32/sysdep-cancel.h	2003-02-27 19:57:49.000000000 +1100
@@ -78,19 +78,46 @@
 # ifdef IS_IN_libpthread
 #  define CENABLE	bl JUMPTARGET(__pthread_enable_asynccancel)
 #  define CDISABLE	bl JUMPTARGET(__pthread_disable_asynccancel)
+#  define __local_multiple_threads __pthread_multiple_threads
 # else
 #  define CENABLE	bl JUMPTARGET(__libc_enable_asynccancel)
 #  define CDISABLE	bl JUMPTARGET(__libc_disable_asynccancel)
+#  define __local_multiple_threads __libc_multiple_threads
 # endif
 
-# ifndef __ASSEMBLER__
-#  define SINGLE_THREAD_P						\
+# if !USE_TLS
+#  ifndef __ASSEMBLER__
+#   define SINGLE_THREAD_P						\
   __builtin_expect (THREAD_GETMEM (THREAD_SELF,				\
 				     p_header.data.multiple_threads) == 0, 1)
-# else
+#  else
 #  define SINGLE_THREAD_P						\
   lwz 10,MULTIPLE_THREADS_OFFSET(2);					\
   cmpwi 10,0
+#  endif
+
+# else /* USE_TLS */
+#  ifndef __ASSEMBLER__
+extern int __local_multiple_threads attribute_hidden;
+#   define SINGLE_THREAD_P __builtin_expect (__local_multiple_threads == 0, 1)
+#  else
+#   if !defined PIC
+#    define SINGLE_THREAD_P						\
+  lis 10,__local_multiple_threads at ha;					\
+  lwz 10,__local_multiple_threads at l(10);				\
+  cmpwi 10,0
+#   else
+#    define SINGLE_THREAD_P						\
+  mflr 9;								\
+  bl _GLOBAL_OFFSET_TABLE_ at local-4;					\
+  mflr 10;								\
+  mtlr 9;								\
+  lwz 10,__local_multiple_threads at got(10);				\
+  lwz 10,0(10);								\
+  cmpwi 10,0
+#   endif
+#  endif
+
 # endif
 
 #elif !defined __ASSEMBLER__
diff -urN cvs/libc/sysdeps/powerpc/powerpc32/dl-machine.c libc/sysdeps/powerpc/powerpc32/dl-machine.c
--- cvs/libc/sysdeps/powerpc/powerpc32/dl-machine.c	2002-11-21 15:10:53.000000000 +1100
+++ libc/sysdeps/powerpc/powerpc32/dl-machine.c	2003-02-28 15:14:05.000000000 +1100
@@ -433,6 +433,12 @@
       *(Elf32_Half*) reloc_addr = finaladdr;
       break;
 
+    case R_PPC_TPREL16:
+      if (__builtin_expect (finaladdr > 0x7fff && finaladdr < 0xffff8000, 0))
+	dl_reloc_overflow (map,  "R_PPC_TPREL16", reloc_addr, sym, refsym);
+      *(Elf32_Half*) reloc_addr = finaladdr;
+      break;
+
     case R_PPC_UADDR16:
       if (__builtin_expect (finaladdr > 0x7fff && finaladdr < 0xffff8000, 0))
 	dl_reloc_overflow (map,  "R_PPC_UADDR16", reloc_addr, sym, refsym);
@@ -441,14 +447,17 @@
       break;
 
     case R_PPC_ADDR16_LO:
+    case R_PPC_TPREL16_LO:
       *(Elf32_Half*) reloc_addr = finaladdr;
       break;
 
     case R_PPC_ADDR16_HI:
+    case R_PPC_TPREL16_HI:
       *(Elf32_Half*) reloc_addr = finaladdr >> 16;
       break;
 
     case R_PPC_ADDR16_HA:
+    case R_PPC_TPREL16_HA:
       *(Elf32_Half*) reloc_addr = (finaladdr + 0x8000) >> 16;
       break;
 
diff -urN cvs/libc/sysdeps/powerpc/powerpc32/dl-machine.h libc/sysdeps/powerpc/powerpc32/dl-machine.h
--- cvs/libc/sysdeps/powerpc/powerpc32/dl-machine.h	2003-01-31 07:25:44.000000000 +1100
+++ libc/sysdeps/powerpc/powerpc32/dl-machine.h	2003-02-28 22:32:11.000000000 +1100
@@ -23,6 +23,7 @@
 #define ELF_MACHINE_NAME "powerpc"
 
 #include <assert.h>
+#include <dl-tls.h>
 
 /* Return nonzero iff ELF header is compatible with the running host.  */
 static inline int
@@ -275,11 +276,22 @@
 /* We never want to use a PLT entry as the destination of a
    reloc, when what is being relocated is a branch. This is
    partly for efficiency, but mostly so we avoid loops.  */
+#if defined USE_TLS && (!defined RTLD_BOOTSTRAP || USE___THREAD)
+#define elf_machine_type_class(type)			\
+  ((((type) == R_PPC_JMP_SLOT				\
+    || (type) == R_PPC_REL24				\
+    || (type) == R_PPC_DTPMOD32				\
+    || (type) == R_PPC_DTPREL32				\
+    || (type) == R_PPC_TPREL32				\
+    || (type) == R_PPC_ADDR24) * ELF_RTYPE_CLASS_PLT)	\
+   | (((type) == R_PPC_COPY) * ELF_RTYPE_CLASS_COPY))
+#else
 #define elf_machine_type_class(type) \
   ((((type) == R_PPC_JMP_SLOT				\
     || (type) == R_PPC_REL24				\
     || (type) == R_PPC_ADDR24) * ELF_RTYPE_CLASS_PLT)	\
    | (((type) == R_PPC_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_PPC_JMP_SLOT
@@ -341,13 +353,16 @@
 		  Elf32_Addr *const reloc_addr)
 {
   const Elf32_Sym *const refsym = sym;
-  Elf32_Word finaladdr;
+  Elf32_Word finaladdr, rawvalue;
+  struct link_map *sym_map = NULL;
   const int rinfo = ELF32_R_TYPE (reloc->r_info);
 
 #ifndef RESOLVE_CONFLICT_FIND_MAP
   if (__builtin_expect (rinfo == R_PPC_NONE, 0))
     return;
 
+  finaladdr = rawvalue = reloc->r_addend;
+
   /* The condition on the next two lines is a hack around a bug in Solaris
      tools on Sparc.  It's not clear whether it should really be here at all,
      but if not the binutils need to be changed.  */
@@ -357,25 +372,25 @@
     {
       /* Has already been relocated.  */
       Elf32_Word loadbase = map->l_addr;
-      finaladdr = loadbase + reloc->r_addend;
+      finaladdr += loadbase;
     }
   else
     {
-      Elf32_Word loadbase
-	= (Elf32_Word) (char *) (RESOLVE (&sym, version,
-					  ELF32_R_TYPE(reloc->r_info)));
+      Elf32_Word loadbase = 0;
+
+      sym_map = RESOLVE_MAP (&sym, version, rinfo);
+      if (sym_map)
+	loadbase = sym_map->l_addr;
       if (sym == NULL)
 	{
 	  /* Weak symbol that wasn't actually defined anywhere.  */
 	  assert (loadbase == 0);
-	  finaladdr = reloc->r_addend;
 	}
       else
-	finaladdr = (loadbase + (Elf32_Word) (char *) sym->st_value
-		     + reloc->r_addend);
+	rawvalue += (Elf32_Word) (char *) sym->st_value;
+      finaladdr = rawvalue + loadbase;
     }
 #else
-  finaladdr = reloc->r_addend;
   if (rinfo == R_PPC_JMP_SLOT)
     RESOLVE_CONFLICT_FIND_MAP (map, reloc_addr);
 #endif
@@ -392,6 +407,44 @@
     {
       *reloc_addr = finaladdr;
     }
+
+#if defined USE_TLS && (!defined RTLD_BOOTSTRAP || USE___THREAD)
+  else if (rinfo == R_PPC_DTPMOD32)
+    {
+#ifdef RTLD_BOOTSTRAP
+      /* During startup the dynamic linker is always index 1.  */
+      *reloc_addr = 1;
+#else
+      /* Get the information from the link map returned by the
+	 RESOLVE_MAP function.  */
+      if (sym_map != NULL)
+	*reloc_addr = sym_map->l_tls_modid;
+#endif
+    }
+  else if (rinfo == R_PPC_DTPREL32)
+    {
+#ifndef RTLD_BOOTSTRAP
+      /* During relocation all TLS symbols are defined and used.
+	 Therefore the offset is already correct.  */
+      *reloc_addr = rawvalue - TLS_DTV_OFFSET;
+#endif
+    }
+  else if (rinfo == R_PPC_TPREL32)
+    {
+#ifdef RTLD_BOOTSTRAP
+      *reloc_addr = rawvalue + sym_map->l_tls_offset
+	      - TLS_TCB_SIZE - TLS_TP_OFFSET;
+#else
+      if (sym_map)
+      {
+        CHECK_STATIC_TLS (map, sym_map);
+        *reloc_addr = rawvalue + sym_map->l_tls_offset
+		- TLS_TCB_SIZE - TLS_TP_OFFSET;
+      }
+#endif
+    }
+#endif /* USE_TLS etc. */
+
   else
     __process_machine_rela (map, reloc, sym, refsym,
 			    reloc_addr, finaladdr, rinfo);
diff -urN cvs/libc/sysdeps/powerpc/powerpc32/elf/configure.in libc/sysdeps/powerpc/powerpc32/elf/configure.in
--- cvs/libc/sysdeps/powerpc/powerpc32/elf/configure.in	Thu Jan 01 10:00:00 1970
+++ libc/sysdeps/powerpc/powerpc32/elf/configure.in	Fri Feb 21 15:08:42 2003
@@ -0,0 +1,42 @@
+GLIBC_PROVIDES dnl See aclocal.m4 in the top level source directory.
+# Local configure fragment for sysdeps/powerpc32/elf.
+
+if test "$usetls" != no; then
+# Check for support of thread-local storage handling in assembler and
+# linker.
+AC_CACHE_CHECK(for powerpc32 TLS support, libc_cv_powerpc32_tls, [dnl
+cat > conftest.s <<\EOF
+	.section ".tdata","awT",@progbits
+x:	.long	1
+x1:	.long	1
+x2:	.long	1
+	.text
+	addi	3,31,x at got@tlsgd
+	addi	3,31,x1 at got@tlsld
+	addi	9,3,x1 at dtprel
+	addis	9,3,x2 at dtprel@ha
+	addi	9,9,x2 at dtprel@l
+	lwz	0,x1 at dtprel(3)
+	addis	9,3,x2 at dtprel@ha
+	lwz	0,x2 at dtprel@l(9)
+	lwz	9,x3 at got@tprel(31)
+	add	9,9,x at tls
+	addi	9,2,x1 at tprel
+	addis	9,2,x2 at tprel@ha
+	addi	9,9,x2 at tprel@l
+EOF
+dnl
+if AC_TRY_COMMAND(${CC-cc} -c $CFLAGS conftest.s 1>&AS_MESSAGE_LOG_FD); then
+  libc_cv_powerpc32_tls=yes
+else
+  libc_cv_powerpc32_tls=no
+fi
+rm -f conftest*])
+if test $libc_cv_powerpc32_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)


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