1
0
mirror of https://github.com/golang/go synced 2024-09-25 01:20:13 -06:00

runtime: switch to OS stack during Windows syscall

R=rsc
CC=golang-dev
https://golang.org/cl/1381041
This commit is contained in:
Alex Brainman 2010-06-11 01:38:12 -07:00 committed by Russ Cox
parent fdb460ec11
commit c1e20720f7
5 changed files with 164 additions and 57 deletions

View File

@ -12,25 +12,9 @@ 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)
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)
CALL ·exitsyscall(SB)
MOVL 4(SP), AX
RET
// TODO(rsc,hectorchu): Switch to m stack before call.
// 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
@ -45,6 +29,37 @@ TEXT stdcall_raw(SB),7,$0
PUSHL m_return_address(CX)
RET
// 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
MOVL 4(SP), AX // threadstart param
MOVL 0(AX), BX // newosproc arg stack

View 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

View 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);

View 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;
}

View 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;
}