mirror of
https://github.com/tinygo-org/tinygo.git
synced 2026-08-04 19:17:47 +00:00
compiler, runtime: fix SyscallN handling for Windows on Go 1.26+
Go 1.26 changed all Windows syscall wrappers in zsyscall_windows.go to use SyscallN instead of fixed-argument Syscall/Syscall6/etc. The SyscallN function now has a body that calls an unexported syscalln function (provided by runtime via //go:linkname). TinyGo's existing createSyscall compiler builtin used call.Args[2:] to extract syscall arguments, but for variadic SyscallN the SSA representation passes args as a slice value (not individual args), causing call.Args[2:] to be empty -- resulting in zero arguments being passed to Windows API calls and 0xc0000005 access violations. Fix this by: 1. Excluding syscall.SyscallN from builtin interception, letting Go 1.26's function body compile normally (it calls syscalln) 2. Adding a new createSyscalln compiler builtin that intercepts syscall.syscalln and correctly handles the variadic slice: - Generates a switch on the arg count n (0-18 cases) - Each case loads args from the slice via GEP/Load - Wraps calls with SetLastError(0)/GetLastError() as before - Handles i386 stdcall conventions 3. Adding runtime stubs for both Go versions: - go1.26: syscall.syscalln stub (body intercepted by compiler) - pre-go1.26: syscall.SyscallN stub (linker satisfaction)
This commit is contained in:
@@ -0,0 +1,18 @@
|
||||
//go:build windows && !go1.26
|
||||
|
||||
package runtime
|
||||
|
||||
// For Go < 1.26, SyscallN is declared without a body in
|
||||
// syscall/dll_windows.go. The standard Go runtime provides its implementation
|
||||
// via //go:linkname. TinyGo must provide one as well.
|
||||
//
|
||||
// Note: The TinyGo compiler cannot correctly handle SyscallN as a builtin
|
||||
// because it uses variadic arguments represented as a slice in SSA, which
|
||||
// the fixed-argument builtin mechanism cannot process. This implementation
|
||||
// is provided to satisfy the linker for code paths that reference SyscallN
|
||||
// (e.g., syscall.Proc.Call).
|
||||
|
||||
//go:linkname syscall_SyscallN syscall.SyscallN
|
||||
func syscall_SyscallN(trap uintptr, args ...uintptr) (r1, r2, err uintptr) {
|
||||
panic("syscall.SyscallN is not yet supported in TinyGo for Go < 1.26")
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
//go:build windows && go1.26
|
||||
|
||||
package runtime
|
||||
|
||||
// Starting with Go 1.26, the syscall package on Windows defines function bodies
|
||||
// for Syscall, SyscallN, etc., that all call syscalln (lowercase). In standard
|
||||
// Go, syscalln is provided by the runtime via //go:linkname. TinyGo's compiler
|
||||
// intercepts calls to syscall.syscalln and replaces them with inline LLVM IR
|
||||
// (see compiler/syscall.go createSyscalln), so this function body is never
|
||||
// actually called at runtime. However, the compiled function bodies in the
|
||||
// syscall package still reference it, so we must provide a definition to
|
||||
// satisfy the linker.
|
||||
|
||||
//go:linkname syscall_syscalln syscall.syscalln
|
||||
func syscall_syscalln(fn, n uintptr, args ...uintptr) (r1, r2, err uintptr) {
|
||||
panic("unreachable: syscall.syscalln should be handled by the compiler")
|
||||
}
|
||||
Reference in New Issue
Block a user