]> Cypherpunks repositories - gostls13.git/commitdiff
runtime: bypass ABI wrapper when calling needm on Windows
authorMichael Anthony Knyszek <mknyszek@google.com>
Thu, 18 Mar 2021 17:03:50 +0000 (17:03 +0000)
committerMichael Knyszek <mknyszek@google.com>
Wed, 24 Mar 2021 19:18:50 +0000 (19:18 +0000)
On Windows, when calling into needm in cgocallback on a new thread that
is unknown to the Go runtime, we currently call through an ABI wrapper.
The ABI wrapper tries to restore the G register from TLS.

On other platforms, TLS is set up just enough that the wrapper will
simply load a nil g from TLS, but on Windows TLS isn't set up at all, so
there's nowhere for the wrapper to load from.

So, bypass the wrapper in the call to needm. needm takes no arguments
and returns no results so there are no special ABI considerations,
except that we must clear X15 which is used as a zero register in Go
code (a function normally performed by the ABI wrapper). needm is also
otherwise already special and carefully crafted to avoid doing anything
that would require a valid G or M, at least until it is able to create
one.

While we're here, this change simplifies setg so that it doesn't set up
TLS on Windows and instead provides an OS-specific osSetupTLS to do
that.

The result of this is that setg(nil) no longer clears the TLS space
pointer on Windows. There's exactly one place this is used (dropm) where
it doesn't matter anymore, and an empty TLS means that setg's wrapper
will crash on the return path. Another result is that the G slot in the
TLS will be properly cleared, however, which isn't true today.

For #40724.

Change-Id: I65c3d924a3b16abe667b06fd91d467d6d5da31d7
Reviewed-on: https://go-review.googlesource.com/c/go/+/303070
Trust: Michael Knyszek <mknyszek@google.com>
Run-TryBot: Michael Knyszek <mknyszek@google.com>
Reviewed-by: Cherry Zhang <cherryyz@google.com>
src/runtime/asm_amd64.s
src/runtime/proc.go
src/runtime/sys_windows_amd64.s
src/runtime/tls_stub.go [new file with mode: 0644]
src/runtime/tls_windows_amd64.go [new file with mode: 0644]

index ab3f63992915fd56d5e638c6692b46a398c60915..b9efad06813d03be96e6c57158d5ef689d5713b6 100644 (file)
@@ -796,7 +796,18 @@ TEXT ·cgocallback(SB),NOSPLIT,$24-24
        MOVQ    BX, savedm-8(SP)        // saved copy of oldm
        JMP     havem
 needm:
-       MOVQ    $runtime·needm(SB), AX
+       // On some platforms (Windows) we cannot call needm through
+       // an ABI wrapper because there's no TLS set up, and the ABI
+       // wrapper will try to restore the G register (R14) from TLS.
+       // Clear X15 because Go expects it and we're not calling
+       // through a wrapper, but otherwise avoid setting the G
+       // register in the wrapper and call needm directly. It
+       // takes no arguments and doesn't return any values so
+       // there's no need to handle that. Clear R14 so that there's
+       // a bad value in there, in case needm tries to use it.
+       XORPS   X15, X15
+       XORQ    R14, R14
+       MOVQ    $runtime·needm<ABIInternal>(SB), AX
        CALL    AX
        MOVQ    $0, savedm-8(SP) // dropm on return
        get_tls(CX)
@@ -890,9 +901,17 @@ havem:
        // for the duration of the call. Since the call is over, return it with dropm.
        MOVQ    savedm-8(SP), BX
        CMPQ    BX, $0
-       JNE 3(PC)
+       JNE     done
        MOVQ    $runtime·dropm(SB), AX
        CALL    AX
+#ifdef GOOS_windows
+       // We need to clear the TLS pointer in case the next
+       // thread that comes into Go tries to reuse that space
+       // but uses the same M.
+       XORQ    DI, DI
+       CALL    runtime·settls(SB)
+#endif
+done:
 
        // Done!
        RET
@@ -901,16 +920,6 @@ havem:
 // set g. for use by needm.
 TEXT runtime·setg(SB), NOSPLIT, $0-8
        MOVQ    gg+0(FP), BX
-#ifdef GOOS_windows
-       CMPQ    BX, $0
-       JNE     settls
-       MOVQ    $0, 0x28(GS)
-       RET
-settls:
-       MOVQ    g_m(BX), AX
-       LEAQ    m_tls(AX), AX
-       MOVQ    AX, 0x28(GS)
-#endif
        get_tls(CX)
        MOVQ    BX, g(CX)
        RET
index a666f86abc042bc4e1182d90de348e94f89bd84f..35996b99d79309c2277ccc2f61f22ef1c044da7c 100644 (file)
@@ -1883,6 +1883,10 @@ func needm() {
        // Store the original signal mask for use by minit.
        mp.sigmask = sigmask
 
+       // Install TLS on some platforms (previously setg
+       // would do this if necessary).
+       osSetupTLS(mp)
+
        // Install g (= m->g0) and set the stack bounds
        // to match the current stack. We don't actually know
        // how big the stack is, like we don't know how big any
index 574def1038b882d3f81e7b1e0be4cfdbf57ad6a6..8a9174161914cb762595ca4a1eaf4eb0282b549f 100644 (file)
@@ -518,3 +518,11 @@ wall:
 useQPC:
        JMP     runtime·nowQPC(SB)
        RET
+
+// func osSetupTLS(mp *m)
+// Setup TLS. for use by needm on Windows.
+TEXT runtime·osSetupTLS(SB),NOSPLIT,$0-8
+       MOVQ    mp+0(FP), AX
+       LEAQ    m_tls(AX), DI
+       CALL    runtime·settls(SB)
+       RET
diff --git a/src/runtime/tls_stub.go b/src/runtime/tls_stub.go
new file mode 100644 (file)
index 0000000..95dafd0
--- /dev/null
@@ -0,0 +1,11 @@
+// Copyright 2021 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.
+
+//go:build (windows && !amd64) || !windows
+// +build windows,!amd64 !windows
+
+package runtime
+
+//go:nosplit
+func osSetupTLS(mp *m) {}
diff --git a/src/runtime/tls_windows_amd64.go b/src/runtime/tls_windows_amd64.go
new file mode 100644 (file)
index 0000000..cacaa84
--- /dev/null
@@ -0,0 +1,10 @@
+// Copyright 2021 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
+
+// osSetupTLS is called by needm to set up TLS for non-Go threads.
+//
+// Defined in assembly.
+func osSetupTLS(mp *m)