1
0
mirror of https://github.com/golang/go synced 2024-09-24 07:20:14 -06:00

runtime: bypass ABI wrapper when calling needm on Windows

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>
This commit is contained in:
Michael Anthony Knyszek 2021-03-18 17:03:50 +00:00 committed by Michael Knyszek
parent 771c57e68e
commit fef5a15396
5 changed files with 54 additions and 12 deletions

View File

@ -796,7 +796,18 @@ TEXT ·cgocallback(SB),NOSPLIT,$24-24
MOVQ BX, savedm-8(SP) // saved copy of oldm MOVQ BX, savedm-8(SP) // saved copy of oldm
JMP havem JMP havem
needm: 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 CALL AX
MOVQ $0, savedm-8(SP) // dropm on return MOVQ $0, savedm-8(SP) // dropm on return
get_tls(CX) get_tls(CX)
@ -890,9 +901,17 @@ havem:
// for the duration of the call. Since the call is over, return it with dropm. // for the duration of the call. Since the call is over, return it with dropm.
MOVQ savedm-8(SP), BX MOVQ savedm-8(SP), BX
CMPQ BX, $0 CMPQ BX, $0
JNE 3(PC) JNE done
MOVQ $runtime·dropm(SB), AX MOVQ $runtime·dropm(SB), AX
CALL 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! // Done!
RET RET
@ -901,16 +920,6 @@ havem:
// set g. for use by needm. // set g. for use by needm.
TEXT runtime·setg(SB), NOSPLIT, $0-8 TEXT runtime·setg(SB), NOSPLIT, $0-8
MOVQ gg+0(FP), BX 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) get_tls(CX)
MOVQ BX, g(CX) MOVQ BX, g(CX)
RET RET

View File

@ -1883,6 +1883,10 @@ func needm() {
// Store the original signal mask for use by minit. // Store the original signal mask for use by minit.
mp.sigmask = sigmask 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 // Install g (= m->g0) and set the stack bounds
// to match the current stack. We don't actually know // to match the current stack. We don't actually know
// how big the stack is, like we don't know how big any // how big the stack is, like we don't know how big any

View File

@ -518,3 +518,11 @@ wall:
useQPC: useQPC:
JMP runtime·nowQPC(SB) JMP runtime·nowQPC(SB)
RET 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

11
src/runtime/tls_stub.go Normal file
View File

@ -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) {}

View File

@ -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)