aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlex Brainman <alex.brainman@gmail.com>2010-06-11 01:38:12 -0700
committerRuss Cox <rsc@golang.org>2010-06-11 01:38:12 -0700
commitc1e20720f7b3c53cd195c4996b1758e44be6787c (patch)
tree77d83d9599059b7efb2d5214580bdeb0eda91fa4
parentfdb460ec11500881ecfd57abd93a9c1e409898b7 (diff)
downloadgo-c1e20720f7b3c53cd195c4996b1758e44be6787c.tar.gz
go-c1e20720f7b3c53cd195c4996b1758e44be6787c.zip
runtime: switch to OS stack during Windows syscall
R=rsc CC=golang-dev https://golang.org/cl/1381041
-rw-r--r--src/pkg/runtime/windows/386/sys.s51
-rw-r--r--src/pkg/runtime/windows/mem.c2
-rw-r--r--src/pkg/runtime/windows/os.h27
-rw-r--r--src/pkg/runtime/windows/syscall.goc74
-rw-r--r--src/pkg/runtime/windows/thread.c65
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 b032b2d45a..e36ef53e0a 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 09f39998c6..982344fa05 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 98876c888e..931f4991c2 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 6bccc486dc..362217e6bc 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 21b679b331..c65f665b1b 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, &param, 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, &param, 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;
+}