]> Cypherpunks repositories - gostls13.git/commitdiff
runtime: allow to call stdcall from Go on windows
authorDmitriy Vyukov <dvyukov@google.com>
Fri, 29 Aug 2014 08:44:07 +0000 (12:44 +0400)
committerDmitriy Vyukov <dvyukov@google.com>
Fri, 29 Aug 2014 08:44:07 +0000 (12:44 +0400)
I've started with just one function with 8 arguments,
but stdcall is called from nosplit functions
and 8 args overflow nosplit area.

LGTM=aram, alex.brainman
R=golang-codereviews, aram, alex.brainman, dave
CC=golang-codereviews, iant, khr, rsc
https://golang.org/cl/135090043

src/pkg/runtime/mem_windows.c
src/pkg/runtime/netpoll_windows.c
src/pkg/runtime/os_windows.c
src/pkg/runtime/os_windows.go
src/pkg/runtime/os_windows.h

index 77ec6e92626abdb5cc7696817ae1d2eac5191a0d..5eb43b2a9320f377edad04188c0a9699c1e53db6 100644 (file)
@@ -29,7 +29,7 @@ void*
 runtime·SysAlloc(uintptr n, uint64 *stat)
 {
        runtime·xadd64(stat, n);
-       return runtime·stdcall(runtime·VirtualAlloc, 4, nil, n, (uintptr)(MEM_COMMIT|MEM_RESERVE), (uintptr)PAGE_READWRITE);
+       return runtime·stdcall4(runtime·VirtualAlloc, 0, n, MEM_COMMIT|MEM_RESERVE, PAGE_READWRITE);
 }
 
 void
@@ -38,7 +38,7 @@ runtime·SysUnused(void *v, uintptr n)
        void *r;
        uintptr small;
 
-       r = runtime·stdcall(runtime·VirtualFree, 3, v, n, (uintptr)MEM_DECOMMIT);
+       r = runtime·stdcall3(runtime·VirtualFree, (uintptr)v, n, MEM_DECOMMIT);
        if(r != nil)
                return;
 
@@ -53,7 +53,7 @@ runtime·SysUnused(void *v, uintptr n)
        // in the worst case, but that's fast enough.
        while(n > 0) {
                small = n;
-               while(small >= 4096 && runtime·stdcall(runtime·VirtualFree, 3, v, small, (uintptr)MEM_DECOMMIT) == nil)
+               while(small >= 4096 && runtime·stdcall3(runtime·VirtualFree, (uintptr)v, small, MEM_DECOMMIT) == nil)
                        small = (small / 2) & ~(4096-1);
                if(small < 4096)
                        runtime·throw("runtime: failed to decommit pages");
@@ -67,7 +67,7 @@ runtime·SysUsed(void *v, uintptr n)
 {
        void *r;
 
-       r = runtime·stdcall(runtime·VirtualAlloc, 4, v, n, (uintptr)MEM_COMMIT, (uintptr)PAGE_READWRITE);
+       r = runtime·stdcall4(runtime·VirtualAlloc, (uintptr)v, n, MEM_COMMIT, PAGE_READWRITE);
        if(r != v)
                runtime·throw("runtime: failed to commit pages");
 }
@@ -78,7 +78,7 @@ runtime·SysFree(void *v, uintptr n, uint64 *stat)
        uintptr r;
 
        runtime·xadd64(stat, -(uint64)n);
-       r = (uintptr)runtime·stdcall(runtime·VirtualFree, 3, v, (uintptr)0, (uintptr)MEM_RELEASE);
+       r = (uintptr)runtime·stdcall3(runtime·VirtualFree, (uintptr)v, 0, MEM_RELEASE);
        if(r == 0)
                runtime·throw("runtime: failed to release pages");
 }
@@ -96,12 +96,12 @@ runtime·SysReserve(void *v, uintptr n, bool *reserved)
        *reserved = true;
        // v is just a hint.
        // First try at v.
-       v = runtime·stdcall(runtime·VirtualAlloc, 4, v, n, (uintptr)MEM_RESERVE, (uintptr)PAGE_READWRITE);
+       v = runtime·stdcall4(runtime·VirtualAlloc, (uintptr)v, n, MEM_RESERVE, PAGE_READWRITE);
        if(v != nil)
                return v;
        
        // Next let the kernel choose the address.
