syscall: remove the 42 args limit in SyscallN

SyscallN already supports more than 42 arguments on 386 and arm64.
Lift that limit on amd64 as well.

Change-Id: I3f5c6ebb959aa9b0d367903cac119fc27cb93064
Reviewed-on: https://go-review.googlesource.com/c/go/+/751862
Reviewed-by: Cherry Mui <cherryyz@google.com>
Reviewed-by: Alex Brainman <alex.brainman@gmail.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Carlos Amedee <carlos@golang.org>
This commit is contained in:
qmuntal
2026-03-06 13:22:34 +01:00
committed by Quim Muntal
parent 4216fa3d04
commit 7c42da1bc5
4 changed files with 15 additions and 23 deletions

View File

@@ -23,19 +23,22 @@ TEXT ·asmstdcall(SB),NOSPLIT,$16
MOVQ 0x30(GS), DI
MOVL $0, 0x68(DI)
SUBQ $(const_MaxArgs*8), SP // room for args
MOVQ SP, R12 // save frame pointer in the callee-saved R12 register to restore it before return
SUBQ $32, SP // reserve shadow space (Windows x64 ABI)
// Fast version, do not store args on the stack.
// Fast version (n <= 4): no stack copy needed.
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
// Slow version (n > 4): grow stack for remaining args.
// Stack stays 16-byte aligned by rounding extra slots to even.
LEAQ -3(CX), R8
ANDQ $~1, R8
SHLQ $3, R8
SUBQ R8, SP
// Copy args to the stack.
MOVQ SP, DI
@@ -65,7 +68,7 @@ _0args:
// Call stdcall function.
CALL AX
ADDQ $(const_MaxArgs*8), SP
MOVQ R12, SP // restore frame pointer
// Return result.
MOVQ 0(SP), CX

View File

@@ -10,13 +10,6 @@ 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

View File

@@ -7,7 +7,6 @@ package runtime
import (
"internal/abi"
"internal/goarch"
"internal/runtime/syscall/windows"
"unsafe"
)
@@ -415,9 +414,6 @@ 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 > windows.MaxArgs {
panic("runtime: SyscallN has too many arguments")
}
// The cgocall parameters are stored in m instead of in
// the stack because the stack can move during fn if it

View File

@@ -8,7 +8,6 @@ import (
"fmt"
"internal/abi"
"internal/race"
"internal/runtime/syscall/windows"
"internal/syscall/windows/sysdll"
"internal/testenv"
"io"
@@ -773,12 +772,13 @@ func TestSyscallN(t *testing.T) {
if _, err := exec.LookPath("gcc"); err != nil {
t.Skip("skipping test: gcc is missing")
}
if runtime.GOARCH != "amd64" {
t.Skipf("skipping test: GOARCH=%s", runtime.GOARCH)
var nargs = 64
if testing.Short() {
nargs = 16
}
for arglen := 0; arglen <= windows.MaxArgs; arglen++ {
arglen := arglen
for arglen := range nargs {
t.Run(fmt.Sprintf("arg-%d", arglen), func(t *testing.T) {
t.Parallel()
args := make([]string, arglen)