aboutsummaryrefslogtreecommitdiff
path: root/src/internal/runtime/syscall
diff options
context:
space:
mode:
authorqmuntal <quimmuntal@gmail.com>2025-07-21 14:39:04 +0200
committerQuim Muntal <quimmuntal@gmail.com>2025-07-28 09:47:09 -0700
commitc7ed3a1c5a152d0e610bbbf104dba30099e6942a (patch)
treee89ef2d6b5a0bcc10f4174f8e67b88e559febc8e /src/internal/runtime/syscall
parente81eac19d30f373496cd1d08ce2f89c0469a21fd (diff)
downloadgo-c7ed3a1c5a152d0e610bbbf104dba30099e6942a.tar.xz
internal/runtime/syscall/windows: factor out code from runtime
Factor out the code related to doing calls using the Windows stdcall calling convention into a separate package. This will allow us to reuse it in other low-level packages that can't depend on syscall. Updates #51087. Cq-Include-Trybots: luci.golang.try:gotip-windows-arm64,gotip-windows-amd64-longtest,gotip-solaris-amd64 Change-Id: I68640b07091183b50da6bef17406c10a397896e9 Reviewed-on: https://go-review.googlesource.com/c/go/+/689156 Reviewed-by: Michael Pratt <mpratt@google.com> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: Michael Knyszek <mknyszek@google.com>
Diffstat (limited to 'src/internal/runtime/syscall')
-rw-r--r--src/internal/runtime/syscall/windows/asm_windows_386.s48
-rw-r--r--src/internal/runtime/syscall/windows/asm_windows_amd64.s84
-rw-r--r--src/internal/runtime/syscall/windows/asm_windows_arm.s77
-rw-r--r--src/internal/runtime/syscall/windows/asm_windows_arm64.s90
-rw-r--r--src/internal/runtime/syscall/windows/syscall_windows.go44
5 files changed, 343 insertions, 0 deletions
diff --git a/src/internal/runtime/syscall/windows/asm_windows_386.s b/src/internal/runtime/syscall/windows/asm_windows_386.s
new file mode 100644
index 0000000000..29cce00309
--- /dev/null
+++ b/src/internal/runtime/syscall/windows/asm_windows_386.s
@@ -0,0 +1,48 @@
+// Copyright 2025 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.
+
+#include "go_asm.h"
+#include "textflag.h"
+
+TEXT ·StdCall<ABIInternal>(SB),NOSPLIT,$0
+ JMP ·asmstdcall(SB)
+
+TEXT ·asmstdcall(SB),NOSPLIT,$0
+ MOVL fn+0(FP), BX
+ MOVL SP, BP // save stack pointer
+
+ // SetLastError(0).
+ MOVL $0, 0x34(FS)
+
+ MOVL StdCallInfo_N(BX), CX
+
+ // Fast version, do not store args on the stack.
+ CMPL CX, $0
+ JE docall
+
+ // Copy args to the stack.
+ MOVL CX, AX
+ SALL $2, AX
+ SUBL AX, SP // room for args
+ MOVL SP, DI
+ MOVL StdCallInfo_Args(BX), SI
+ CLD
+ REP; MOVSL
+
+docall:
+ // Call stdcall or cdecl function.
+ // DI SI BP BX are preserved, SP is not
+ CALL StdCallInfo_Fn(BX)
+ MOVL BP, SP
+
+ // Return result.
+ MOVL fn+0(FP), BX
+ MOVL AX, StdCallInfo_R1(BX)
+ MOVL DX, StdCallInfo_R2(BX)
+
+ // GetLastError().
+ MOVL 0x34(FS), AX
+ MOVL AX, StdCallInfo_Err(BX)
+
+ RET
diff --git a/src/internal/runtime/syscall/windows/asm_windows_amd64.s b/src/internal/runtime/syscall/windows/asm_windows_amd64.s
new file mode 100644
index 0000000000..c31cbcdd14
--- /dev/null
+++ b/src/internal/runtime/syscall/windows/asm_windows_amd64.s
@@ -0,0 +1,84 @@
+// Copyright 2025 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.
+
+#include "go_asm.h"
+#include "textflag.h"
+
+TEXT ·StdCall<ABIInternal>(SB),NOSPLIT,$0
+ MOVQ AX, CX
+ JMP ·asmstdcall(SB)
+
+TEXT ·asmstdcall(SB),NOSPLIT,$16
+ MOVQ SP, AX
+ ANDQ $~15, SP // alignment as per Windows requirement
+ MOVQ AX, 8(SP)
+ MOVQ CX, 0(SP) // asmcgocall will put first argument into CX.
+
+ MOVQ StdCallInfo_Fn(CX), AX
+ MOVQ StdCallInfo_Args(CX), SI
+ MOVQ StdCallInfo_N(CX), CX
+
+ // SetLastError(0).
+ MOVQ 0x30(GS), DI
+ MOVL $0, 0x68(DI)
+
+ SUBQ $(const_MaxArgs*8), SP // room for args
+
+ // Fast version, do not store args on the stack.
+ CMPL CX, $0; JE _0args
+ CMPL CX, $1; JE _1args
+ CMPL CX, $2; JE _2args
+ CMPL CX, $3; JE _3args
+ CMPL CX, $4; JE _4args
+
+ // Check we have enough room for args.
+ CMPL CX, $const_MaxArgs
+ JLE 2(PC)
+ INT $3 // not enough room -> crash
+
+ // Copy args to the stack.
+ MOVQ SP, DI
+ CLD
+ REP; MOVSQ
+ MOVQ SP, SI
+
+ // Load first 4 args into correspondent registers.
+ // Floating point arguments are passed in the XMM
+ // registers. Set them here in case any of the arguments
+ // are floating point values. For details see
+ // https://learn.microsoft.com/en-us/cpp/build/x64-calling-convention?view=msvc-170
+_4args:
+ MOVQ 24(SI), R9
+ MOVQ R9, X3
+_3args:
+ MOVQ 16(SI), R8
+ MOVQ R8, X2
+_2args:
+ MOVQ 8(SI), DX
+ MOVQ DX, X1
+_1args:
+ MOVQ 0(SI), CX
+ MOVQ CX, X0
+_0args:
+
+ // Call stdcall function.
+ CALL AX
+
+ ADDQ $(const_MaxArgs*8), SP
+
+ // Return result.
+ MOVQ 0(SP), CX
+ MOVQ 8(SP), SP
+ MOVQ AX, StdCallInfo_R1(CX)
+ // Floating point return values are returned in XMM0. Setting r2 to this
+ // value in case this call returned a floating point value. For details,
+ // see https://docs.microsoft.com/en-us/cpp/build/x64-calling-convention
+ MOVQ X0, StdCallInfo_R2(CX)
+
+ // GetLastError().
+ MOVQ 0x30(GS), DI
+ MOVL 0x68(DI), AX
+ MOVQ AX, StdCallInfo_Err(CX)
+
+ RET
diff --git a/src/internal/runtime/syscall/windows/asm_windows_arm.s b/src/internal/runtime/syscall/windows/asm_windows_arm.s
new file mode 100644
index 0000000000..8cc4d5c9aa
--- /dev/null
+++ b/src/internal/runtime/syscall/windows/asm_windows_arm.s
@@ -0,0 +1,77 @@
+// Copyright 2025 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.
+
+#include "go_asm.h"
+#include "go_tls.h"
+#include "textflag.h"
+#include "time_windows.h"
+
+TEXT ·StdCall<ABIInternal>(SB),NOSPLIT,$0
+ B ·asmstdcall(SB)
+
+TEXT ·asmstdcall(SB),NOSPLIT|NOFRAME,$0
+ MOVM.DB.W [R4, R5, R14], (R13) // push {r4, r5, lr}
+ MOVW R0, R4 // put fn * in r4
+ MOVW R13, R5 // save stack pointer in r5
+
+ // SetLastError(0)
+ MOVW $0, R0
+ MRC 15, 0, R1, C13, C0, 2
+ MOVW R0, 0x34(R1)
+
+ MOVW 8(R4), R12 // fn->Args
+
+ // Do we have more than 4 arguments?
+ MOVW 4(R4), R0 // fn->n
+ SUB.S $4, R0, R2
+ BLE loadregs
+
+ // Reserve stack space for remaining args
+ SUB R2<<2, R13
+ BIC $0x7, R13 // alignment for ABI
+
+ // R0: count of arguments
+ // R1:
+ // R2: loop counter, from 0 to (n-4)
+ // R3: scratch
+ // R4: pointer to StdCallInfo struct
+ // R12: fn->args
+ MOVW $0, R2
+stackargs:
+ ADD $4, R2, R3 // r3 = args[4 + i]
+ MOVW R3<<2(R12), R3
+ MOVW R3, R2<<2(R13) // stack[i] = r3
+
+ ADD $1, R2 // i++
+ SUB $4, R0, R3 // while (i < (n - 4))
+ CMP R3, R2
+ BLT stackargs
+
+loadregs:
+ CMP $3, R0
+ MOVW.GT 12(R12), R3
+
+ CMP $2, R0
+ MOVW.GT 8(R12), R2
+
+ CMP $1, R0
+ MOVW.GT 4(R12), R1
+
+ CMP $0, R0
+ MOVW.GT 0(R12), R0
+
+ BIC $0x7, R13 // alignment for ABI
+ MOVW 0(R4), R12 // branch to fn->fn
+ BL (R12)
+
+ MOVW R5, R13 // free stack space
+ MOVW R0, 12(R4) // save return value to fn->r1
+ MOVW R1, 16(R4)
+
+ // GetLastError
+ MRC 15, 0, R1, C13, C0, 2
+ MOVW 0x34(R1), R0
+ MOVW R0, 20(R4) // store in fn->err
+
+ MOVM.IA.W (R13), [R4, R5, R15]
diff --git a/src/internal/runtime/syscall/windows/asm_windows_arm64.s b/src/internal/runtime/syscall/windows/asm_windows_arm64.s
new file mode 100644
index 0000000000..fb4cda0f83
--- /dev/null
+++ b/src/internal/runtime/syscall/windows/asm_windows_arm64.s
@@ -0,0 +1,90 @@
+// Copyright 2025 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.
+
+#include "go_asm.h"
+#include "textflag.h"
+
+// Offsets into Thread Environment Block (pointer in R18)
+#define TEB_error 0x68
+
+TEXT ·StdCall<ABIInternal>(SB),NOSPLIT,$0
+ B ·asmstdcall(SB)
+
+TEXT ·asmstdcall(SB),NOSPLIT,$16
+ STP (R19, R20), 16(RSP) // save old R19, R20
+ MOVD R0, R19 // save fn pointer
+ MOVD RSP, R20 // save stack pointer
+
+ // SetLastError(0)
+ MOVD $0, TEB_error(R18_PLATFORM)
+ MOVD StdCallInfo_Args(R19), R12
+
+ // Do we have more than 8 arguments?
+ MOVD StdCallInfo_N(R19), R0
+ CMP $0, R0; BEQ _0args
+ CMP $1, R0; BEQ _1args
+ CMP $2, R0; BEQ _2args
+ CMP $3, R0; BEQ _3args
+ CMP $4, R0; BEQ _4args
+ CMP $5, R0; BEQ _5args
+ CMP $6, R0; BEQ _6args
+ CMP $7, R0; BEQ _7args
+ CMP $8, R0; BEQ _8args
+
+ // Reserve stack space for remaining args
+ SUB $8, R0, R2
+ ADD $1, R2, R3 // make even number of words for stack alignment
+ AND $~1, R3
+ LSL $3, R3
+ SUB R3, RSP
+
+ // R4: size of stack arguments (n-8)*8
+ // R5: &args[8]
+ // R6: loop counter, from 0 to (n-8)*8
+ // R7: scratch
+ // R8: copy of RSP - (R2)(RSP) assembles as (R2)(ZR)
+ SUB $8, R0, R4
+ LSL $3, R4
+ ADD $(8*8), R12, R5
+ MOVD $0, R6
+ MOVD RSP, R8
+stackargs:
+ MOVD (R6)(R5), R7
+ MOVD R7, (R6)(R8)
+ ADD $8, R6
+ CMP R6, R4
+ BNE stackargs
+
+_8args:
+ MOVD (7*8)(R12), R7
+_7args:
+ MOVD (6*8)(R12), R6
+_6args:
+ MOVD (5*8)(R12), R5
+_5args:
+ MOVD (4*8)(R12), R4
+_4args:
+ MOVD (3*8)(R12), R3
+_3args:
+ MOVD (2*8)(R12), R2
+_2args:
+ MOVD (1*8)(R12), R1
+_1args:
+ MOVD (0*8)(R12), R0
+_0args:
+
+ MOVD StdCallInfo_Fn(R19), R12
+ BL (R12)
+
+ MOVD R20, RSP // free stack space
+ MOVD R0, StdCallInfo_R1(R19) // save return value
+ // TODO(rsc) floating point like amd64 in StdCallInfo_R2?
+
+ // GetLastError
+ MOVD TEB_error(R18_PLATFORM), R0
+ MOVD R0, StdCallInfo_Err(R19)
+
+ // Restore callee-saved registers.
+ LDP 16(RSP), (R19, R20)
+ RET
diff --git a/src/internal/runtime/syscall/windows/syscall_windows.go b/src/internal/runtime/syscall/windows/syscall_windows.go
new file mode 100644
index 0000000000..0d350f0d7f
--- /dev/null
+++ b/src/internal/runtime/syscall/windows/syscall_windows.go
@@ -0,0 +1,44 @@
+// Copyright 2025 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 windows provides the syscall primitives required for the runtime.
+
+package windows
+
+import (
+ "internal/abi"
+)
+
+// MaxArgs should be divisible by 2, as Windows stack
+// must be kept 16-byte aligned on syscall entry.
+//
+// Although it only permits maximum 42 parameters, it
+// is arguably large enough.
+const MaxArgs = 42
+
+// StdCallInfo is a structure used to pass parameters to the system call.
+type StdCallInfo struct {
+ Fn uintptr
+ N uintptr // number of parameters
+ Args uintptr // parameters
+ R1 uintptr // return values
+ R2 uintptr
+ Err uintptr // error number
+}
+
+// StdCall calls a function using Windows' stdcall convention.
+//
+//go:noescape
+func StdCall(fn *StdCallInfo)
+
+// asmstdcall is the function pointer for [AsmStdCallAddr].
+func asmstdcall(fn *StdCallInfo)
+
+// AsmStdCallAddr is the address of a function that accepts a pointer
+// to [StdCallInfo] stored on the stack following the C calling convention,
+// and calls the function using Windows' stdcall calling convention.
+// Shouldn't be called directly from Go.
+func AsmStdCallAddr() uintptr {
+ return abi.FuncPCABI0(asmstdcall)
+}