mirror of
https://github.com/golang/go
synced 2024-11-21 14:14:40 -07:00
runtime: switch to OS stack during Windows syscall
R=rsc CC=golang-dev https://golang.org/cl/1381041
This commit is contained in:
parent
fdb460ec11
commit
c1e20720f7
@ -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
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user