-       return runtime·stdcall(runtime·VirtualAlloc, 4, nil, n, (uintptr)MEM_RESERVE, (uintptr)PAGE_READWRITE);
+       return runtime·stdcall4(runtime·VirtualAlloc, 0, n, MEM_RESERVE, PAGE_READWRITE);
 }
 
 void
@@ -112,7 +112,7 @@ runtime·SysMap(void *v, uintptr n, bool reserved, uint64 *stat)
        USED(reserved);
 
        runtime·xadd64(stat, n);
-       p = runtime·stdcall(runtime·VirtualAlloc, 4, v, n, (uintptr)MEM_COMMIT, (uintptr)PAGE_READWRITE);
+       p = runtime·stdcall4(runtime·VirtualAlloc, (uintptr)v, n, MEM_COMMIT, PAGE_READWRITE);
        if(p != v)
                runtime·throw("runtime: cannot map pages in arena address space");
 }
index 45282921251bfddc1b849af572fc66d79475e9f8..64da41ad9049af21acdcdf194d0a9aabb0f789f7 100644 (file)
@@ -47,7 +47,7 @@ static uintptr iocphandle = INVALID_HANDLE_VALUE;  // completion port io handle
 void
 runtime·netpollinit(void)
 {
-       iocphandle = (uintptr)runtime·stdcall(runtime·CreateIoCompletionPort, 4, INVALID_HANDLE_VALUE, (uintptr)0, (uintptr)0, (uintptr)DWORD_MAX);
+       iocphandle = (uintptr)runtime·stdcall4(runtime·CreateIoCompletionPort, INVALID_HANDLE_VALUE, 0, 0, DWORD_MAX);
        if(iocphandle == 0) {
                runtime·printf("netpoll: failed to create iocp handle (errno=%d)\n", runtime·getlasterror());
                runtime·throw("netpoll: failed to create iocp handle");
@@ -59,7 +59,7 @@ int32
 runtime·netpollopen(uintptr fd, PollDesc *pd)
 {
        USED(pd);
-       if(runtime·stdcall(runtime·CreateIoCompletionPort, 4, fd, iocphandle, (uintptr)0, (uintptr)0) == 0)
+       if(runtime·stdcall4(runtime·CreateIoCompletionPort, fd, iocphandle, 0, 0) == 0)
                return -runtime·getlasterror();
        return 0;
 }
@@ -103,7 +103,7 @@ retry:
                        n = 8;
                if(block)
                        g->m->blocked = true;
-               if(runtime·stdcall(runtime·GetQueuedCompletionStatusEx, 6, iocphandle, entries, (uintptr)n, &n, (uintptr)wait, (uintptr)0) == 0) {
+               if(runtime·stdcall6(runtime·GetQueuedCompletionStatusEx, iocphandle, (uintptr)entries, n, (uintptr)&n, wait, 0) == 0) {
                        g->m->blocked = false;
                        errno = runtime·getlasterror();
                        if(!block && errno == WAIT_TIMEOUT)
@@ -116,7 +116,7 @@ retry:
                        op = entries[i].op;
                        errno = 0;
                        qty = 0;
-                       if(runtime·stdcall(runtime·WSAGetOverlappedResult, 5, runtime·netpollfd(op->pd), op, &qty, (uintptr)0, (uintptr)&flags) == 0)
+                       if(runtime·stdcall5(runtime·WSAGetOverlappedResult, runtime·netpollfd(op->pd), (uintptr)op, (uintptr)&qty, 0, (uintptr)&flags) == 0)
                                errno = runtime·getlasterror();
                        handlecompletion(&gp, op, errno, qty);
                }
@@ -126,7 +126,7 @@ retry:
                qty = 0;
                if(block)
                        g->m->blocked = true;
-               if(runtime·stdcall(runtime·GetQueuedCompletionStatus, 5, iocphandle, &qty, &key, &op, (uintptr)wait) == 0) {
+               if(runtime·stdcall5(runtime·GetQueuedCompletionStatus, iocphandle, (uintptr)&qty, (uintptr)&key, (uintptr)&op, wait) == 0) {
                        g->m->blocked = false;
                        errno = runtime·getlasterror();
                        if(!block && errno == WAIT_TIMEOUT)
index aadc30a076f5b25b3d9cc6e8dc4eb977fdc9786c..43026d64577c23ac0435bc052e953be00677b3bc 100644 (file)
@@ -81,7 +81,7 @@ getproccount(void)
 {
        SystemInfo info;
 
-       runtime·stdcall(runtime·GetSystemInfo, 1, &info);
+       runtime·stdcall1(runtime·GetSystemInfo, (uintptr)&info);
        return info.dwNumberOfProcessors;
 }
 
@@ -92,20 +92,20 @@ runtime·osinit(void)
 
        runtime·externalthreadhandlerp = (uintptr)runtime·externalthreadhandler;
 
-       runtime·stdcall(runtime·AddVectoredExceptionHandler, 2, (uintptr)1, (uintptr)runtime·sigtramp);
-       runtime·stdcall(runtime·SetConsoleCtrlHandler, 2, runtime·ctrlhandler, (uintptr)1);
-       runtime·stdcall(runtime·timeBeginPeriod, 1, (uintptr)1);
+       runtime·stdcall2(runtime·AddVectoredExceptionHandler, 1, (uintptr)runtime·sigtramp);
+       runtime·stdcall2(runtime·SetConsoleCtrlHandler, (uintptr)runtime·ctrlhandler, 1);
+       runtime·stdcall1(runtime·timeBeginPeriod, 1);
        runtime·ncpu = getproccount();
        
        // Windows dynamic priority boosting assumes that a process has different types
        // of dedicated threads -- GUI, IO, computational, etc. Go processes use
        // equivalent threads that all do a mix of GUI, IO, computations, etc.
        // In such context dynamic priority boosting does nothing but harm, so we turn it off.
-       runtime·stdcall(runtime·SetProcessPriorityBoost, 2, (uintptr)-1, (uintptr)1);
+       runtime·stdcall2(runtime·SetProcessPriorityBoost, -1, 1);
 
-       kernel32 = runtime·stdcall(runtime·LoadLibraryA, 1, "kernel32.dll");
+       kernel32 = runtime·stdcall1(runtime·LoadLibraryA, (uintptr)"kernel32.dll");
        if(kernel32 != nil) {
-               runtime·GetQueuedCompletionStatusEx = runtime·stdcall(runtime·GetProcAddress, 2, kernel32, "GetQueuedCompletionStatusEx");
+               runtime·GetQueuedCompletionStatusEx = runtime·stdcall2(runtime·GetProcAddress, (uintptr)kernel32, (uintptr)"GetQueuedCompletionStatusEx");
        }
 }
 
@@ -115,15 +115,15 @@ runtime·get_random_data(byte **rnd, int32 *rnd_len)
        uintptr handle;
        *rnd = nil;
        *rnd_len = 0;
-       if(runtime·stdcall(runtime·CryptAcquireContextW, 5, &handle, nil, nil,
-                          (uintptr)1 /* PROV_RSA_FULL */,
-                          (uintptr)0xf0000000U /* CRYPT_VERIFYCONTEXT */) != 0) {
+       if(runtime·stdcall5(runtime·CryptAcquireContextW, (uintptr)&handle, (uintptr)nil, (uintptr)nil,
+                          1 /* PROV_RSA_FULL */,
+                          0xf0000000U /* CRYPT_VERIFYCONTEXT */) != 0) {
                static byte random_data[HashRandomBytes];
-               if(runtime·stdcall(runtime·CryptGenRandom, 3, handle, (uintptr)HashRandomBytes, random_data)) {
+               if(runtime·stdcall3(runtime·CryptGenRandom, handle, HashRandomBytes, (uintptr)&random_data[0])) {
                        *rnd = random_data;
                        *rnd_len = HashRandomBytes;
                }
-               runtime·stdcall(runtime·CryptReleaseContext, 2, handle, (uintptr)0);
+               runtime·stdcall2(runtime·CryptReleaseContext, handle, 0);
        }
 }
 
@@ -137,7 +137,7 @@ runtime·goenvs(void)
        int32 i, n;
        uint16 *p;
 
-       env = runtime·stdcall(runtime·GetEnvironmentStringsW, 0);
+       env = runtime·stdcall0(runtime·GetEnvironmentStringsW);
 
        n = 0;
        for(p=env; *p; n++)
@@ -154,13 +154,13 @@ runtime·goenvs(void)
        syscall·envs.len = n;
        syscall·envs.cap = n;
 
-       runtime·stdcall(runtime·FreeEnvironmentStringsW, 1, env);
+       runtime·stdcall1(runtime·FreeEnvironmentStringsW, (uintptr)env);
 }
 
 void
 runtime·exit(int32 code)
 {
-       runtime·stdcall(runtime·ExitProcess, 1, (uintptr)code);
+       runtime·stdcall1(runtime·ExitProcess, code);
 }
 
 int32
@@ -172,17 +172,17 @@ runtime·write(uintptr fd, void *buf, int32 n)
        written = 0;
        switch(fd) {
        case 1:
-               handle = runtime·stdcall(runtime·GetStdHandle, 1, (uintptr)-11);
+               handle = runtime·stdcall1(runtime·GetStdHandle, -11);
                break;
        case 2:
-               handle = runtime·stdcall(runtime·GetStdHandle, 1, (uintptr)-12);
+               handle = runtime·stdcall1(runtime·GetStdHandle, -12);
                break;
        default:
                // assume fd is real windows handle.
                handle = (void*)fd;
                break;
        }
-       runtime·stdcall(runtime·WriteFile, 5, handle, buf, (uintptr)n, &written, (uintptr)0);
+       runtime·stdcall5(runtime·WriteFile, (uintptr)handle, (uintptr)buf, n, (uintptr)&written, 0);
        return written;
 }
 
@@ -200,7 +200,7 @@ runtime·semasleep(int64 ns)
                if(ns == 0)
                        ns = 1;
        }
-       if(runtime·stdcall(runtime·WaitForSingleObject, 2, g->m->waitsema, (uintptr)ns) != 0)
+       if(runtime·stdcall2(runtime·WaitForSingleObject, (uintptr)g->m->waitsema, ns) != 0)
                return -1;  // timeout
        return 0;
 }
@@ -208,13 +208,13 @@ runtime·semasleep(int64 ns)
 void
 runtime·semawakeup(M *mp)
 {
-       runtime·stdcall(runtime·SetEvent, 1, mp->waitsema);
+       runtime·stdcall1(runtime·SetEvent, mp->waitsema);
 }
 
 uintptr
 runtime·semacreate(void)
 {
-       return (uintptr)runtime·stdcall(runtime·CreateEvent, 4, (uintptr)0, (uintptr)0, (uintptr)0, (uintptr)0);
+       return (uintptr)runtime·stdcall4(runtime·CreateEvent, 0, 0, 0, 0);
 }
 
 #define STACK_SIZE_PARAM_IS_A_RESERVATION ((uintptr)0x00010000)
@@ -226,9 +226,9 @@ runtime·newosproc(M *mp, void *stk)
 
        USED(stk);
 
-       thandle = runtime·stdcall(runtime·CreateThread, 6,
-               nil, (uintptr)0x20000, runtime·tstart_stdcall, mp,
-               STACK_SIZE_PARAM_IS_A_RESERVATION, nil);
+       thandle = runtime·stdcall6(runtime·CreateThread,
+               (uintptr)nil, 0x20000, (uintptr)runtime·tstart_stdcall, (uintptr)mp,
+               STACK_SIZE_PARAM_IS_A_RESERVATION, (uintptr)nil);
        if(thandle == nil) {
                runtime·printf("runtime: failed to create new OS thread (have %d already; errno=%d)\n", runtime·mcount(), runtime·getlasterror());
                runtime·throw("runtime.newosproc");
@@ -251,9 +251,7 @@ runtime·minit(void)
        void *thandle;
 
        // -1 = current process, -2 = current thread
-       runtime·stdcall(runtime·DuplicateHandle, 7,
-               (uintptr)-1, (uintptr)-2, (uintptr)-1, &thandle,
-               (uintptr)0, (uintptr)0, (uintptr)DUPLICATE_SAME_ACCESS);
+       runtime·stdcall7(runtime·DuplicateHandle, -1, -2, -1, (uintptr)&thandle, 0, 0, DUPLICATE_SAME_ACCESS);
        runtime·atomicstorep(&g->m->thread, thandle);
 }
 
@@ -318,12 +316,10 @@ time·now(int64 sec, int32 usec)
 
 // Calling stdcall on os stack.
 #pragma textflag NOSPLIT
-void *
-runtime·stdcall(void *fn, int32 count, ...)
+static void*
+stdcall(void *fn)
 {
        g->m->libcall.fn = fn;
-       g->m->libcall.n = count;
-       g->m->libcall.args = (uintptr*)&count + 1;
        if(g->m->profilehz != 0) {
                // leave pc/sp for cpu profiler
                g->m->libcallg = g;
@@ -337,6 +333,85 @@ runtime·stdcall(void *fn, int32 count, ...)
        return (void*)g->m->libcall.r1;
 }
 
+#pragma textflag NOSPLIT
+void*
+runtime·stdcall0(void *fn)
+{
+       g->m->libcall.n = 0;
+       g->m->libcall.args = &fn;  // it's unused but must be non-nil, otherwise crashes
+       return stdcall(fn);
+}
+
+#pragma textflag NOSPLIT
+void*
+runtime·stdcall1(void *fn, uintptr a0)
+{
+       USED(a0);
+       g->m->libcall.n = 1;
+       g->m->libcall.args = &a0;
+       return stdcall(fn);
+}
+
+#pragma textflag NOSPLIT
+void*
+runtime·stdcall2(void *fn, uintptr a0, uintptr a1)
+{
+       USED(a0, a1);
+       g->m->libcall.n = 2;
+       g->m->libcall.args = &a0;
+       return stdcall(fn);
+}
+
+#pragma textflag NOSPLIT
+void*
+runtime·stdcall3(void *fn, uintptr a0, uintptr a1, uintptr a2)
+{
+       USED(a0, a1, a2);
+       g->m->libcall.n = 3;
+       g->m->libcall.args = &a0;
+       return stdcall(fn);
+}
+
+#pragma textflag NOSPLIT
+void*
+runtime·stdcall4(void *fn, uintptr a0, uintptr a1, uintptr a2, uintptr a3)
+{
+       USED(a0, a1, a2, a3);
+       g->m->libcall.n = 4;
+       g->m->libcall.args = &a0;
+       return stdcall(fn);
+}
+
+#pragma textflag NOSPLIT
+void*
+runtime·stdcall5(void *fn, uintptr a0, uintptr a1, uintptr a2, uintptr a3, uintptr a4)
+{
+       USED(a0, a1, a2, a3, a4);
+       g->m->libcall.n = 5;
+       g->m->libcall.args = &a0;
+       return stdcall(fn);
+}
+
+#pragma textflag NOSPLIT
+void*
+runtime·stdcall6(void *fn, uintptr a0, uintptr a1, uintptr a2, uintptr a3, uintptr a4, uintptr a5)
+{
+       USED(a0, a1, a2, a3, a4, a5);
+       g->m->libcall.n = 6;
+       g->m->libcall.args = &a0;
+       return stdcall(fn);
+}
+
+#pragma textflag NOSPLIT
+void*
+runtime·stdcall7(void *fn, uintptr a0, uintptr a1, uintptr a2, uintptr a3, uintptr a4, uintptr a5, uintptr a6)
+{
+       USED(a0, a1, a2, a3, a4, a5, a6);
+       g->m->libcall.n = 7;
+       g->m->libcall.args = &a0;
+       return stdcall(fn);
+}
+
 extern void runtime·usleep1(uint32);
 
 #pragma textflag NOSPLIT
@@ -451,7 +526,7 @@ profilem(M *mp)
        // align Context to 16 bytes
        r = (Context*)((uintptr)(&rbuf[15]) & ~15);
        r->ContextFlags = CONTEXT_CONTROL;
-       runtime·stdcall(runtime·GetThreadContext, 2, mp->thread, r);
+       runtime·stdcall2(runtime·GetThreadContext, (uintptr)mp->thread, (uintptr)r);
        runtime·dosigprof(r, gp, mp);
 }
 
@@ -461,11 +536,10 @@ runtime·profileloop1(void)
        M *mp, *allm;
        void *thread;
 
-       runtime·stdcall(runtime·SetThreadPriority, 2,
-               (uintptr)-2, (uintptr)THREAD_PRIORITY_HIGHEST);
+       runtime·stdcall2(runtime·SetThreadPriority, -2, THREAD_PRIORITY_HIGHEST);
 
        for(;;) {
-               runtime·stdcall(runtime·WaitForSingleObject, 2, profiletimer, (uintptr)-1);
+               runtime·stdcall2(runtime·WaitForSingleObject, (uintptr)profiletimer, -1);
                allm = runtime·atomicloadp(&runtime·allm);
                for(mp = allm; mp != nil; mp = mp->alllink) {
                        thread = runtime·atomicloadp(&mp->thread);
@@ -474,10 +548,10 @@ runtime·profileloop1(void)
                        // idle timer thread, idle heap scavenger, etc.
                        if(thread == nil || mp->profilehz == 0 || mp->blocked)
                                continue;
-                       runtime·stdcall(runtime·SuspendThread, 1, thread);
+                       runtime·stdcall1(runtime·SuspendThread, (uintptr)thread);
                        if(mp->profilehz != 0 && !mp->blocked)
                                profilem(mp);
-                       runtime·stdcall(runtime·ResumeThread, 1, thread);
+                       runtime·stdcall1(runtime·ResumeThread, (uintptr)thread);
                }
        }
 }
