diff --git a/windows/mkwinsyscall/mkwinsyscall.go b/windows/mkwinsyscall/mkwinsyscall.go
index 11f4873bce..3947092c5f 100644
--- a/windows/mkwinsyscall/mkwinsyscall.go
+++ b/windows/mkwinsyscall/mkwinsyscall.go
@@ -57,7 +57,6 @@ import (
 	"go/parser"
 	"go/token"
 	"io"
-	"io/ioutil"
 	"log"
 	"os"
 	"path/filepath"
@@ -568,6 +567,8 @@ func (f *Fn) SyscallParamCount() int {
 		return 12
 	case n <= 15:
 		return 15
+	case n <= 42: // current SyscallN limit
+		return n
 	default:
 		panic("too many arguments to system call")
 	}
@@ -579,6 +580,9 @@ func (f *Fn) Syscall() string {
 	if c == 3 {
 		return syscalldot() + "Syscall"
 	}
+	if c > 15 {
+		return syscalldot() + "SyscallN"
+	}
 	return syscalldot() + "Syscall" + strconv.Itoa(c)
 }
 
@@ -923,7 +927,7 @@ func main() {
 	if *filename == "" {
 		_, err = os.Stdout.Write(data)
 	} else {
-		err = ioutil.WriteFile(*filename, data, 0644)
+		err = os.WriteFile(*filename, data, 0644)
 	}
 	if err != nil {
 		log.Fatal(err)
@@ -1011,7 +1015,7 @@ func {{.HelperName}}({{.HelperParamList}}) {{template "results" .}}{
 
 {{define "results"}}{{if .Rets.List}}{{.Rets.List}} {{end}}{{end}}
 
-{{define "syscall"}}{{.Rets.SetReturnValuesCode}}{{.Syscall}}(proc{{.DLLFuncName}}.Addr(), {{.ParamCount}}, {{.SyscallParamList}}){{end}}
+{{define "syscall"}}{{.Rets.SetReturnValuesCode}}{{.Syscall}}(proc{{.DLLFuncName}}.Addr(),{{if le .ParamCount 15}} {{.ParamCount}},{{end}} {{.SyscallParamList}}){{end}}
 
 {{define "tmpvarsreadback"}}{{range .Params}}{{if .TmpVarReadbackCode}}
 {{.TmpVarReadbackCode}}{{end}}{{end}}{{end}}
diff --git a/windows/mkwinsyscall/mkwinsyscall_test.go b/windows/mkwinsyscall/mkwinsyscall_test.go
index cabbf40312..b000e6b5cc 100644
--- a/windows/mkwinsyscall/mkwinsyscall_test.go
+++ b/windows/mkwinsyscall/mkwinsyscall_test.go
@@ -9,6 +9,7 @@ import (
 	"go/format"
 	"os"
 	"path/filepath"
+	"strings"
 	"testing"
 )
 
@@ -48,3 +49,65 @@ func TestDLLFilenameEscaping(t *testing.T) {
 		})
 	}
 }
+
+func TestSyscallXGeneration(t *testing.T) {
+	tests := []struct {
+		name        string
+		wantsysfunc string
+		sig         string
+	}{
+		{
+			name:        "syscall with 2 params",
+			wantsysfunc: "syscall.Syscall",
+			sig:         "Example(a1 *uint16, a2 *uint16) = ",
+		},
+		{
+			name:        "syscall with 6 params",
+			wantsysfunc: "syscall.Syscall6",
+			sig:         "Example(a1 *uint, a2 *uint, a3 *uint, a4 *uint, a5 *uint, a6 *uint) = ",
+		},
+		{
+			name:        "syscall with 15 params",
+			wantsysfunc: "syscall.Syscall15",
+			sig: strings.ReplaceAll(`Example(a1 *uint, a2 *uint, a3 *uint, a4 *uint, a5 *uint, a6 *uint,
+						a7 *uint, a8 *uint, a9 *uint, a10 *uint, a11 *uint, a12 *uint,
+						a13 *uint, a14 *uint, a15 *uint) = `, "\n", ""),
+		},
+		{
+			name:        "syscall with 18 params",
+			wantsysfunc: "syscall.SyscallN",
+			sig: strings.ReplaceAll(`Example(a1 *uint, a2 *uint, a3 *uint, a4 *uint, a5 *uint, a6 *uint,
+						a7 *uint, a8 *uint, a9 *uint, a10 *uint, a11 *uint, a12 *uint,
+						a13 *uint, a14 *uint, a15 *uint, a16 *uint, a17 *uint, a18 *uint) = `, "\n", ""),
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			// Write the syscall into a temp file for testing.
+			prefix := "package windows\n//sys " + tt.sig
+			suffix := ".Example"
+			name := filepath.Join(t.TempDir(), "syscall.go")
+			if err := os.WriteFile(name, []byte(prefix+"example"+suffix), 0666); err != nil {
+				t.Fatal(err)
+			}
+
+			// Ensure parsing, generating, and formatting run without errors.
+			// This is good enough to show that escaping is working.
+			src, err := ParseFiles([]string{name})
+			if err != nil {
+				t.Fatal(err)
+			}
+			var buf bytes.Buffer
+			if err := src.Generate(&buf); err != nil {
+				t.Fatal(err)
+			}
+			if _, err := format.Source(buf.Bytes()); err != nil {
+				t.Fatal(err)
+			}
+
+			if !strings.Contains(buf.String(), tt.wantsysfunc+"(") {
+				t.Fatalf("expected syscall func %q in buffer %s", tt.wantsysfunc, buf.String())
+			}
+		})
+	}
+}