aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorCherry Zhang <cherryyz@google.com>2020-10-24 13:14:36 -0400
committerCherry Zhang <cherryyz@google.com>2020-10-28 13:25:44 +0000
commit72dec90bfdb60a0ca2ac1b743db472d2e689414e (patch)
tree9c3e315b322275e8b55f01c40757bb0ed2f47b25 /src
parentcf6cfba4d5358404dd890f6025e573a4b2156543 (diff)
downloadgo-72dec90bfdb60a0ca2ac1b743db472d2e689414e.tar.xz
runtime: set up TLS without cgo on darwin/arm64
Currently, on darwin/arm64 we set up TLS using cgo. TLS is not set for pure Go programs. As we use libc for syscalls on darwin, we need to save the G register before the libc call. Otherwise it is not signal-safe, as a signal may land during the execution of a libc function, where the G register may be clobbered. This CL initializes TLS in Go, by calling the pthread functions directly without cgo. This makes it possible to save the G register to TLS in pure Go programs (done in a later CL). Inspired by Elias's CL 209197. Write the logic in Go instead of assembly. Updates #38485, #35853. Change-Id: I257ba2a411ad387b2f4d50d10129d37fec7a226e Reviewed-on: https://go-review.googlesource.com/c/go/+/265118 Trust: Cherry Zhang <cherryyz@google.com> Trust: Elias Naur <mail@eliasnaur.com> Run-TryBot: Cherry Zhang <cherryyz@google.com> TryBot-Result: Go Bot <gobot@golang.org> Reviewed-by: Ian Lance Taylor <iant@golang.org>
Diffstat (limited to 'src')
-rw-r--r--src/runtime/asm_arm64.s15
-rw-r--r--src/runtime/cgo/gcc_darwin_arm64.c36
-rw-r--r--src/runtime/defs_darwin_arm64.go4
-rw-r--r--src/runtime/sys_darwin_arm64.go62
-rw-r--r--src/runtime/sys_darwin_arm64.s12
5 files changed, 93 insertions, 36 deletions
diff --git a/src/runtime/asm_arm64.s b/src/runtime/asm_arm64.s
index a45e342478..6257c1a183 100644
--- a/src/runtime/asm_arm64.s
+++ b/src/runtime/asm_arm64.s
@@ -15,6 +15,19 @@ TEXT runtime·rt0_go(SB),NOSPLIT,$0
MOVW R0, 8(RSP) // argc
MOVD R1, 16(RSP) // argv
+#ifdef TLS_darwin
+ // Initialize TLS.
+ MOVD ZR, g // clear g, make sure it's not junk.
+ SUB $32, RSP
+ MRS_TPIDR_R0
+ AND $~7, R0
+ MOVD R0, 16(RSP) // arg2: TLS base
+ MOVD $runtime·tls_g(SB), R2
+ MOVD R2, 8(RSP) // arg1: &tlsg
+ BL ·tlsinit(SB)
+ ADD $32, RSP
+#endif
+
// create istack out of the given (operating system) stack.
// _cgo_init may update stackguard.
MOVD $runtime·g0(SB), g
@@ -29,9 +42,9 @@ TEXT runtime·rt0_go(SB),NOSPLIT,$0
MOVD _cgo_init(SB), R12
CBZ R12, nocgo
+#ifdef GOOS_android
MRS_TPIDR_R0 // load TLS base pointer
MOVD R0, R3 // arg 3: TLS base pointer
-#ifdef TLSG_IS_VARIABLE
MOVD $runtime·tls_g(SB), R2 // arg 2: &tls_g
#else
MOVD $0, R2 // arg 2: not used when using platform's TLS
diff --git a/src/runtime/cgo/gcc_darwin_arm64.c b/src/runtime/cgo/gcc_darwin_arm64.c
index dbe848b4ee..a5f07f1f1b 100644
--- a/src/runtime/cgo/gcc_darwin_arm64.c
+++ b/src/runtime/cgo/gcc_darwin_arm64.c
@@ -20,37 +20,6 @@
#include <CoreFoundation/CFString.h>
#endif
-#define magic (0xc476c475c47957UL)
-
-// inittls allocates a thread-local storage slot for g.
-//
-// It finds the first available slot using pthread_key_create and uses
-// it as the offset value for runtime.tlsg.
-static void
-inittls(void **tlsg, void **tlsbase)
-{
- pthread_key_t k;
- int i, err;
-
- err = pthread_key_create(&k, nil);
- if(err != 0) {
- fprintf(stderr, "runtime/cgo: pthread_key_create failed: %d\n", err);
- abort();
- }
- //fprintf(stderr, "runtime/cgo: k = %d, tlsbase = %p\n", (int)k, tlsbase); // debug
- pthread_setspecific(k, (void*)magic);
- // The first key should be at 257.
- for (i=0; i<PTHREAD_KEYS_MAX; i++) {
- if (*(tlsbase+i) == (void*)magic) {
- *tlsg = (void*)(i*sizeof(void *));
- pthread_setspecific(k, 0);
- return;
- }
- }
- fprintf(stderr, "runtime/cgo: could not find pthread key.\n");
- abort();
-}
-
static void *threadentry(void*);
static void (*setg_gcc)(void*);
@@ -156,7 +125,7 @@ init_working_dir()
#endif // TARGET_OS_IPHONE
void
-x_cgo_init(G *g, void (*setg)(void*), void **tlsg, void **tlsbase)
+x_cgo_init(G *g, void (*setg)(void*))
{
pthread_attr_t attr;
size_t size;
@@ -168,9 +137,6 @@ x_cgo_init(G *g, void (*setg)(void*), void **tlsg, void **tlsbase)
g->stacklo = (uintptr)&attr - size + 4096;
pthread_attr_destroy(&attr);
- // yes, tlsbase from mrs might not be correctly aligned.
- inittls(tlsg, (void**)((uintptr)tlsbase & ~7));
-
#if TARGET_OS_IPHONE
darwin_arm_init_mach_exception_handler();
darwin_arm_init_thread_exception_port();
diff --git a/src/runtime/defs_darwin_arm64.go b/src/runtime/defs_darwin_arm64.go
index 2f466045d4..9076e8bd54 100644
--- a/src/runtime/defs_darwin_arm64.go
+++ b/src/runtime/defs_darwin_arm64.go
@@ -94,6 +94,8 @@ const (
_PTHREAD_CREATE_DETACHED = 0x2
+ _PTHREAD_KEYS_MAX = 512
+
_F_SETFD = 0x2
_F_GETFL = 0x3
_F_SETFL = 0x4
@@ -233,3 +235,5 @@ type machTimebaseInfo struct {
numer uint32
denom uint32
}
+
+type pthreadkey uint64
diff --git a/src/runtime/sys_darwin_arm64.go b/src/runtime/sys_darwin_arm64.go
new file mode 100644
index 0000000000..9c14f33a1c
--- /dev/null
+++ b/src/runtime/sys_darwin_arm64.go
@@ -0,0 +1,62 @@
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package runtime
+
+import (
+ "runtime/internal/sys"
+ "unsafe"
+)
+
+// libc function wrappers. Must run on system stack.
+
+//go:nosplit
+//go:cgo_unsafe_args
+func g0_pthread_key_create(k *pthreadkey, destructor uintptr) int32 {
+ return asmcgocall(unsafe.Pointer(funcPC(pthread_key_create_trampoline)), unsafe.Pointer(&k))
+}
+func pthread_key_create_trampoline()
+
+//go:nosplit
+//go:cgo_unsafe_args
+func g0_pthread_setspecific(k pthreadkey, value uintptr) int32 {
+ return asmcgocall(unsafe.Pointer(funcPC(pthread_setspecific_trampoline)), unsafe.Pointer(&k))
+}
+func pthread_setspecific_trampoline()
+
+//go:cgo_import_dynamic libc_pthread_key_create pthread_key_create "/usr/lib/libSystem.B.dylib"
+//go:cgo_import_dynamic libc_pthread_setspecific pthread_setspecific "/usr/lib/libSystem.B.dylib"
+
+// tlsinit allocates a thread-local storage slot for g.
+//
+// It finds the first available slot using pthread_key_create and uses
+// it as the offset value for runtime.tlsg.
+//
+// This runs at startup on g0 stack, but before g is set, so it must
+// not split stack (transitively). g is expected to be nil, so things
+// (e.g. asmcgocall) will skip saving or reading g.
+//
+//go:nosplit
+func tlsinit(tlsg *uintptr, tlsbase *[_PTHREAD_KEYS_MAX]uintptr) {
+ var k pthreadkey
+ err := g0_pthread_key_create(&k, 0)
+ if err != 0 {
+ abort()
+ }
+
+ const magic = 0xc476c475c47957
+ err = g0_pthread_setspecific(k, magic)
+ if err != 0 {
+ abort()
+ }
+
+ for i, x := range tlsbase {
+ if x == magic {
+ *tlsg = uintptr(i * sys.PtrSize)
+ g0_pthread_setspecific(k, 0)
+ return
+ }
+ }
+ abort()
+}
diff --git a/src/runtime/sys_darwin_arm64.s b/src/runtime/sys_darwin_arm64.s
index f8d6f28dc7..31b997df13 100644
--- a/src/runtime/sys_darwin_arm64.s
+++ b/src/runtime/sys_darwin_arm64.s
@@ -497,6 +497,18 @@ TEXT runtime·pthread_kill_trampoline(SB),NOSPLIT,$0
BL libc_pthread_kill(SB)
RET
+TEXT runtime·pthread_key_create_trampoline(SB),NOSPLIT,$0
+ MOVD 8(R0), R1 // arg 2 destructor
+ MOVD 0(R0), R0 // arg 1 *key
+ BL libc_pthread_key_create(SB)
+ RET
+
+TEXT runtime·pthread_setspecific_trampoline(SB),NOSPLIT,$0
+ MOVD 8(R0), R1 // arg 2 value
+ MOVD 0(R0), R0 // arg 1 key
+ BL libc_pthread_setspecific(SB)
+ RET
+
// syscall calls a function in libc on behalf of the syscall package.
// syscall takes a pointer to a struct like:
// struct {