diff --git a/src/runtime/asm_amd64.s b/src/runtime/asm_amd64.s index ab3f639929..b9efad0681 100644 --- a/src/runtime/asm_amd64.s +++ b/src/runtime/asm_amd64.s @@ -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(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 diff --git a/src/runtime/proc.go b/src/runtime/proc.go index a666f86abc..35996b99d7 100644 --- a/src/runtime/proc.go +++ b/src/runtime/proc.go @@ -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 diff --git a/src/runtime/sys_windows_amd64.s b/src/runtime/sys_windows_amd64.s index 574def1038..8a91741619 100644 --- a/src/runtime/sys_windows_amd64.s +++ b/src/runtime/sys_windows_amd64.s @@ -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 index 0000000000..95dafd007c --- /dev/null +++ b/src/runtime/tls_stub.go @@ -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 index 0000000000..cacaa84496 --- /dev/null +++ b/src/runtime/tls_windows_amd64.go @@ -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)