@@ -492,11 +566,11 @@ runtime·resetcpuprofiler(int32 hz)
 
        runtime·lock(&lock);
        if(profiletimer == nil) {
-               timer = runtime·stdcall(runtime·CreateWaitableTimer, 3, nil, nil, nil);
+               timer = runtime·stdcall3(runtime·CreateWaitableTimer, (uintptr)nil, (uintptr)nil, (uintptr)nil);
                runtime·atomicstorep(&profiletimer, timer);
-               thread = runtime·stdcall(runtime·CreateThread, 6,
-                       nil, nil, runtime·profileloop, nil, nil, nil);
-               runtime·stdcall(runtime·CloseHandle, 1, thread);
+               thread = runtime·stdcall6(runtime·CreateThread,
+                       (uintptr)nil, (uintptr)nil, (uintptr)runtime·profileloop, (uintptr)nil, (uintptr)nil, (uintptr)nil);
+               runtime·stdcall1(runtime·CloseHandle, (uintptr)thread);
        }
        runtime·unlock(&lock);
 
@@ -508,8 +582,8 @@ runtime·resetcpuprofiler(int32 hz)
                        ms = 1;
                due = ms * -10000;
        }
-       runtime·stdcall(runtime·SetWaitableTimer, 6,
-               profiletimer, &due, (uintptr)ms, nil, nil, nil);
+       runtime·stdcall6(runtime·SetWaitableTimer,
+               (uintptr)profiletimer, (uintptr)&due, ms, (uintptr)nil, (uintptr)nil, (uintptr)nil);
        runtime·atomicstore((uint32*)&g->m->profilehz, hz);
 }
 
