mirror of
https://github.com/golang/go
synced 2024-11-21 19:24:45 -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
|
MOVL 0x08(AX), AX // get base of module
|
||||||
RET
|
RET
|
||||||
|
|
||||||
// TODO(rsc,hectorchu): Switch to m stack before call.
|
// void *stdcall_raw(void *fn, ...);
|
||||||
TEXT stdcall(SB),7,$0
|
// Call fn with stdcall calling convention.
|
||||||
CALL ·entersyscall(SB)
|
// fn parameters are on stack.
|
||||||
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.
|
|
||||||
TEXT stdcall_raw(SB),7,$0
|
TEXT stdcall_raw(SB),7,$0
|
||||||
get_tls(CX)
|
get_tls(CX)
|
||||||
MOVL m(CX), CX
|
MOVL m(CX), CX
|
||||||
@ -45,6 +29,37 @@ TEXT stdcall_raw(SB),7,$0
|
|||||||
PUSHL m_return_address(CX)
|
PUSHL m_return_address(CX)
|
||||||
RET
|
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
|
TEXT threadstart(SB),7,$0
|
||||||
MOVL 4(SP), AX // threadstart param
|
MOVL 4(SP), AX // threadstart param
|
||||||
MOVL 0(AX), BX // newosproc arg stack
|
MOVL 0(AX), BX // newosproc arg stack
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
void*
|
void*
|
||||||
SysAlloc(uintptr n)
|
SysAlloc(uintptr n)
|
||||||
{
|
{
|
||||||
return stdcall_raw(VirtualAlloc, nil, n, 0x3000, 0x40);
|
return stdcall(VirtualAlloc, 4, nil, n, 0x3000, 0x40);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -7,10 +7,6 @@
|
|||||||
// The arguments are strings.
|
// The arguments are strings.
|
||||||
void *get_proc_addr(void *library, void *name);
|
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 *VirtualAlloc;
|
||||||
extern void *LoadLibraryEx;
|
extern void *LoadLibraryEx;
|
||||||
extern void *GetProcAddress;
|
extern void *GetProcAddress;
|
||||||
@ -21,3 +17,26 @@ void windows_goargs(void);
|
|||||||
|
|
||||||
// Get start address of symbol data in memory.
|
// Get start address of symbol data in memory.
|
||||||
void *get_symdat_addr(void);
|
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"
|
#include "os.h"
|
||||||
|
|
||||||
func loadlibraryex(filename uintptr) (handle uint32) {
|
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) {
|
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) {
|
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();
|
·entersyscall();
|
||||||
r1 = (uintptr)stdcall_raw((void*)trap, a1, a2, a3);
|
syscall(&p);
|
||||||
r2 = 0;
|
|
||||||
err = (uintptr)stdcall_raw(GetLastError);
|
|
||||||
·exitsyscall();
|
·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) {
|
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();
|
·entersyscall();
|
||||||
r1 = (uintptr)stdcall_raw((void*)trap, a1, a2, a3, a4, a5, a6);
|
syscall(&p);
|
||||||
r2 = 0;
|
|
||||||
err = (uintptr)stdcall_raw(GetLastError);
|
|
||||||
·exitsyscall();
|
·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) {
|
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();
|
·entersyscall();
|
||||||
r1 = (uintptr)stdcall_raw((void*)trap, a1, a2, a3, a4, a5, a6, a7, a8, a9);
|
syscall(&p);
|
||||||
r2 = 0;
|
|
||||||
lasterr = (uintptr)stdcall_raw(GetLastError);
|
|
||||||
·exitsyscall();
|
·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) {
|
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;
|
r2 = 0;
|
||||||
err = (uintptr)stdcall_raw(GetLastError);
|
err = p.err;
|
||||||
}
|
}
|
||||||
|
@ -5,8 +5,6 @@
|
|||||||
#include "runtime.h"
|
#include "runtime.h"
|
||||||
#include "os.h"
|
#include "os.h"
|
||||||
|
|
||||||
#define stdcall stdcall_raw
|
|
||||||
|
|
||||||
extern void *get_kernel_module(void);
|
extern void *get_kernel_module(void);
|
||||||
|
|
||||||
// Also referenced by external packages
|
// Also referenced by external packages
|
||||||
@ -75,8 +73,8 @@ get_proc_addr(void *library, void *name)
|
|||||||
{
|
{
|
||||||
void *base;
|
void *base;
|
||||||
|
|
||||||
base = stdcall(LoadLibraryEx, library, 0, 0);
|
base = stdcall_raw(LoadLibraryEx, library, 0, 0);
|
||||||
return stdcall(GetProcAddress, base, name);
|
return stdcall_raw(GetProcAddress, base, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -96,9 +94,9 @@ windows_goargs(void)
|
|||||||
clta = get_proc_addr("shell32.dll", "CommandLineToArgvW");
|
clta = get_proc_addr("shell32.dll", "CommandLineToArgvW");
|
||||||
ges = get_proc_addr("kernel32.dll", "GetEnvironmentStringsW");
|
ges = get_proc_addr("kernel32.dll", "GetEnvironmentStringsW");
|
||||||
|
|
||||||
cmd = stdcall(gcl);
|
cmd = stdcall(gcl, 0);
|
||||||
env = stdcall(ges);
|
env = stdcall(ges, 0);
|
||||||
argv = stdcall(clta, cmd, &argc);
|
argv = stdcall(clta, 2, cmd, &argc);
|
||||||
|
|
||||||
envc = 0;
|
envc = 0;
|
||||||
for(envp=env; *envp; envc++)
|
for(envp=env; *envp; envc++)
|
||||||
@ -126,7 +124,7 @@ windows_goargs(void)
|
|||||||
void
|
void
|
||||||
exit(int32 code)
|
exit(int32 code)
|
||||||
{
|
{
|
||||||
stdcall(ExitProcess, code);
|
stdcall(ExitProcess, 1, code);
|
||||||
}
|
}
|
||||||
|
|
||||||
int32
|
int32
|
||||||
@ -138,15 +136,15 @@ write(int32 fd, void *buf, int32 n)
|
|||||||
written = 0;
|
written = 0;
|
||||||
switch(fd) {
|
switch(fd) {
|
||||||
case 1:
|
case 1:
|
||||||
handle = stdcall(GetStdHandle, -11);
|
handle = stdcall(GetStdHandle, 1, -11);
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
handle = stdcall(GetStdHandle, -12);
|
handle = stdcall(GetStdHandle, 1, -12);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
stdcall(WriteFile, handle, buf, n, &written, 0);
|
stdcall(WriteFile, 5, handle, buf, n, &written, 0);
|
||||||
return written;
|
return written;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -157,7 +155,7 @@ get_symdat_addr(void)
|
|||||||
uint32 peh, add;
|
uint32 peh, add;
|
||||||
uint16 oph;
|
uint16 oph;
|
||||||
|
|
||||||
mod = stdcall(GetModuleHandle, 0);
|
mod = stdcall(GetModuleHandle, 1, 0);
|
||||||
peh = *(uint32*)(mod+0x3c);
|
peh = *(uint32*)(mod+0x3c);
|
||||||
p = mod+peh+4;
|
p = mod+peh+4;
|
||||||
oph = *(uint16*)(p+0x10);
|
oph = *(uint16*)(p+0x10);
|
||||||
@ -174,10 +172,10 @@ initevent(void **pevent)
|
|||||||
{
|
{
|
||||||
void *event;
|
void *event;
|
||||||
|
|
||||||
event = stdcall(CreateEvent, 0, 0, 0, 0);
|
event = stdcall(CreateEvent, 4, 0, 0, 0, 0);
|
||||||
if(!casp(pevent, 0, event)) {
|
if(!casp(pevent, 0, event)) {
|
||||||
// Someone else filled it in. Use theirs.
|
// Someone else filled it in. Use theirs.
|
||||||
stdcall(CloseHandle, event);
|
stdcall(CloseHandle, 1, event);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -189,14 +187,14 @@ eventlock(Lock *l)
|
|||||||
initevent(&l->event);
|
initevent(&l->event);
|
||||||
|
|
||||||
if(xadd(&l->key, 1) > 1) // someone else has it; wait
|
if(xadd(&l->key, 1) > 1) // someone else has it; wait
|
||||||
stdcall(WaitForSingleObject, l->event, -1);
|
stdcall(WaitForSingleObject, 2, l->event, -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
eventunlock(Lock *l)
|
eventunlock(Lock *l)
|
||||||
{
|
{
|
||||||
if(xadd(&l->key, -1) > 0) // someone else is waiting
|
if(xadd(&l->key, -1) > 0) // someone else is waiting
|
||||||
stdcall(SetEvent, l->event);
|
stdcall(SetEvent, 1, l->event);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -253,10 +251,10 @@ newosproc(M *m, G *g, void *stk, void (*fn)(void))
|
|||||||
extern uint32 threadstart(void *p);
|
extern uint32 threadstart(void *p);
|
||||||
|
|
||||||
USED(g, stk, fn);
|
USED(g, stk, fn);
|
||||||
param.event_handle = stdcall(CreateEvent, 0, 0, 0, 0);
|
param.event_handle = stdcall(CreateEvent, 4, 0, 0, 0, 0);
|
||||||
stdcall(CreateThread, 0, 0, threadstart, ¶m, 0, 0);
|
stdcall(CreateThread, 6, 0, 0, threadstart, ¶m, 0, 0);
|
||||||
stdcall(WaitForSingleObject, param.event_handle, -1);
|
stdcall(WaitForSingleObject, 2, param.event_handle, -1);
|
||||||
stdcall(CloseHandle, param.event_handle);
|
stdcall(CloseHandle, 1, param.event_handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Called to initialize a new m (including the bootstrap m).
|
// Called to initialize a new m (including the bootstrap m).
|
||||||
@ -264,3 +262,30 @@ void
|
|||||||
minit(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