Patchwork [03/11] nds32: Thread-Local Storage Support

login
register
mail settings
Submitter Vincent Chen
Date May 6, 2018, 2:41 p.m.
Message ID <1525617685-32083-4-git-send-email-vincentc@andestech.com>
Download mbox | patch
Permalink /patch/27131/
State New
Headers show

Comments

Vincent Chen - May 6, 2018, 2:41 p.m.
This patch implements TLS mechanism for nds32. 4 TLS addressing mode
(LE, IE, LD, GD) is supported when running on Linux via NPTL.
---
 sysdeps/nds32/dl-tls.h             |  28 +++++++
 sysdeps/nds32/dl-tlsdesc.S         | 104 ++++++++++++++++++++++++
 sysdeps/nds32/dl-tlsdesc.h         |  62 ++++++++++++++
 sysdeps/nds32/nptl/tcb-offsets.sym |   7 ++
 sysdeps/nds32/nptl/tls.h           | 160 +++++++++++++++++++++++++++++++++++++
 sysdeps/nds32/tls-macros.h         |  75 +++++++++++++++++
 sysdeps/nds32/tlsdesc.c            |  38 +++++++++
 sysdeps/nds32/tlsdesc.sym          |  16 ++++
 8 files changed, 490 insertions(+)
 create mode 100644 sysdeps/nds32/dl-tls.h
 create mode 100644 sysdeps/nds32/dl-tlsdesc.S
 create mode 100644 sysdeps/nds32/dl-tlsdesc.h
 create mode 100644 sysdeps/nds32/nptl/tcb-offsets.sym
 create mode 100644 sysdeps/nds32/nptl/tls.h
 create mode 100644 sysdeps/nds32/tls-macros.h
 create mode 100644 sysdeps/nds32/tlsdesc.c
 create mode 100644 sysdeps/nds32/tlsdesc.sym

Patch

