mirror of
https://github.com/golang/go.git
synced 2025-10-19 19:13:18 +00:00
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>
This commit is contained in:
parent
e81eac19d3
commit
c7ed3a1c5a
22 changed files with 407 additions and 346 deletions
|
@ -57,6 +57,7 @@ var runtimePkgs = []string{
|
|||
"internal/runtime/strconv",
|
||||
"internal/runtime/sys",
|
||||
"internal/runtime/syscall/linux",
|
||||
"internal/runtime/syscall/windows",
|
||||
|
||||
"internal/abi",
|
||||
"internal/bytealg",
|
||||
|
@ -95,6 +96,7 @@ var allowAsmABIPkgs = []string{
|
|||
"internal/bytealg",
|
||||
"internal/chacha8rand",
|
||||
"internal/runtime/syscall/linux",
|
||||
"internal/runtime/syscall/windows",
|
||||
"internal/runtime/startlinetest",
|
||||
}
|
||||
|
||||
|
|
|
@ -92,6 +92,7 @@ var depsRules = `
|
|||
< internal/asan
|
||||
< internal/runtime/sys
|
||||
< internal/runtime/syscall/linux
|
||||
< internal/runtime/syscall/windows
|
||||
< internal/runtime/atomic
|
||||
< internal/runtime/exithook
|
||||
< internal/runtime/gc
|
||||
|
|
|
@ -67,6 +67,7 @@ var rtPkgs = [...]string{
|
|||
"internal/runtime/sys",
|
||||
"internal/runtime/maps",
|
||||
"internal/runtime/syscall/linux",
|
||||
"internal/runtime/syscall/windows",
|
||||
"internal/runtime/cgroup",
|
||||
"internal/stringslite",
|
||||
"runtime",
|
||||
|
|
48
src/internal/runtime/syscall/windows/asm_windows_386.s
Normal file
48
src/internal/runtime/syscall/windows/asm_windows_386.s
Normal file
|
@ -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
|
84
src/internal/runtime/syscall/windows/asm_windows_amd64.s
Normal file
84
src/internal/runtime/syscall/windows/asm_windows_amd64.s
Normal file
|
@ -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
|
77
src/internal/runtime/syscall/windows/asm_windows_arm.s
Normal file
77
src/internal/runtime/syscall/windows/asm_windows_arm.s
Normal file
|
@ -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]
|
90
src/internal/runtime/syscall/windows/asm_windows_arm64.s
Normal file
90
src/internal/runtime/syscall/windows/asm_windows_arm64.s
Normal file
|
@ -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
|
44
src/internal/runtime/syscall/windows/syscall_windows.go
Normal file
44
src/internal/runtime/syscall/windows/syscall_windows.go
Normal file
|
@ -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)
|
||||
}
|
|
@ -191,8 +191,8 @@ func cgocall(fn, arg unsafe.Pointer) int32 {
|
|||
|
||||
osPreemptExtExit(mp)
|
||||
|
||||
// Save current syscall parameters, so m.winsyscall can be
|
||||
// used again if callback decide to make syscall.
|
||||
// After exitsyscall we can be rescheduled on a different M,
|
||||
// so we need to restore the original M's winsyscall.
|
||||
winsyscall := mp.winsyscall
|
||||
|
||||
exitsyscall()
|
||||
|
|
|
@ -11,8 +11,6 @@ import (
|
|||
"unsafe"
|
||||
)
|
||||
|
||||
const MaxArgs = maxArgs
|
||||
|
||||
var (
|
||||
OsYield = osyield
|
||||
TimeBeginPeriodRetValue = &timeBeginPeriodRetValue
|
||||
|
|
|
@ -27,6 +27,7 @@ type funcDescriptor struct {
|
|||
type mOS struct {
|
||||
waitsema uintptr // semaphore for parking on locks
|
||||
perrno uintptr // pointer to tls errno
|
||||
libcall libcall
|
||||
}
|
||||
|
||||
//go:nosplit
|
||||
|
|
|
@ -21,9 +21,8 @@ type mscratch struct {
|
|||
type mOS struct {
|
||||
waitsema uintptr // semaphore for parking on locks
|
||||
perrno *int32 // pointer to tls errno
|
||||
// these are here because they are too large to be on the stack
|
||||
// of low-level NOSPLIT functions.
|
||||
//LibCall libcall;
|
||||
// This is here to avoid using the G stack so the stack can move during the call.
|
||||
libcall libcall
|
||||
ts mts
|
||||
scratch mscratch
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@ import (
|
|||
"internal/abi"
|
||||
"internal/runtime/atomic"
|
||||
"internal/runtime/sys"
|
||||
"internal/runtime/syscall/windows"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
|
@ -160,6 +161,9 @@ func tstart_stdcall(newm *m)
|
|||
func wintls()
|
||||
|
||||
type mOS struct {
|
||||
// This is here to avoid using the G stack so the stack can move during the call.
|
||||
stdCallInfo windows.StdCallInfo
|
||||
|
||||
threadLock mutex // protects "thread" and prevents closing
|
||||
thread uintptr // thread handle
|
||||
|
||||
|
@ -210,13 +214,9 @@ func read(fd int32, p unsafe.Pointer, n int32) int32 {
|
|||
|
||||
type sigset struct{}
|
||||
|
||||
// Call a Windows function with stdcall conventions,
|
||||
// and switch to os stack during the call.
|
||||
func asmstdcall(fn unsafe.Pointer)
|
||||
|
||||
var asmstdcallAddr unsafe.Pointer
|
||||
|
||||
type winlibcall libcall
|
||||
type winlibcall windows.StdCallInfo
|
||||
|
||||
func windowsFindfunc(lib uintptr, name []byte) stdFunction {
|
||||
if name[len(name)-1] != 0 {
|
||||
|
@ -472,7 +472,7 @@ func initLongPathSupport() {
|
|||
}
|
||||
|
||||
func osinit() {
|
||||
asmstdcallAddr = unsafe.Pointer(abi.FuncPCABI0(asmstdcall))
|
||||
asmstdcallAddr = unsafe.Pointer(windows.AsmStdCallAddr())
|
||||
|
||||
loadOptionalSyscalls()
|
||||
|
||||
|
@ -935,20 +935,17 @@ func mdestroy(mp *m) {
|
|||
}
|
||||
}
|
||||
|
||||
// asmstdcall_trampoline calls asmstdcall converting from Go to C calling convention.
|
||||
func asmstdcall_trampoline(args unsafe.Pointer)
|
||||
|
||||
// stdcall_no_g calls asmstdcall on os stack without using g.
|
||||
//
|
||||
//go:nosplit
|
||||
func stdcall_no_g(fn stdFunction, n int, args uintptr) uintptr {
|
||||
libcall := libcall{
|
||||
fn: uintptr(unsafe.Pointer(fn)),
|
||||
n: uintptr(n),
|
||||
args: args,
|
||||
call := windows.StdCallInfo{
|
||||
Fn: uintptr(unsafe.Pointer(fn)),
|
||||
N: uintptr(n),
|
||||
Args: args,
|
||||
}
|
||||
asmstdcall_trampoline(noescape(unsafe.Pointer(&libcall)))
|
||||
return libcall.r1
|
||||
windows.StdCall(&call)
|
||||
return call.R1
|
||||
}
|
||||
|
||||
// Calling stdcall on os stack.
|
||||
|
@ -959,7 +956,7 @@ func stdcall_no_g(fn stdFunction, n int, args uintptr) uintptr {
|
|||
func stdcall(fn stdFunction) uintptr {
|
||||
gp := getg()
|
||||
mp := gp.m
|
||||
mp.libcall.fn = uintptr(unsafe.Pointer(fn))
|
||||
mp.stdCallInfo.Fn = uintptr(unsafe.Pointer(fn))
|
||||
resetLibcall := false
|
||||
if mp.profilehz != 0 && mp.libcallsp == 0 {
|
||||
// leave pc/sp for cpu profiler
|
||||
|
@ -970,18 +967,18 @@ func stdcall(fn stdFunction) uintptr {
|
|||
mp.libcallsp = sys.GetCallerSP()
|
||||
resetLibcall = true // See comment in sys_darwin.go:libcCall
|
||||
}
|
||||
asmcgocall(asmstdcallAddr, unsafe.Pointer(&mp.libcall))
|
||||
asmcgocall(asmstdcallAddr, unsafe.Pointer(&mp.stdCallInfo))
|
||||
if resetLibcall {
|
||||
mp.libcallsp = 0
|
||||
}
|
||||
return mp.libcall.r1
|
||||
return mp.stdCallInfo.R1
|
||||
}
|
||||
|
||||
//go:nosplit
|
||||
func stdcall0(fn stdFunction) uintptr {
|
||||
mp := getg().m
|
||||
mp.libcall.n = 0
|
||||
mp.libcall.args = 0
|
||||
mp.stdCallInfo.N = 0
|
||||
mp.stdCallInfo.Args = 0
|
||||
return stdcall(fn)
|
||||
}
|
||||
|
||||
|
@ -989,8 +986,8 @@ func stdcall0(fn stdFunction) uintptr {
|
|||
//go:cgo_unsafe_args
|
||||
func stdcall1(fn stdFunction, a0 uintptr) uintptr {
|
||||
mp := getg().m
|
||||
mp.libcall.n = 1
|
||||
mp.libcall.args = uintptr(noescape(unsafe.Pointer(&a0)))
|
||||
mp.stdCallInfo.N = 1
|
||||
mp.stdCallInfo.Args = uintptr(noescape(unsafe.Pointer(&a0)))
|
||||
return stdcall(fn)
|
||||
}
|
||||
|
||||
|
@ -998,8 +995,8 @@ func stdcall1(fn stdFunction, a0 uintptr) uintptr {
|
|||
//go:cgo_unsafe_args
|
||||
func stdcall2(fn stdFunction, a0, a1 uintptr) uintptr {
|
||||
mp := getg().m
|
||||
mp.libcall.n = 2
|
||||
mp.libcall.args = uintptr(noescape(unsafe.Pointer(&a0)))
|
||||
mp.stdCallInfo.N = 2
|
||||
mp.stdCallInfo.Args = uintptr(noescape(unsafe.Pointer(&a0)))
|
||||
return stdcall(fn)
|
||||
}
|
||||
|
||||
|
@ -1007,8 +1004,8 @@ func stdcall2(fn stdFunction, a0, a1 uintptr) uintptr {
|
|||
//go:cgo_unsafe_args
|
||||
func stdcall3(fn stdFunction, a0, a1, a2 uintptr) uintptr {
|
||||
mp := getg().m
|
||||
mp.libcall.n = 3
|
||||
mp.libcall.args = uintptr(noescape(unsafe.Pointer(&a0)))
|
||||
mp.stdCallInfo.N = 3
|
||||
mp.stdCallInfo.Args = uintptr(noescape(unsafe.Pointer(&a0)))
|
||||
return stdcall(fn)
|
||||
}
|
||||
|
||||
|
@ -1016,8 +1013,8 @@ func stdcall3(fn stdFunction, a0, a1, a2 uintptr) uintptr {
|
|||
//go:cgo_unsafe_args
|
||||
func stdcall4(fn stdFunction, a0, a1, a2, a3 uintptr) uintptr {
|
||||
mp := getg().m
|
||||
mp.libcall.n = 4
|
||||
mp.libcall.args = uintptr(noescape(unsafe.Pointer(&a0)))
|
||||
mp.stdCallInfo.N = 4
|
||||
mp.stdCallInfo.Args = uintptr(noescape(unsafe.Pointer(&a0)))
|
||||
return stdcall(fn)
|
||||
}
|
||||
|
||||
|
@ -1025,8 +1022,8 @@ func stdcall4(fn stdFunction, a0, a1, a2, a3 uintptr) uintptr {
|
|||
//go:cgo_unsafe_args
|
||||
func stdcall5(fn stdFunction, a0, a1, a2, a3, a4 uintptr) uintptr {
|
||||
mp := getg().m
|
||||
mp.libcall.n = 5
|
||||
mp.libcall.args = uintptr(noescape(unsafe.Pointer(&a0)))
|
||||
mp.stdCallInfo.N = 5
|
||||
mp.stdCallInfo.Args = uintptr(noescape(unsafe.Pointer(&a0)))
|
||||
return stdcall(fn)
|
||||
}
|
||||
|
||||
|
@ -1034,8 +1031,8 @@ func stdcall5(fn stdFunction, a0, a1, a2, a3, a4 uintptr) uintptr {
|
|||
//go:cgo_unsafe_args
|
||||
func stdcall6(fn stdFunction, a0, a1, a2, a3, a4, a5 uintptr) uintptr {
|
||||
mp := getg().m
|
||||
mp.libcall.n = 6
|
||||
mp.libcall.args = uintptr(noescape(unsafe.Pointer(&a0)))
|
||||
mp.stdCallInfo.N = 6
|
||||
mp.stdCallInfo.Args = uintptr(noescape(unsafe.Pointer(&a0)))
|
||||
return stdcall(fn)
|
||||
}
|
||||
|
||||
|
@ -1043,8 +1040,8 @@ func stdcall6(fn stdFunction, a0, a1, a2, a3, a4, a5 uintptr) uintptr {
|
|||
//go:cgo_unsafe_args
|
||||
func stdcall7(fn stdFunction, a0, a1, a2, a3, a4, a5, a6 uintptr) uintptr {
|
||||
mp := getg().m
|
||||
mp.libcall.n = 7
|
||||
mp.libcall.args = uintptr(noescape(unsafe.Pointer(&a0)))
|
||||
mp.stdCallInfo.N = 7
|
||||
mp.stdCallInfo.Args = uintptr(noescape(unsafe.Pointer(&a0)))
|
||||
return stdcall(fn)
|
||||
}
|
||||
|
||||
|
@ -1052,8 +1049,8 @@ func stdcall7(fn stdFunction, a0, a1, a2, a3, a4, a5, a6 uintptr) uintptr {
|
|||
//go:cgo_unsafe_args
|
||||
func stdcall8(fn stdFunction, a0, a1, a2, a3, a4, a5, a6, a7 uintptr) uintptr {
|
||||
mp := getg().m
|
||||
mp.libcall.n = 8
|
||||
mp.libcall.args = uintptr(noescape(unsafe.Pointer(&a0)))
|
||||
mp.stdCallInfo.N = 8
|
||||
mp.stdCallInfo.Args = uintptr(noescape(unsafe.Pointer(&a0)))
|
||||
return stdcall(fn)
|
||||
}
|
||||
|
||||
|
|
|
@ -593,9 +593,7 @@ type m struct {
|
|||
freelink *m // on sched.freem
|
||||
trace mTraceState
|
||||
|
||||
// these are here because they are too large to be on the stack
|
||||
// of low-level NOSPLIT functions.
|
||||
libcall libcall
|
||||
// These are here to avoid using the G stack so the stack can move during the call.
|
||||
libcallpc uintptr // for cpu profiler
|
||||
libcallsp uintptr
|
||||
libcallg guintptr
|
||||
|
|
|
@ -130,15 +130,15 @@ TEXT sigtramp<>(SB),NOSPLIT|NOFRAME|TOPFRAME,$0
|
|||
|
||||
// Save m->libcall. We need to do this because we
|
||||
// might get interrupted by a signal in runtime·asmcgocall.
|
||||
MOVD (m_libcall+libcall_fn)(R6), R7
|
||||
MOVD (m_mOS+mOS_libcall+libcall_fn)(R6), R7
|
||||
MOVD R7, 96(R1)
|
||||
MOVD (m_libcall+libcall_args)(R6), R7
|
||||
MOVD (m_mOS+mOS_libcall+libcall_args)(R6), R7
|
||||
MOVD R7, 104(R1)
|
||||
MOVD (m_libcall+libcall_n)(R6), R7
|
||||
MOVD (m_mOS+mOS_libcall+libcall_n)(R6), R7
|
||||
MOVD R7, 112(R1)
|
||||
MOVD (m_libcall+libcall_r1)(R6), R7
|
||||
MOVD (m_mOS+mOS_libcall+libcall_r1)(R6), R7
|
||||
MOVD R7, 120(R1)
|
||||
MOVD (m_libcall+libcall_r2)(R6), R7
|
||||
MOVD (m_mOS+mOS_libcall+libcall_r2)(R6), R7
|
||||
MOVD R7, 128(R1)
|
||||
|
||||
// save errno, it might be EINTR; stuff we do here might reset it.
|
||||
|
@ -162,15 +162,15 @@ sigtramp:
|
|||
|
||||
// restore libcall
|
||||
MOVD 96(R1), R7
|
||||
MOVD R7, (m_libcall+libcall_fn)(R6)
|
||||
MOVD R7, (m_mOS+mOS_libcall+libcall_fn)(R6)
|
||||
MOVD 104(R1), R7
|
||||
MOVD R7, (m_libcall+libcall_args)(R6)
|
||||
MOVD R7, (m_mOS+mOS_libcall+libcall_args)(R6)
|
||||
MOVD 112(R1), R7
|
||||
MOVD R7, (m_libcall+libcall_n)(R6)
|
||||
MOVD R7, (m_mOS+mOS_libcall+libcall_n)(R6)
|
||||
MOVD 120(R1), R7
|
||||
MOVD R7, (m_libcall+libcall_r1)(R6)
|
||||
MOVD R7, (m_mOS+mOS_libcall+libcall_r1)(R6)
|
||||
MOVD 128(R1), R7
|
||||
MOVD R7, (m_libcall+libcall_r2)(R6)
|
||||
MOVD R7, (m_mOS+mOS_libcall+libcall_r2)(R6)
|
||||
|
||||
// restore errno
|
||||
MOVD (m_mOS+mOS_perrno)(R6), R7
|
||||
|
|
|
@ -155,7 +155,7 @@ allgood:
|
|||
|
||||
// save m->libcall
|
||||
MOVQ g_m(R10), BP
|
||||
LEAQ m_libcall(BP), R11
|
||||
LEAQ (m_mOS+mOS_libcall)(BP), R11
|
||||
MOVQ libcall_fn(R11), R10
|
||||
MOVQ R10, 72(SP)
|
||||
MOVQ libcall_args(R11), R10
|
||||
|
@ -197,7 +197,7 @@ allgood:
|
|||
MOVQ g(BX), BP
|
||||
MOVQ g_m(BP), BP
|
||||
// restore libcall
|
||||
LEAQ m_libcall(BP), R11
|
||||
LEAQ (m_mOS+mOS_libcall)(BP), R11
|
||||
MOVQ 72(SP), R10
|
||||
MOVQ R10, libcall_fn(R11)
|
||||
MOVQ 80(SP), R10
|
||||
|
|
|
@ -11,49 +11,6 @@
|
|||
#define TEB_TlsSlots 0xE10
|
||||
#define TEB_ArbitraryPtr 0x14
|
||||
|
||||
TEXT runtime·asmstdcall_trampoline<ABIInternal>(SB),NOSPLIT,$0
|
||||
JMP runtime·asmstdcall(SB)
|
||||
|
||||
// void runtime·asmstdcall(void *c);
|
||||
TEXT runtime·asmstdcall(SB),NOSPLIT,$0
|
||||
MOVL fn+0(FP), BX
|
||||
MOVL SP, BP // save stack pointer
|
||||
|
||||
// SetLastError(0).
|
||||
MOVL $0, 0x34(FS)
|
||||
|
||||
MOVL libcall_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 libcall_args(BX), SI
|
||||
CLD
|
||||
REP; MOVSL
|
||||
|
||||
docall:
|
||||
// Call stdcall or cdecl function.
|
||||
// DI SI BP BX are preserved, SP is not
|
||||
CALL libcall_fn(BX)
|
||||
MOVL BP, SP
|
||||
|
||||
// Return result.
|
||||
MOVL fn+0(FP), BX
|
||||
MOVL AX, libcall_r1(BX)
|
||||
MOVL DX, libcall_r2(BX)
|
||||
|
||||
// GetLastError().
|
||||
MOVL 0x34(FS), AX
|
||||
MOVL AX, libcall_err(BX)
|
||||
|
||||
RET
|
||||
|
||||
// faster get/set last error
|
||||
TEXT runtime·getlasterror(SB),NOSPLIT,$0
|
||||
MOVL 0x34(FS), AX
|
||||
|
|
|
@ -12,85 +12,6 @@
|
|||
#define TEB_TlsSlots 0x1480
|
||||
#define TEB_ArbitraryPtr 0x28
|
||||
|
||||
TEXT runtime·asmstdcall_trampoline<ABIInternal>(SB),NOSPLIT,$0
|
||||
MOVQ AX, CX
|
||||
JMP runtime·asmstdcall(SB)
|
||||
|
||||
// void runtime·asmstdcall(void *c);
|
||||
TEXT runtime·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 libcall_fn(CX), AX
|
||||
MOVQ libcall_args(CX), SI
|
||||
MOVQ libcall_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, libcall_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, libcall_r2(CX)
|
||||
|
||||
// GetLastError().
|
||||
MOVQ 0x30(GS), DI
|
||||
MOVL 0x68(DI), AX
|
||||
MOVQ AX, libcall_err(CX)
|
||||
|
||||
RET
|
||||
|
||||
// faster get/set last error
|
||||
TEXT runtime·getlasterror(SB),NOSPLIT,$0
|
||||
MOVQ 0x30(GS), AX
|
||||
|
|
|
@ -9,76 +9,6 @@
|
|||
|
||||
// Note: For system ABI, R0-R3 are args, R4-R11 are callee-save.
|
||||
|
||||
TEXT runtime·asmstdcall_trampoline<ABIInternal>(SB),NOSPLIT,$0
|
||||
B runtime·asmstdcall(SB)
|
||||
|
||||
// void runtime·asmstdcall(void *c);
|
||||
TEXT runtime·asmstdcall(SB),NOSPLIT|NOFRAME,$0
|
||||
MOVM.DB.W [R4, R5, R14], (R13) // push {r4, r5, lr}
|
||||
MOVW R0, R4 // put libcall * 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 // libcall->args
|
||||
|
||||
// Do we have more than 4 arguments?
|
||||
MOVW 4(R4), R0 // libcall->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 libcall struct
|
||||
// R12: libcall->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 libcall->fn
|
||||
BL (R12)
|
||||
|
||||
MOVW R5, R13 // free stack space
|
||||
MOVW R0, 12(R4) // save return value to libcall->r1
|
||||
MOVW R1, 16(R4)
|
||||
|
||||
// GetLastError
|
||||
MRC 15, 0, R1, C13, C0, 2
|
||||
MOVW 0x34(R1), R0
|
||||
MOVW R0, 20(R4) // store in libcall->err
|
||||
|
||||
MOVM.IA.W (R13), [R4, R5, R15]
|
||||
|
||||
TEXT runtime·getlasterror(SB),NOSPLIT,$0
|
||||
MRC 15, 0, R0, C13, C0, 2
|
||||
MOVW 0x34(R0), R0
|
||||
|
|
|
@ -19,88 +19,6 @@
|
|||
//
|
||||
// load_g and save_g (in tls_arm64.s) clobber R27 (REGTMP) and R0.
|
||||
|
||||
TEXT runtime·asmstdcall_trampoline<ABIInternal>(SB),NOSPLIT,$0
|
||||
B runtime·asmstdcall(SB)
|
||||
|
||||
// void runtime·asmstdcall(void *c);
|
||||
TEXT runtime·asmstdcall(SB),NOSPLIT,$16
|
||||
STP (R19, R20), 16(RSP) // save old R19, R20
|
||||
MOVD R0, R19 // save libcall pointer
|
||||
MOVD RSP, R20 // save stack pointer
|
||||
|
||||
// SetLastError(0)
|
||||
MOVD $0, TEB_error(R18_PLATFORM)
|
||||
MOVD libcall_args(R19), R12 // libcall->args
|
||||
|
||||
// Do we have more than 8 arguments?
|
||||
MOVD libcall_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 libcall_fn(R19), R12 // branch to libcall->fn
|
||||
BL (R12)
|
||||
|
||||
MOVD R20, RSP // free stack space
|
||||
MOVD R0, libcall_r1(R19) // save return value to libcall->r1
|
||||
// TODO(rsc) floating point like amd64 in libcall->r2?
|
||||
|
||||
// GetLastError
|
||||
MOVD TEB_error(R18_PLATFORM), R0
|
||||
MOVD R0, libcall_err(R19)
|
||||
|
||||
// Restore callee-saved registers.
|
||||
LDP 16(RSP), (R19, R20)
|
||||
RET
|
||||
|
||||
TEXT runtime·getlasterror(SB),NOSPLIT,$0
|
||||
MOVD TEB_error(R18_PLATFORM), R0
|
||||
MOVD R0, ret+0(FP)
|
||||
|
|
|
@ -7,6 +7,7 @@ package runtime
|
|||
import (
|
||||
"internal/abi"
|
||||
"internal/goarch"
|
||||
"internal/runtime/syscall/windows"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
|
@ -487,13 +488,6 @@ func syscall_Syscall18(fn, nargs, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11,
|
|||
return syscall_syscalln(fn, nargs, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18)
|
||||
}
|
||||
|
||||
// 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
|
||||
|
||||
//go:linkname syscall_SyscallN syscall.SyscallN
|
||||
//go:nosplit
|
||||
func syscall_SyscallN(fn uintptr, args ...uintptr) (r1, r2, err uintptr) {
|
||||
|
@ -505,7 +499,7 @@ func syscall_syscalln(fn, n uintptr, args ...uintptr) (r1, r2, err uintptr) {
|
|||
if n > uintptr(len(args)) {
|
||||
panic("syscall: n > len(args)") // should not be reachable from user code
|
||||
}
|
||||
if n > maxArgs {
|
||||
if n > windows.MaxArgs {
|
||||
panic("runtime: SyscallN has too many arguments")
|
||||
}
|
||||
|
||||
|
@ -513,15 +507,15 @@ func syscall_syscalln(fn, n uintptr, args ...uintptr) (r1, r2, err uintptr) {
|
|||
// the stack because the stack can move during fn if it
|
||||
// calls back into Go.
|
||||
c := &getg().m.winsyscall
|
||||
c.fn = fn
|
||||
c.n = n
|
||||
if c.n != 0 {
|
||||
c.args = uintptr(noescape(unsafe.Pointer(&args[0])))
|
||||
c.Fn = fn
|
||||
c.N = n
|
||||
if c.N != 0 {
|
||||
c.Args = uintptr(noescape(unsafe.Pointer(&args[0])))
|
||||
}
|
||||
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, c.Err
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@ import (
|
|||
"fmt"
|
||||
"internal/abi"
|
||||
"internal/race"
|
||||
"internal/runtime/syscall/windows"
|
||||
"internal/syscall/windows/sysdll"
|
||||
"internal/testenv"
|
||||
"io"
|
||||
|
@ -776,7 +777,7 @@ func TestSyscallN(t *testing.T) {
|
|||
t.Skipf("skipping test: GOARCH=%s", runtime.GOARCH)
|
||||
}
|
||||
|
||||
for arglen := 0; arglen <= runtime.MaxArgs; arglen++ {
|
||||
for arglen := 0; arglen <= windows.MaxArgs; arglen++ {
|
||||
arglen := arglen
|
||||
t.Run(fmt.Sprintf("arg-%d", arglen), func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue