diff --git a/src/cmd/internal/obj/x86/obj6.go b/src/cmd/internal/obj/x86/obj6.go index b8c7ad7d1bb..06736d43bd1 100644 --- a/src/cmd/internal/obj/x86/obj6.go +++ b/src/cmd/internal/obj/x86/obj6.go @@ -912,7 +912,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) { } if autoffset != deltasp { - ctxt.Diag("unbalanced PUSH/POP") + ctxt.Diag("%s: unbalanced PUSH/POP", cursym) } if autoffset != 0 { diff --git a/src/runtime/cgo/abi_amd64.h b/src/runtime/cgo/abi_amd64.h new file mode 100644 index 00000000000..44cc0969dac --- /dev/null +++ b/src/runtime/cgo/abi_amd64.h @@ -0,0 +1,69 @@ +// 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. + +// Macros for transitioning from the host ABI to Go ABI0. +// +// TODO(austin): Define these for ELF platforms as well. + +#ifdef GOOS_windows + +// REGS_HOST_TO_ABI0_STACK is the stack bytes used by +// PUSH_REGS_HOST_TO_ABI0. +#define REGS_HOST_TO_ABI0_STACK (28*8 + 8) + +// PUSH_REGS_HOST_TO_ABI0 prepares for transitioning from +// the host ABI to Go ABI0 code. It saves all registers that are +// callee-save in the host ABI and caller-save in Go ABI0 and prepares +// for entry to Go. +// +// Save DI SI BP BX R12 R13 R14 R15 X6-X15 registers and the DF flag. +// Clear the DF flag for the Go ABI. +// MXCSR matches the Go ABI, so we don't have to set that, +// and Go doesn't modify it, so we don't have to save it. +#define PUSH_REGS_HOST_TO_ABI0() \ + PUSHFQ \ + CLD \ + ADJSP $(REGS_HOST_TO_ABI0_STACK - 8) \ + MOVQ DI, (0*0)(SP) \ + MOVQ SI, (1*8)(SP) \ + MOVQ BP, (2*8)(SP) \ + MOVQ BX, (3*8)(SP) \ + MOVQ R12, (4*8)(SP) \ + MOVQ R13, (5*8)(SP) \ + MOVQ R14, (6*8)(SP) \ + MOVQ R15, (7*8)(SP) \ + MOVUPS X6, (8*8)(SP) \ + MOVUPS X7, (10*8)(SP) \ + MOVUPS X8, (12*8)(SP) \ + MOVUPS X9, (14*8)(SP) \ + MOVUPS X10, (16*8)(SP) \ + MOVUPS X11, (18*8)(SP) \ + MOVUPS X12, (20*8)(SP) \ + MOVUPS X13, (22*8)(SP) \ + MOVUPS X14, (24*8)(SP) \ + MOVUPS X15, (26*8)(SP) + +#define POP_REGS_HOST_TO_ABI0() \ + MOVQ (0*0)(SP), DI \ + MOVQ (1*8)(SP), SI \ + MOVQ (2*8)(SP), BP \ + MOVQ (3*8)(SP), BX \ + MOVQ (4*8)(SP), R12 \ + MOVQ (5*8)(SP), R13 \ + MOVQ (6*8)(SP), R14 \ + MOVQ (7*8)(SP), R15 \ + MOVUPS (8*8)(SP), X6 \ + MOVUPS (10*8)(SP), X7 \ + MOVUPS (12*8)(SP), X8 \ + MOVUPS (14*8)(SP), X9 \ + MOVUPS (16*8)(SP), X10 \ + MOVUPS (18*8)(SP), X11 \ + MOVUPS (20*8)(SP), X12 \ + MOVUPS (22*8)(SP), X13 \ + MOVUPS (24*8)(SP), X14 \ + MOVUPS (26*8)(SP), X15 \ + ADJSP $-(REGS_HOST_TO_ABI0_STACK - 8) \ + POPFQ + +#endif diff --git a/src/runtime/cgo/asm_amd64.s b/src/runtime/cgo/asm_amd64.s index 5dc8e2d235c..447ddb118df 100644 --- a/src/runtime/cgo/asm_amd64.s +++ b/src/runtime/cgo/asm_amd64.s @@ -3,6 +3,7 @@ // license that can be found in the LICENSE file. #include "textflag.h" +#include "abi_amd64.h" // Called by C code generated by cmd/cgo. // func crosscall2(fn, a unsafe.Pointer, n int32, ctxt uintptr) @@ -11,57 +12,18 @@ // This signature is known to SWIG, so we can't change it. #ifndef GOOS_windows TEXT crosscall2(SB),NOSPLIT,$0x50-0 /* keeps stack pointer 32-byte aligned */ -#else -TEXT crosscall2(SB),NOSPLIT,$0x110-0 /* also need to save xmm6 - xmm15 */ -#endif MOVQ BX, 0x18(SP) MOVQ R12, 0x28(SP) MOVQ R13, 0x30(SP) MOVQ R14, 0x38(SP) MOVQ R15, 0x40(SP) -#ifdef GOOS_windows - // Win64 save RBX, RBP, RDI, RSI, RSP, R12, R13, R14, R15 and XMM6 -- XMM15. - MOVQ DI, 0x48(SP) - MOVQ SI, 0x50(SP) - MOVUPS X6, 0x60(SP) - MOVUPS X7, 0x70(SP) - MOVUPS X8, 0x80(SP) - MOVUPS X9, 0x90(SP) - MOVUPS X10, 0xa0(SP) - MOVUPS X11, 0xb0(SP) - MOVUPS X12, 0xc0(SP) - MOVUPS X13, 0xd0(SP) - MOVUPS X14, 0xe0(SP) - MOVUPS X15, 0xf0(SP) - - MOVQ CX, 0x0(SP) /* fn */ - MOVQ DX, 0x8(SP) /* arg */ - // Skip n in R8. - MOVQ R9, 0x10(SP) /* ctxt */ - - CALL runtime·cgocallback(SB) - - MOVQ 0x48(SP), DI - MOVQ 0x50(SP), SI - MOVUPS 0x60(SP), X6 - MOVUPS 0x70(SP), X7 - MOVUPS 0x80(SP), X8 - MOVUPS 0x90(SP), X9 - MOVUPS 0xa0(SP), X10 - MOVUPS 0xb0(SP), X11 - MOVUPS 0xc0(SP), X12 - MOVUPS 0xd0(SP), X13 - MOVUPS 0xe0(SP), X14 - MOVUPS 0xf0(SP), X15 -#else MOVQ DI, 0x0(SP) /* fn */ MOVQ SI, 0x8(SP) /* arg */ // Skip n in DX. MOVQ CX, 0x10(SP) /* ctxt */ CALL runtime·cgocallback(SB) -#endif MOVQ 0x18(SP), BX MOVQ 0x28(SP), R12 @@ -70,3 +32,21 @@ TEXT crosscall2(SB),NOSPLIT,$0x110-0 /* also need to save xmm6 - xmm15 */ MOVQ 0x40(SP), R15 RET + +#else +TEXT crosscall2(SB),NOSPLIT,$0-0 + PUSH_REGS_HOST_TO_ABI0() + + // Make room for arguments to cgocallback. + ADJSP $0x18 + MOVQ CX, 0x0(SP) /* fn */ + MOVQ DX, 0x8(SP) /* arg */ + // Skip n in R8. + MOVQ R9, 0x10(SP) /* ctxt */ + + CALL runtime·cgocallback(SB) + + ADJSP $-0x18 + POP_REGS_HOST_TO_ABI0() + RET +#endif diff --git a/src/runtime/sys_windows_amd64.s b/src/runtime/sys_windows_amd64.s index 68963313297..a9a7dfdd494 100644 --- a/src/runtime/sys_windows_amd64.s +++ b/src/runtime/sys_windows_amd64.s @@ -5,6 +5,7 @@ #include "go_asm.h" #include "go_tls.h" #include "textflag.h" +#include "cgo/abi_amd64.h" // maxargs should be divisible by 2, as Windows stack // must be kept 16-byte aligned on syscall entry. @@ -111,18 +112,10 @@ TEXT runtime·getlasterror(SB),NOSPLIT,$0 TEXT sigtramp<>(SB),NOSPLIT|NOFRAME,$0-0 // CX: PEXCEPTION_POINTERS ExceptionInfo - // DI SI BP BX R12 R13 R14 R15 registers and DF flag are preserved - // as required by windows callback convention. - PUSHFQ - SUBQ $112, SP - MOVQ DI, 80(SP) - MOVQ SI, 72(SP) - MOVQ BP, 64(SP) - MOVQ BX, 56(SP) - MOVQ R12, 48(SP) - MOVQ R13, 40(SP) - MOVQ R14, 32(SP) - MOVQ R15, 88(SP) + // Switch from the host ABI to the Go ABI. + PUSH_REGS_HOST_TO_ABI0() + // Make stack space for the rest of the function. + ADJSP $48 MOVQ AX, R15 // save handler address @@ -138,8 +131,8 @@ TEXT sigtramp<>(SB),NOSPLIT|NOFRAME,$0-0 CALL runtime·badsignal2(SB) // save g and SP in case of stack switch - MOVQ DX, 96(SP) // g - MOVQ SP, 104(SP) + MOVQ DX, 32(SP) // g + MOVQ SP, 40(SP) // do we need to switch to the g0 stack? MOVQ g_m(DX), BX @@ -153,9 +146,11 @@ TEXT sigtramp<>(SB),NOSPLIT|NOFRAME,$0-0 MOVQ (g_sched+gobuf_sp)(BX), DI // make room for sighandler arguments // and re-save old SP for restoring later. - // (note that the 104(DI) here must match the 104(SP) above.) - SUBQ $120, DI - MOVQ SP, 104(DI) + // Adjust g0 stack by the space we're using and + // save SP at the same place on the g0 stack. + // The 32(DI) here must match the 32(SP) above. + SUBQ $(REGS_HOST_TO_ABI0_STACK + 48), DI + MOVQ SP, 40(DI) MOVQ DI, SP g0: @@ -170,23 +165,14 @@ g0: // switch back to original stack and g // no-op if we never left. - MOVQ 104(SP), SP - MOVQ 96(SP), DX + MOVQ 40(SP), SP + MOVQ 32(SP), DX get_tls(BP) MOVQ DX, g(BP) done: - // restore registers as required for windows callback - MOVQ 88(SP), R15 - MOVQ 32(SP), R14 - MOVQ 40(SP), R13 - MOVQ 48(SP), R12 - MOVQ 56(SP), BX - MOVQ 64(SP), BP - MOVQ 72(SP), SI - MOVQ 80(SP), DI - ADDQ $112, SP - POPFQ + ADJSP $-48 + POP_REGS_HOST_TO_ABI0() RET @@ -230,21 +216,8 @@ TEXT runtime·callbackasm1(SB),NOSPLIT,$0 DIVL CX SUBQ $1, AX // subtract 1 because return PC is to the next slot - // DI SI BP BX R12 R13 R14 R15 registers and DF flag are preserved - // as required by windows callback convention. - PUSHFQ - SUBQ $64, SP - MOVQ DI, 56(SP) - MOVQ SI, 48(SP) - MOVQ BP, 40(SP) - MOVQ BX, 32(SP) - MOVQ R12, 24(SP) - MOVQ R13, 16(SP) - MOVQ R14, 8(SP) - MOVQ R15, 0(SP) - - // Go ABI requires DF flag to be cleared. - CLD + // Switch from the host ABI to the Go ABI. + PUSH_REGS_HOST_TO_ABI0() // Create a struct callbackArgs on our stack to be passed as // the "frame" to cgocallback and on to callbackWrap. @@ -263,23 +236,16 @@ TEXT runtime·callbackasm1(SB),NOSPLIT,$0 MOVQ (24+callbackArgs_result)(SP), AX ADDQ $(24+callbackArgs__size), SP - // restore registers as required for windows callback - MOVQ 0(SP), R15 - MOVQ 8(SP), R14 - MOVQ 16(SP), R13 - MOVQ 24(SP), R12 - MOVQ 32(SP), BX - MOVQ 40(SP), BP - MOVQ 48(SP), SI - MOVQ 56(SP), DI - ADDQ $64, SP - POPFQ + POP_REGS_HOST_TO_ABI0() // The return value was placed in AX above. RET // uint32 tstart_stdcall(M *newm); TEXT runtime·tstart_stdcall(SB),NOSPLIT,$0 + // Switch from the host ABI to the Go ABI. + PUSH_REGS_HOST_TO_ABI0() + // CX contains first arg newm MOVQ m_g0(CX), DX // g @@ -298,12 +264,11 @@ TEXT runtime·tstart_stdcall(SB),NOSPLIT,$0 MOVQ CX, g_m(DX) MOVQ DX, g(SI) - // Someday the convention will be D is always cleared. - CLD - CALL runtime·stackcheck(SB) // clobbers AX,CX CALL runtime·mstart(SB) + POP_REGS_HOST_TO_ABI0() + XORL AX, AX // return 0 == success RET