index 188ca3219ea1665d801b17801e37c93fb0435728..a1b95943185e1c08a12e3ea585c065d0be3a8beb 100644 (file)
@@ -6,6 +6,17 @@ package runtime
 
 import "unsafe"
 
+type stdFunction *byte
+
+func stdcall0(fn stdFunction) uintptr
+func stdcall1(fn stdFunction, a0 uintptr) uintptr
+func stdcall2(fn stdFunction, a0, a1 uintptr) uintptr
+func stdcall3(fn stdFunction, a0, a1, a2 uintptr) uintptr
+func stdcall4(fn stdFunction, a0, a1, a2, a3 uintptr) uintptr
+func stdcall5(fn stdFunction, a0, a1, a2, a3, a4 uintptr) uintptr
+func stdcall6(fn stdFunction, a0, a1, a2, a3, a4, a5 uintptr) uintptr
+func stdcall7(fn stdFunction, a0, a1, a2, a3, a4, a5, a6 uintptr) uintptr
+
 func asmstdcall(fn unsafe.Pointer)
 func getlasterror() uint32
 func setlasterror(err uint32)
index b64fa88736f0a2451925ab6630865c145e67a74b..e1e3cb0e2361808200760a9ef189ab1e6eefac15 100644 (file)
@@ -8,11 +8,15 @@ extern void *runtime·GetQueuedCompletionStatusEx;
 
 // Call a Windows function with stdcall conventions,
 // and switch to os stack during the call.
-#pragma        varargck        countpos        runtime·stdcall        2
-#pragma        varargck        type            runtime·stdcall        void*
-#pragma        varargck        type            runtime·stdcall        uintptr
 void runtime·asmstdcall(void *c);
-void *runtime·stdcall(void *fn, int32 count, ...);
+void *runtime·stdcall0(void *fn);
+void *runtime·stdcall1(void *fn, uintptr a0);
+void *runtime·stdcall2(void *fn, uintptr a0, uintptr a1);
+void *runtime·stdcall3(void *fn, uintptr a0, uintptr a1, uintptr a2);
+void *runtime·stdcall4(void *fn, uintptr a0, uintptr a1, uintptr a2, uintptr a3);
+void *runtime·stdcall5(void *fn, uintptr a0, uintptr a1, uintptr a2, uintptr a3, uintptr a4);
+void *runtime·stdcall6(void *fn, uintptr a0, uintptr a1, uintptr a2, uintptr a3, uintptr a4, uintptr a5);
+void *runtime·stdcall7(void *fn, uintptr a0, uintptr a1, uintptr a2, uintptr a3, uintptr a4, uintptr a5, uintptr a6);
 
 uint32 runtime·getlasterror(void);
 void runtime·setlasterror(uint32 err);