]> Cypherpunks repositories - gostls13.git/commitdiff
runtime: switch to OS stack during Windows syscall
authorAlex Brainman <alex.brainman@gmail.com>
Fri, 11 Jun 2010 08:38:12 +0000 (01:38 -0700)
committerRuss Cox <rsc@golang.org>
Fri, 11 Jun 2010 08:38:12 +0000 (01:38 -0700)
R=rsc
CC=golang-dev
https://golang.org/cl/1381041

src/pkg/runtime/windows/386/sys.s
src/pkg/runtime/windows/mem.c
src/pkg/runtime/windows/os.h
src/pkg/runtime/windows/syscall.goc
src/pkg/runtime/windows/thread.c

index b032b2d45a28661de1e26327a1b839a1b016b4f5..e36ef53e0a8e29ecc354b5d987acc9c9a851dc77 100644 (file)
@@ -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
index 09f39998c62612d2d5dec0ea686ce3acead0d193..982344fa0577feaa51fb1642e2f19af694f8cd69 100644 (file)
@@ -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
index 98876c888e04d553f6e9f4b1ae6d0b2cfaa81217..931f4991c24e61f79757d47f82218a08d8399d95 100644 (file)
@@ -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);
index 6bccc486dc431d097b82a2baadc20da45f6a884d..362217e6bcc4af411e9668f9c257c933d996934e 100644 (file)
@@ -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;
 }
index 21b679b3312cf2ca9d46738d78aea38cb16eef52..c65f665b1b16f3860e05dab3d664dafe2d945784 100644 (file)
@@ -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;
+}