runtime: return the error code as a return value in asmstdcall

This shaves off 8 bytes from the syscall_syscalln stack frame, which is
significant as that call path is almost over the nosplit limit.

Also, it follows the cgocall convention of returning the error code as
a return value, making it easier to reason about.

Cq-Include-Trybots: luci.golang.try:gotip-windows-amd64-longtest,gotip-windows-arm64,gotip-windows-386
Change-Id: I62acdb7c0d4cf9cb928bf3974d3300dd752f6c29
Reviewed-on: https://go-review.googlesource.com/c/go/+/751861
Reviewed-by: Cherry Mui <cherryyz@google.com>
Reviewed-by: Carlos Amedee <carlos@golang.org>
Reviewed-by: Alex Brainman <alex.brainman@gmail.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
This commit is contained in:
qmuntal
2026-03-06 12:22:14 +01:00
committed by Quim Muntal
parent bf1c1b3bde
commit 4216fa3d04
5 changed files with 16 additions and 10 deletions

View File

@@ -5,10 +5,14 @@
#include "go_asm.h"
#include "textflag.h"
TEXT ·StdCall<ABIInternal>(SB),NOSPLIT,$0
JMP ·asmstdcall(SB)
TEXT ·StdCall<ABIInternal>(SB),NOSPLIT,$4-8
MOVL fn+0(FP), AX
MOVL AX, 0(SP)
CALL ·asmstdcall(SB)
MOVL AX, ret+4(FP)
RET
TEXT ·asmstdcall(SB),NOSPLIT,$0
TEXT ·asmstdcall(SB),NOSPLIT,$0-4
MOVL fn+0(FP), BX
MOVL SP, BP // save stack pointer
@@ -43,6 +47,5 @@ docall:
// GetLastError().
MOVL 0x34(FS), AX
MOVL AX, StdCallInfo_Err(BX)
RET

View File

@@ -79,6 +79,5 @@ _0args:
// GetLastError().
MOVQ 0x30(GS), DI
MOVL 0x68(DI), AX
MOVQ AX, StdCallInfo_Err(CX)
RET

View File

@@ -83,7 +83,6 @@ _0args:
// GetLastError
MOVD TEB_error(R18_PLATFORM), R0
MOVD R0, StdCallInfo_Err(R19)
// Restore callee-saved registers.
LDP 16(RSP), (R19, R20)

View File

@@ -24,15 +24,20 @@ type StdCallInfo struct {
Args uintptr // parameters
R1 uintptr // return values
R2 uintptr
Err uintptr // error number
}
// StdCall calls a function using Windows' stdcall convention.
// The calling thread's last-error code value is cleared before calling the function,
// and stored in the return value.
//
//go:noescape
func StdCall(fn *StdCallInfo)
func StdCall(fn *StdCallInfo) uint32
// asmstdcall is the function pointer for [AsmStdCallAddr].
// The calling thread's last-error code value is cleared before calling the function,
// and returned in the C ABI return register (not via Go stack convention).
// This function is not called directly from Go; it is either jumped to from
// [StdCall] or called from C via [AsmStdCallAddr].
func asmstdcall(fn *StdCallInfo)
// AsmStdCallAddr is the address of a function that accepts a pointer

View File

@@ -428,10 +428,10 @@ func syscall_syscalln(fn, n uintptr, args ...uintptr) (r1, r2, err uintptr) {
if c.N != 0 {
c.Args = uintptr(noescape(unsafe.Pointer(&args[0])))
}
cgocall(asmstdcallAddr, unsafe.Pointer(c))
errno := cgocall(asmstdcallAddr, unsafe.Pointer(c))
// cgocall may reschedule us on to a different M,
// but it copies the return values into the new M's
// so we can read them from there.
c = &getg().m.winsyscall
return c.R1, c.R2, c.Err
return c.R1, c.R2, uintptr(errno)
}