summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDmitriy Vyukov <dvyukov@google.com>2014-08-29 12:44:07 +0400
committerDmitriy Vyukov <dvyukov@google.com>2014-08-29 12:44:07 +0400
commit16fb7800cf2a096c2e5b282fb947e9555dfdede3 (patch)
tree80fef53e0e8fa547ae8ce43b223ad36ffe3a6339
parenta871339e1e8483a97a09bb6e360f41e1aca902a5 (diff)
downloadgo-16fb7800cf2a096c2e5b282fb947e9555dfdede3.tar.gz
runtime: allow to call stdcall from Go on windows
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://codereview.appspot.com/135090043
-rw-r--r--src/pkg/runtime/mem_windows.c16
-rw-r--r--src/pkg/runtime/netpoll_windows.c10
-rw-r--r--src/pkg/runtime/os_windows.c160
-rw-r--r--src/pkg/runtime/os_windows.go11
-rw-r--r--src/pkg/runtime/os_windows.h12
5 files changed, 149 insertions, 60 deletions
diff --git a/src/pkg/runtime/mem_windows.c b/src/pkg/runtime/mem_windows.c
index 77ec6e926..5eb43b2a9 100644
--- a/src/pkg/runtime/mem_windows.c
+++ b/src/pkg/runtime/mem_windows.c
@@ -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");
}
diff --git a/src/pkg/runtime/netpoll_windows.c b/src/pkg/runtime/netpoll_windows.c
index 452829212..64da41ad9 100644
--- a/src/pkg/runtime/netpoll_windows.c
+++ b/src/pkg/runtime/netpoll_windows.c
@@ -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)
diff --git a/src/pkg/runtime/os_windows.c b/src/pkg/runtime/os_windows.c
index aadc30a07..43026d645 100644
--- a/src/pkg/runtime/os_windows.c
+++ b/src/pkg/runtime/os_windows.c
@@ -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);
}
diff --git a/src/pkg/runtime/os_windows.go b/src/pkg/runtime/os_windows.go
index 188ca3219..a1b959431 100644
--- a/src/pkg/runtime/os_windows.go
+++ b/src/pkg/runtime/os_windows.go
@@ -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)
diff --git a/src/pkg/runtime/os_windows.h b/src/pkg/runtime/os_windows.h
index b64fa8873..e1e3cb0e2 100644
--- a/src/pkg/runtime/os_windows.h
+++ b/src/pkg/runtime/os_windows.h
@@ -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);