diff --git a/sysdeps/nds32/dl-tls.h b/sysdeps/nds32/dl-tls.h
new file mode 100644
index 0000000..385d031
--- /dev/null
+++ b/sysdeps/nds32/dl-tls.h
@@ -0,0 +1,28 @@ 
+/* Thread-local storage handling in the ELF dynamic linker.  Andes nds32 version.
+   Copyright (C) 2013 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, see
+   <http://www.gnu.org/licenses/>.  */
+
+
+/* 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;
+
+
+extern void *__tls_get_addr (tls_index *ti);
diff --git a/sysdeps/nds32/dl-tlsdesc.S b/sysdeps/nds32/dl-tlsdesc.S
new file mode 100644
index 0000000..d677740
--- /dev/null
+++ b/sysdeps/nds32/dl-tlsdesc.S
@@ -0,0 +1,104 @@ 
+/* Thread-local storage handling in the ELF dynamic linker, Andes nds32 version.
+   Copyright (C) 2006-2013 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, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <sysdep.h>
+#include <tls.h>
+#include "tlsdesc.h"
+
+	.text
+	.hidden _dl_tlsdesc_return
+	.global	_dl_tlsdesc_return
+	.type	_dl_tlsdesc_return,#function
+	cfi_startproc
+	.align 2
+_dl_tlsdesc_return:
+	lwi	$r0,	[$r0	+ 4]
+	add	$r0,	$r0,	$r25
+	ret
+	cfi_endproc
+	.size   _dl_tlsdesc_return, .-_dl_tlsdesc_return
+
+	.hidden _dl_tlsdesc_undefweak
+	.global	_dl_tlsdesc_undefweak
+	.type	_dl_tlsdesc_undefweak,#function
+	cfi_startproc
+	.align 2
+_dl_tlsdesc_undefweak:
+	ret
+	cfi_endproc
+	.size   _dl_tlsdesc_undefweak, .-_dl_tlsdesc_undefweak
+
+#ifdef SHARED
+	/* Handler for dynamic TLS symbols.
+	   Prototype:
+	   _dl_tlsdesc_dynamic (tlsdesc *) ;
+
+	  ptrdiff_t
+	  _dl_tlsdesc_dynamic(struct tlsdesc *tdp)
+	  {
+            struct tlsdesc_dynamic_arg *td = tdp->argument.pointer;
+            dtv_t *dtv = (dtv_t *)THREAD_DTV();
+            if (__builtin_expect (td->gen_count <= dtv[0].counter
+               && (dtv[td->tlsinfo.ti_module].pointer.val
+                  != TLS_DTV_UNALLOCATED),
+               1))
+               return dtv[td->tlsinfo.ti_module].pointer.val +
+                       td->tlsinfo.ti_offset;
+
+             return __tls_get_addr (&td->tlsinfo);
+           }
+	*/
+	.hidden _dl_tlsdesc_dynamic
+	.global	_dl_tlsdesc_dynamic
+	.type	_dl_tlsdesc_dynamic,#function
+	cfi_startproc
+	.pic
+	.align 2
+
+_dl_tlsdesc_dynamic:
+	lwi	$r0,	[$r0 + 4]                  /* $r0 = td.  */
+	lwi	$r1,	[$r0 + #TLSDESC_GEN_COUNT] /* $r1 = td->gen_count.  */
+	lwi	$r2,	[$r25 +	#DTV_OFFSET]	   /* $r2 = &dtv[0].  */
+	lwi	$r3,	[$r2]                      /* $r3 = module id.  */
+	sub	$r1,	$r1,	$r3
+	bgtz	$r1,	2f
+	lwi	$r3,	[$r0 + #TLSDESC_MODID]
+	slli	$r3,	$r3,	#3  /* $r3 = module offset = ID * 8.  */
+	lw	$r3,	[$r2 + $r3] /* $r3 = &dtc[ID] = &dtv[0]+ module offset.  */
+	movi	$r1,	#TLS_DTV_UNALLOCATED
+	beq	$r3,	$r1,	2f
+	lwi	$r1,	[$r0 + #TLSDESC_MODOFF]
+	add	$r0,	$r3,	$r1
+1:	
+	ret
+2:
+	smw.adm $sp,[$sp],$sp,#0x6
+	.cfi_adjust_cfa_offset 8
+	.cfi_rel_offset gp, 0
+	.cfi_rel_offset lp, 4
+	GET_GTABLE ($gp)
+	la	$r15, HIDDEN_JUMPTARGET (__tls_get_addr@PLT)
+	jral 	$r15
+	lmw.bim $sp,[$sp],$sp,#0x6
+	.cfi_adjust_cfa_offset -8
+	.cfi_restore gp
+	.cfi_restore lp
+	j	1b
+	cfi_endproc
+	.size   _dl_tlsdesc_dynamic, .-_dl_tlsdesc_dynamic
+#endif /* SHARED */
diff --git a/sysdeps/nds32/dl-tlsdesc.h b/sysdeps/nds32/dl-tlsdesc.h
new file mode 100644
index 0000000..16d2270
--- /dev/null
+++ b/sysdeps/nds32/dl-tlsdesc.h
@@ -0,0 +1,62 @@ 
+/* Thread-local storage descriptor handling in the ELF dynamic linker.
+   Andes nds32 version.
+   Copyright (C) 2005-2013 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; witout 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, see
+   <http://www.gnu.org/licenses/>.  */
+
+#ifndef _NDS32_DL_TLSDESC_H
+# define _NDS32_DL_TLSDESC_H 1
+
+/* Type used to represent a TLS descriptor in the GOT.  */
+struct tlsdesc
+{
+  ptrdiff_t (*entry)(struct tlsdesc *);
+  union
+    {
+      void *pointer;
+      long value;
+    } argument;
+};
+
+
+typedef struct dl_tls_index
+{
+  unsigned long int ti_module;
+  unsigned long int ti_offset;
+} tls_index;
+
+/* Type used as the argument in a TLS descriptor for a symbol that
+   needs dynamic TLS offsets.  */
+struct tlsdesc_dynamic_arg
+{
+  tls_index tlsinfo;
+  size_t gen_count;
+};
+
+extern ptrdiff_t attribute_hidden
+_dl_tlsdesc_return(struct tlsdesc *);
+
+extern ptrdiff_t attribute_hidden
+_dl_tlsdesc_undefweak(struct tlsdesc *);
+
+# ifdef SHARED
+extern void *_dl_make_tlsdesc_dynamic (struct link_map *map, size_t ti_offset);
+
+extern ptrdiff_t attribute_hidden
+_dl_tlsdesc_dynamic(struct tlsdesc *);
+# endif
+
+#endif /* nds32/dl-tlsdesc.h */
diff --git a/sysdeps/nds32/nptl/tcb-offsets.sym b/sysdeps/nds32/nptl/tcb-offsets.sym
new file mode 100644
index 0000000..333dd53
--- /dev/null
+++ b/sysdeps/nds32/nptl/tcb-offsets.sym
@@ -0,0 +1,7 @@ 
+#include <sysdep.h>
+#include <tls.h>
+
+#define thread_offsetof(mem)    (long)(offsetof (struct pthread, mem) - TLS_TCB_OFFSET - TLS_PRE_TCB_SIZE)
+
+MULTIPLE_THREADS_OFFSET         thread_offsetof (header.multiple_threads)
+TID_OFFSET                      thread_offsetof (tid)
diff --git a/sysdeps/nds32/nptl/tls.h b/sysdeps/nds32/nptl/tls.h
new file mode 100644
index 0000000..59c5557
--- /dev/null
+++ b/sysdeps/nds32/nptl/tls.h
@@ -0,0 +1,160 @@ 
+/* Definition for thread-local data handling, Andes NPTL/nds32 version.
+   Copyright (C) 2011-2018 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, see
+   <http://www.gnu.org/licenses/>.  */
+
+#ifndef _NDS32_TLS_H
+#define _NDS32_TLS_H	1
+
+#include <dl-sysdep.h>
+
+#ifndef __ASSEMBLER__
+# include <stdbool.h>
+# include <stddef.h>
+# include <stdint.h>
+# include <dl-dtv.h>
+
+#else
+# include <tcb-offsets.h>
+#endif /* __ASSEMBLER__ */
+
+
+#ifndef __ASSEMBLER__
+
+/* Get system call information.  */
+# include <sysdep.h>
+
+/* The TP points to the start of the thread blocks.  */
+# define TLS_DTV_AT_TP	1
+# define TLS_TCB_AT_TP	0
+
+/* We use the multiple_threads field in the pthread struct.  */
+# define TLS_MULTIPLE_THREADS_IN_TCB	1
+
+/* Get the thread descriptor definition.  */
+# include <nptl/descr.h>
+
+typedef struct
+{
+  dtv_t *dtv;
+  void *private;
+} tcbhead_t;
+
+/* This is the size of the initial TCB.  */
+# define TLS_INIT_TCB_SIZE      0
+
+/* Alignment requirements for the initial TCB.  */
+# define TLS_INIT_TCB_ALIGN     __alignof__ (struct pthread)
+
+/* This is the size of the TCB.  */
+# define TLS_TCB_SIZE           0
+
+/* Alignment requirements for the TCB.  */
+# define TLS_TCB_ALIGN          __alignof__ (struct pthread)
+
+
+
+/* This is the size we need before TCB - actually, it includes the TCB.  */
+# define TLS_PRE_TCB_SIZE \
+  (sizeof (struct pthread)						      \
+   + ((sizeof (tcbhead_t) + TLS_TCB_ALIGN - 1) & ~(TLS_TCB_ALIGN - 1)))
+
+/* Return the thread descriptor (tp) for the current thread.  */
+register void *__thread_pointer asm ("$r25");
+
+
+/* The thread pointer tp points to the end of the TCB.
+ * The pthread_descr structure is immediately in front of the TCB.  */
+# define TLS_TCB_OFFSET	0
+
+/* 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))[-1].dtv = (dtvp) + 1)
+
+/* Install new dtv for current thread.  */
+# define INSTALL_NEW_DTV(dtv) (THREAD_DTV() = (dtv))
+
+/* Return dtv of given thread descriptor.  */
+# define GET_DTV(tcbp)	(((tcbhead_t *) (tcbp))[-1].dtv)
+
+/* Code to initially initialize the thread pointer (tp).  */
+# define TLS_INIT_TP(tcbp) \
+    (__thread_pointer = (char *)(tcbp) + TLS_TCB_OFFSET, NULL)
+
+/* Value passed to 'clone' for initialization of the thread register.  */
+# define TLS_DEFINE_INIT_TP(tp, pd) \
+  void *tp = (void *) (pd) + TLS_TCB_OFFSET + TLS_PRE_TCB_SIZE
+
+/* Return the address of the dtv for the current thread.  */
+# define THREAD_DTV() \
+    (((tcbhead_t *) (__thread_pointer - TLS_TCB_OFFSET))[-1].dtv)
+
+/* Return the thread descriptor for the current thread.  */
+# define THREAD_SELF \
+    ((struct pthread *) (__thread_pointer \
+			 - TLS_TCB_OFFSET - TLS_PRE_TCB_SIZE))
+
+/* Magic for libthread_db to know how to do THREAD_SELF.  */
+# define DB_THREAD_SELF \
+  REGISTER (32, 32, 26 * 4, - TLS_TCB_OFFSET - TLS_PRE_TCB_SIZE)
+
+/* Read member of the thread descriptor directly.  */
+# define THREAD_GETMEM(descr, member) (descr->member)
+
+/* Same as THREAD_GETMEM, but the member offset can be non-constant.  */
+# define THREAD_GETMEM_NC(descr, member, idx) \
+    (descr->member[idx])
+
+/* Set member of the thread descriptor directly.  */
+# define THREAD_SETMEM(descr, member, value) \
+    (descr->member = (value))
+
+/* Same as THREAD_SETMEM, but the member offset can be non-constant.  */
+# define THREAD_SETMEM_NC(descr, member, idx, value) \
+    (descr->member[idx] = (value))
+
+
+/* l_tls_offset == 0 is perfectly valid, so we have to use some different
+    value to mean unset l_tls_offset.  */
+# define NO_TLS_OFFSET		-1
+
+/* Get and set the global scope generation counter in struct pthread.  */
+# define THREAD_GSCOPE_FLAG_UNUSED 0
+# define THREAD_GSCOPE_FLAG_USED   1
+# define THREAD_GSCOPE_FLAG_WAIT   2
+# define THREAD_GSCOPE_RESET_FLAG() \
+  do									     \
+    { int __res								     \
+	= atomic_exchange_rel (&THREAD_SELF->header.gscope_flag,	     \
+			       THREAD_GSCOPE_FLAG_UNUSED);		     \
+      if (__res == THREAD_GSCOPE_FLAG_WAIT)				     \
+	lll_futex_wake (&THREAD_SELF->header.gscope_flag, 1, LLL_PRIVATE);   \
+    }									     \
+  while (0)
+# define THREAD_GSCOPE_SET_FLAG() \
+  do									     \
+    {									     \
+      THREAD_SELF->header.gscope_flag = THREAD_GSCOPE_FLAG_USED;	     \
+      atomic_write_barrier ();						     \
+    }									     \
+  while (0)
+# define THREAD_GSCOPE_WAIT() \
+  GL(dl_wait_lookup_done) ()
+
+#endif /* __ASSEMBLER__ */
+
+#endif /* tls.h */
diff --git a/sysdeps/nds32/tls-macros.h b/sysdeps/nds32/tls-macros.h
new file mode 100644
index 0000000..b6ff5c1
--- /dev/null
+++ b/sysdeps/nds32/tls-macros.h
@@ -0,0 +1,75 @@ 
+/* Macros to support TLS testing in times of missing compiler support.
+   Andes nds32 version.
+   Copyright (C) 2017-2018 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, see
+   <http://www.gnu.org/licenses/>.  */
+
+#define TLS_LE(x) 						\
+({	int *__l;						\
+	asm("sethi	%0, hi20("#x"@TPOFF)\n\t"		\
+            "ori	%0, %0, lo12("#x"@TPOFF)\n\t"		\
+            "add	%0, %0, $r25\n\t"			\
+	    :"=r"(__l));					\
+	__l;})
+
+#ifdef PIC
+# define TLS_IE(x)						\
+({	int *__l;						\
+	asm(".relax_hint begin\n\t"				\
+            "sethi	%0, hi20("#x"@GOTTPOFF)\n\t"		\
+            ".relax_hint\n\t"					\
+            "ori	%0, %0, lo12("#x"@GOTTPOFF)\n\t"	\
+            ".relax_hint end\n\t"				\
+            "lw	%0, [%0 + $gp]\n\t"				\
+            "add	%0, %0, $r25\n\t"			\
+            :"=r"(__l));					\
+	__l;})
+#else
+# define TLS_IE(x) 						\
+({	int *__l;						\
+	asm(".relax_hint begin\n\t"				\
+            "sethi 	%0, hi20("#x"@GOTTPOFF)\n\t"		\
+            ".relax_hint end\n\t"				\
+            "lwi 	%0, [%0 + lo12("#x"@GOTTPOFF)]\n\t"	\
+            "add	%0, %0, $r25\n\t"			\
+            :"=r"(__l));					\
+	__l;})
+#endif
+
+#define TLS_LD(x) TLS_GD(x)
+
+#define TLS_GD(x)						\
+({	int *__l;	                                        \
+	asm("smw.adm $r1,[$sp],$r5,#0\n\t"			\
+            "smw.adm $r16,[$sp],$r24,#0\n\t"			\
+            ".relax_hint begin\n\t"				\
+            "sethi	$r0, hi20("#x"@TLSDESC)\n\t"		\
+            ".relax_hint\n\t"					\
+            "ori	$r0, $r0, lo12("#x"@TLSDESC)\n\t"	\
+            ".relax_hint\n\t"					\
+            "lw 	$r15, [$r0 + $gp]\n\t"			\
+            ".relax_hint\n\t"					\
+            "add 	$r0, $r0, $gp\n\t"			\
+            ".relax_hint end\n\t"				\
+            "jral 	$r15\n\t"	        		\
+            "lmw.bim $r16,[$sp],$r24,#0\n\t"                	\
+            "lmw.bim $r1,[$sp],$r5,#0\n\t"                  	\
+            "move	%0, $r0\n\t"				\
+            :"=r"(__l)						\
+            :							\
+            :"$r0","$r15");					\
+	__l;})
diff --git a/sysdeps/nds32/tlsdesc.c b/sysdeps/nds32/tlsdesc.c
new file mode 100644
index 0000000..65d0be0
--- /dev/null
+++ b/sysdeps/nds32/tlsdesc.c
@@ -0,0 +1,38 @@ 
+/* Manage TLS descriptors, Andes nds32 version.
+   Copyright (C) 2005-2013 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, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <ldsodefs.h>
+#include <tls.h>
+#include <dl-tlsdesc.h>
+#include <dl-unmap-segments.h>
+#define _dl_tlsdesc_resolve_hold 0
+#include <tlsdeschtab.h>
+
+/* Unmap the dynamic object, but also release its TLS descriptor table
+   if there is one.  */
+
+void
+_dl_unmap (struct link_map *map)
+{
+  _dl_unmap_segments (map);
+
+#ifdef SHARED
+  if (map->l_mach.tlsdesc_table)
+    htab_delete (map->l_mach.tlsdesc_table);
+#endif
+}
diff --git a/sysdeps/nds32/tlsdesc.sym b/sysdeps/nds32/tlsdesc.sym
new file mode 100644
index 0000000..0a34a74
--- /dev/null
+++ b/sysdeps/nds32/tlsdesc.sym
@@ -0,0 +1,16 @@ 
+#include <stddef.h>
+#include <sysdep.h>
+#include <tls.h>
+#include <link.h>
+#include <dl-tlsdesc.h>
+
+#define dtv_offsetof(dtv)   (offsetof (tcbhead_t, dtv) - TLS_TCB_OFFSET - sizeof (tcbhead_t))
+
+DTV_OFFSET          dtv_offsetof (dtv)
+
+TLSDESC_ARG         offsetof (struct tlsdesc, argument.pointer)
+
+TLSDESC_GEN_COUNT   offsetof (struct tlsdesc_dynamic_arg, gen_count)
+TLSDESC_MODID       offsetof (struct tlsdesc_dynamic_arg, tlsinfo.ti_module)
+TLSDESC_MODOFF      offsetof (struct tlsdesc_dynamic_arg, tlsinfo.ti_offset)
+TLS_DTV_UNALLOCATED     TLS_DTV_UNALLOCATED