diff options
author | Alex Brainman <alex.brainman@gmail.com> | 2010-06-11 01:38:12 -0700 |
---|---|---|
committer | Alex Brainman <alex.brainman@gmail.com> | 2010-06-11 01:38:12 -0700 |
commit | 0711ab15504895a329f015807e51b2ca7cd38b47 (patch) | |
tree | 2a6db0c9e8976256e081db200875a1d54fa8d1fa /src | |
parent | 3e249b78c6b1e3caec2532dd15d94db6adefac55 (diff) | |
download | golang-0711ab15504895a329f015807e51b2ca7cd38b47.tar.gz |
runtime: switch to OS stack during Windows syscall
R=rsc
CC=golang-dev
http://codereview.appspot.com/1381041
Committer: Russ Cox <rsc@golang.org>
Diffstat (limited to 'src')
-rw-r--r-- | src/pkg/runtime/windows/386/sys.s | 51 | ||||
-rw-r--r-- | src/pkg/runtime/windows/mem.c | 2 | ||||
-rw-r--r-- | src/pkg/runtime/windows/os.h | 27 | ||||
-rw-r--r-- | src/pkg/runtime/windows/syscall.goc | 74 | ||||
-rw-r--r-- | src/pkg/runtime/windows/thread.c | 65 |
5 files changed, 163 insertions, 56 deletions
diff --git a/src/pkg/runtime/windows/386/sys.s b/src/pkg/runtime/windows/386/sys.s index b032b2d45..e36ef53e0 100644 --- a/src/pkg/runtime/windows/386/sys.s +++ b/src/pkg/runtime/windows/386/sys.s @@ -12,9 +12,10 @@ TEXT get_kernel_module(SB),7,$0 MOVL 0x08(AX), AX // get base of module RET -// TODO(rsc,hectorchu): Switch to m stack before call. -TEXT stdcall(SB),7,$0 - CALL ·entersyscall(SB) +// void *stdcall_raw(void *fn, ...); +// Call fn with stdcall calling convention. +// fn parameters are on stack. +TEXT stdcall_raw(SB),7,$0 get_tls(CX) MOVL m(CX), CX POPL m_return_address(CX) // save return address @@ -26,23 +27,37 @@ TEXT stdcall(SB),7,$0 MOVL m_stack_pointer(CX), SP PUSHL AX PUSHL m_return_address(CX) - CALL ·exitsyscall(SB) - MOVL 4(SP), AX RET -// TODO(rsc,hectorchu): Switch to m stack before call. -TEXT stdcall_raw(SB),7,$0 - get_tls(CX) - MOVL m(CX), CX - POPL m_return_address(CX) // save return address - POPL AX // first arg is function pointer - MOVL SP, m_stack_pointer(CX) // save stack pointer - CALL AX - get_tls(CX) - MOVL m(CX), CX - MOVL m_stack_pointer(CX), SP - PUSHL AX - PUSHL m_return_address(CX) +// void syscall(StdcallParams *p); +// Call p.fn syscall + GetLastError on os stack. +TEXT syscall(SB),7,$16 + MOVL p+0(FP), AX + MOVL SP, CX + + // Figure out if we need to switch to m->g0 stack. + get_tls(DI) + MOVL m(DI), DX + MOVL m_g0(DX), SI + CMPL g(DI), SI + JEQ 2(PC) + MOVL (m_sched+gobuf_sp)(DX), SP + + // Now on a scheduling stack (an os stack). + MOVL g(DI), BP + MOVL BP, 8(SP) + MOVL SI, g(DI) + MOVL CX, 4(SP) + MOVL AX, 0(SP) + CALL call_syscall(SB) + + // Back; switch to original g and stack, re-establish + // "DF is clear" invariant. + CLD + get_tls(DI) + MOVL 8(SP), SI + MOVL SI, g(DI) + MOVL 4(SP), SP RET TEXT threadstart(SB),7,$0 diff --git a/src/pkg/runtime/windows/mem.c b/src/pkg/runtime/windows/mem.c index 09f39998c..982344fa0 100644 --- a/src/pkg/runtime/windows/mem.c +++ b/src/pkg/runtime/windows/mem.c @@ -10,7 +10,7 @@ void* SysAlloc(uintptr n) { - return stdcall_raw(VirtualAlloc, nil, n, 0x3000, 0x40); + return stdcall(VirtualAlloc, 4, nil, n, 0x3000, 0x40); } void diff --git a/src/pkg/runtime/windows/os.h b/src/pkg/runtime/windows/os.h index 98876c888..931f4991c 100644 --- a/src/pkg/runtime/windows/os.h +++ b/src/pkg/runtime/windows/os.h @@ -7,10 +7,6 @@ // The arguments are strings. void *get_proc_addr(void *library, void *name); -// Call a Windows function with stdcall conventions. -void *stdcall(void *fn, ...); -void *stdcall_raw(void *fn, ...); - extern void *VirtualAlloc; extern void *LoadLibraryEx; extern void *GetProcAddress; @@ -21,3 +17,26 @@ void windows_goargs(void); // Get start address of symbol data in memory. void *get_symdat_addr(void); + +// Call a Windows function with stdcall conventions. +void *stdcall_raw(void *fn, ...); + +// Call a Windows function with stdcall conventions, +// and switch to os stack during the call. +void *stdcall(void *fn, int32 count, ...); + +// Call stdcall Windows function StdcallParams.fn +// with params StdcallParams.args, +// followed immediately by GetLastError call. +// Both return values are returned in StdcallParams.r and +// StdcallParams.err. Will use os stack during the call. +typedef struct StdcallParams StdcallParams; +struct StdcallParams +{ + void *fn; + uintptr args[9]; + uintptr r; + uintptr err; +}; +void call_syscall(void *args); +void syscall(StdcallParams *p); diff --git a/src/pkg/runtime/windows/syscall.goc b/src/pkg/runtime/windows/syscall.goc index 6bccc486d..362217e6b 100644 --- a/src/pkg/runtime/windows/syscall.goc +++ b/src/pkg/runtime/windows/syscall.goc @@ -7,39 +7,87 @@ package syscall #include "os.h" func loadlibraryex(filename uintptr) (handle uint32) { - handle = (uint32)stdcall(LoadLibraryEx, filename, 0, 0); + StdcallParams p; + p.fn = (void*)LoadLibraryEx; + p.args[0] = filename; + p.args[1] = 0; + p.args[2] = 0; + ·entersyscall(); + syscall(&p); + ·exitsyscall(); + handle = p.r; } func getprocaddress(handle uint32, procname uintptr) (proc uintptr) { - proc = (uintptr)stdcall(GetProcAddress, handle, procname); + StdcallParams p; + p.fn = (void*)GetProcAddress; + p.args[0] = handle; + p.args[1] = procname; + ·entersyscall(); + syscall(&p); + ·exitsyscall(); + proc = p.r; } func Syscall(trap uintptr, a1 uintptr, a2 uintptr, a3 uintptr) (r1 uintptr, r2 uintptr, err uintptr) { + StdcallParams p; + p.fn = (void*)trap; + p.args[0] = a1; + p.args[1] = a2; + p.args[2] = a3; ·entersyscall(); - r1 = (uintptr)stdcall_raw((void*)trap, a1, a2, a3); - r2 = 0; - err = (uintptr)stdcall_raw(GetLastError); + syscall(&p); ·exitsyscall(); + r1 = p.r; + r2 = 0; + err = p.err; } func Syscall6(trap uintptr, a1 uintptr, a2 uintptr, a3 uintptr, a4 uintptr, a5 uintptr, a6 uintptr) (r1 uintptr, r2 uintptr, err uintptr) { + StdcallParams p; + p.fn = (void*)trap; + p.args[0] = a1; + p.args[1] = a2; + p.args[2] = a3; + p.args[3] = a4; + p.args[4] = a5; + p.args[5] = a6; ·entersyscall(); - r1 = (uintptr)stdcall_raw((void*)trap, a1, a2, a3, a4, a5, a6); - r2 = 0; - err = (uintptr)stdcall_raw(GetLastError); + syscall(&p); ·exitsyscall(); + r1 = p.r; + r2 = 0; + err = p.err; } func Syscall9(trap uintptr, a1 uintptr, a2 uintptr, a3 uintptr, a4 uintptr, a5 uintptr, a6 uintptr, a7 uintptr, a8 uintptr, a9 uintptr) (r1 uintptr, r2 uintptr, lasterr uintptr) { + StdcallParams p; + p.fn = (void*)trap; + p.args[0] = a1; + p.args[1] = a2; + p.args[2] = a3; + p.args[3] = a4; + p.args[4] = a5; + p.args[5] = a6; + p.args[6] = a7; + p.args[7] = a8; + p.args[8] = a9; ·entersyscall(); - r1 = (uintptr)stdcall_raw((void*)trap, a1, a2, a3, a4, a5, a6, a7, a8, a9); - r2 = 0; - lasterr = (uintptr)stdcall_raw(GetLastError); + syscall(&p); ·exitsyscall(); + r1 = p.r; + r2 = 0; + lasterr = p.err; } func RawSyscall(trap uintptr, a1 uintptr, a2 uintptr, a3 uintptr) (r1 uintptr, r2 uintptr, err uintptr) { - r1 = (uintptr)stdcall_raw((void*)trap, a1, a2, a3); + StdcallParams p; + p.fn = (void*)trap; + p.args[0] = a1; + p.args[1] = a2; + p.args[2] = a3; + syscall(&p); + r1 = p.r; r2 = 0; - err = (uintptr)stdcall_raw(GetLastError); + err = p.err; } diff --git a/src/pkg/runtime/windows/thread.c b/src/pkg/runtime/windows/thread.c index 21b679b33..c65f665b1 100644 --- a/src/pkg/runtime/windows/thread.c +++ b/src/pkg/runtime/windows/thread.c @@ -5,8 +5,6 @@ #include "runtime.h" #include "os.h" -#define stdcall stdcall_raw - extern void *get_kernel_module(void); // Also referenced by external packages @@ -75,8 +73,8 @@ get_proc_addr(void *library, void *name) { void *base; - base = stdcall(LoadLibraryEx, library, 0, 0); - return stdcall(GetProcAddress, base, name); + base = stdcall_raw(LoadLibraryEx, library, 0, 0); + return stdcall_raw(GetProcAddress, base, name); } void @@ -96,9 +94,9 @@ windows_goargs(void) clta = get_proc_addr("shell32.dll", "CommandLineToArgvW"); ges = get_proc_addr("kernel32.dll", "GetEnvironmentStringsW"); - cmd = stdcall(gcl); - env = stdcall(ges); - argv = stdcall(clta, cmd, &argc); + cmd = stdcall(gcl, 0); + env = stdcall(ges, 0); + argv = stdcall(clta, 2, cmd, &argc); envc = 0; for(envp=env; *envp; envc++) @@ -126,7 +124,7 @@ windows_goargs(void) void exit(int32 code) { - stdcall(ExitProcess, code); + stdcall(ExitProcess, 1, code); } int32 @@ -138,15 +136,15 @@ write(int32 fd, void *buf, int32 n) written = 0; switch(fd) { case 1: - handle = stdcall(GetStdHandle, -11); + handle = stdcall(GetStdHandle, 1, -11); break; case 2: - handle = stdcall(GetStdHandle, -12); + handle = stdcall(GetStdHandle, 1, -12); break; default: return -1; } - stdcall(WriteFile, handle, buf, n, &written, 0); + stdcall(WriteFile, 5, handle, buf, n, &written, 0); return written; } @@ -157,7 +155,7 @@ get_symdat_addr(void) uint32 peh, add; uint16 oph; - mod = stdcall(GetModuleHandle, 0); + mod = stdcall(GetModuleHandle, 1, 0); peh = *(uint32*)(mod+0x3c); p = mod+peh+4; oph = *(uint16*)(p+0x10); @@ -174,10 +172,10 @@ initevent(void **pevent) { void *event; - event = stdcall(CreateEvent, 0, 0, 0, 0); + event = stdcall(CreateEvent, 4, 0, 0, 0, 0); if(!casp(pevent, 0, event)) { // Someone else filled it in. Use theirs. - stdcall(CloseHandle, event); + stdcall(CloseHandle, 1, event); } } @@ -189,14 +187,14 @@ eventlock(Lock *l) initevent(&l->event); if(xadd(&l->key, 1) > 1) // someone else has it; wait - stdcall(WaitForSingleObject, l->event, -1); + stdcall(WaitForSingleObject, 2, l->event, -1); } static void eventunlock(Lock *l) { if(xadd(&l->key, -1) > 0) // someone else is waiting - stdcall(SetEvent, l->event); + stdcall(SetEvent, 1, l->event); } void @@ -253,10 +251,10 @@ newosproc(M *m, G *g, void *stk, void (*fn)(void)) extern uint32 threadstart(void *p); USED(g, stk, fn); - param.event_handle = stdcall(CreateEvent, 0, 0, 0, 0); - stdcall(CreateThread, 0, 0, threadstart, ¶m, 0, 0); - stdcall(WaitForSingleObject, param.event_handle, -1); - stdcall(CloseHandle, param.event_handle); + param.event_handle = stdcall(CreateEvent, 4, 0, 0, 0, 0); + stdcall(CreateThread, 6, 0, 0, threadstart, ¶m, 0, 0); + stdcall(WaitForSingleObject, 2, param.event_handle, -1); + stdcall(CloseHandle, 1, param.event_handle); } // Called to initialize a new m (including the bootstrap m). @@ -264,3 +262,30 @@ void minit(void) { } + +// Calling stdcall on os stack. +#pragma textflag 7 +void * +stdcall(void *fn, int32 count, ...) +{ + uintptr *a; + StdcallParams p; + + p.fn = fn; + a = (uintptr*)(&count + 1); + while(count > 0) { + count--; + p.args[count] = a[count]; + } + syscall(&p); + return (void*)(p.r); +} + +void +call_syscall(void *args) +{ + StdcallParams *p = (StdcallParams*)args; + p->r = (uintptr)stdcall_raw((void*)p->fn, p->args[0], p->args[1], p->args[2], p->args[3], p->args[4], p->args[5], p->args[6], p->args[7], p->args[8]); + p->err = (uintptr)stdcall_raw(GetLastError); + return; +} |