mirror of
https://github.com/golang/go
synced 2024-11-24 20:00:10 -07:00
Ported runtime to Windows.
R=rsc CC=golang-dev https://golang.org/cl/176066
This commit is contained in:
parent
5c07e0c17c
commit
6bfe5f55f4
@ -26,17 +26,19 @@ TEXT _rt0_386(SB),7,$0
|
||||
CALL ldt0setup(SB)
|
||||
|
||||
// store through it, to make sure it works
|
||||
MOVL $0x123, 0(GS)
|
||||
get_tls(BX)
|
||||
MOVL $0x123, g(BX)
|
||||
MOVL tls0(SB), AX
|
||||
CMPL AX, $0x123
|
||||
JEQ ok
|
||||
MOVL AX, 0 // abort
|
||||
ok:
|
||||
// set up m and g "registers"
|
||||
get_tls(BX)
|
||||
LEAL g0(SB), CX
|
||||
MOVL CX, g
|
||||
MOVL CX, g(BX)
|
||||
LEAL m0(SB), AX
|
||||
MOVL AX, m
|
||||
MOVL AX, m(BX)
|
||||
|
||||
// save m->g0 = g0
|
||||
MOVL CX, m_g0(AX)
|
||||
@ -100,7 +102,8 @@ TEXT gosave(SB), 7, $0
|
||||
MOVL BX, gobuf_sp(AX)
|
||||
MOVL 0(SP), BX // caller's PC
|
||||
MOVL BX, gobuf_pc(AX)
|
||||
MOVL g, BX
|
||||
get_tls(CX)
|
||||
MOVL g(CX), BX
|
||||
MOVL BX, gobuf_g(AX)
|
||||
MOVL $0, AX // return 0
|
||||
RET
|
||||
@ -112,7 +115,8 @@ TEXT gogo(SB), 7, $0
|
||||
MOVL 4(SP), BX // gobuf
|
||||
MOVL gobuf_g(BX), DX
|
||||
MOVL 0(DX), CX // make sure g != nil
|
||||
MOVL DX, g
|
||||
get_tls(CX)
|
||||
MOVL DX, g(CX)
|
||||
MOVL gobuf_sp(BX), SP // restore SP
|
||||
MOVL gobuf_pc(BX), BX
|
||||
JMP BX
|
||||
@ -124,7 +128,8 @@ TEXT gogocall(SB), 7, $0
|
||||
MOVL 8(SP), AX // fn
|
||||
MOVL 4(SP), BX // gobuf
|
||||
MOVL gobuf_g(BX), DX
|
||||
MOVL DX, g
|
||||
get_tls(CX)
|
||||
MOVL DX, g(CX)
|
||||
MOVL 0(DX), CX // make sure g != nil
|
||||
MOVL gobuf_sp(BX), SP // restore SP
|
||||
MOVL gobuf_pc(BX), BX
|
||||
@ -139,9 +144,10 @@ TEXT gogocall(SB), 7, $0
|
||||
// Called during function prolog when more stack is needed.
|
||||
TEXT runtime·morestack(SB),7,$0
|
||||
// Cannot grow scheduler stack (m->g0).
|
||||
MOVL m, BX
|
||||
get_tls(CX)
|
||||
MOVL m(CX), BX
|
||||
MOVL m_g0(BX), SI
|
||||
CMPL g, SI
|
||||
CMPL g(CX), SI
|
||||
JNE 2(PC)
|
||||
INT $3
|
||||
|
||||
@ -158,7 +164,8 @@ TEXT runtime·morestack(SB),7,$0
|
||||
LEAL 8(SP), CX // f's caller's SP
|
||||
MOVL CX, (m_morebuf+gobuf_sp)(BX)
|
||||
MOVL CX, (m_morefp)(BX)
|
||||
MOVL g, SI
|
||||
get_tls(CX)
|
||||
MOVL g(CX), SI
|
||||
MOVL SI, (m_morebuf+gobuf_g)(BX)
|
||||
|
||||
// Set m->morepc to f's PC.
|
||||
@ -167,7 +174,7 @@ TEXT runtime·morestack(SB),7,$0
|
||||
|
||||
// Call newstack on m's scheduling stack.
|
||||
MOVL m_g0(BX), BP
|
||||
MOVL BP, g
|
||||
MOVL BP, g(CX)
|
||||
MOVL (m_sched+gobuf_sp)(BX), SP
|
||||
CALL newstack(SB)
|
||||
MOVL $0, 0x1003 // crash if newstack returns
|
||||
@ -179,7 +186,8 @@ TEXT runtime·morestack(SB),7,$0
|
||||
//
|
||||
// func call(fn *byte, arg *byte, argsize uint32).
|
||||
TEXT reflect·call(SB), 7, $0
|
||||
MOVL m, BX
|
||||
get_tls(CX)
|
||||
MOVL m(CX), BX
|
||||
|
||||
// Save our caller's state as the PC and SP to
|
||||
// restore when returning from f.
|
||||
@ -187,7 +195,7 @@ TEXT reflect·call(SB), 7, $0
|
||||
MOVL AX, (m_morebuf+gobuf_pc)(BX)
|
||||
LEAL 4(SP), AX // our caller's SP
|
||||
MOVL AX, (m_morebuf+gobuf_sp)(BX)
|
||||
MOVL g, AX
|
||||
MOVL g(CX), AX
|
||||
MOVL AX, (m_morebuf+gobuf_g)(BX)
|
||||
|
||||
// Set up morestack arguments to call f on a new stack.
|
||||
@ -207,7 +215,8 @@ TEXT reflect·call(SB), 7, $0
|
||||
|
||||
// Call newstack on m's scheduling stack.
|
||||
MOVL m_g0(BX), BP
|
||||
MOVL BP, g
|
||||
get_tls(CX)
|
||||
MOVL BP, g(CX)
|
||||
MOVL (m_sched+gobuf_sp)(BX), SP
|
||||
CALL newstack(SB)
|
||||
MOVL $0, 0x1103 // crash if newstack returns
|
||||
@ -217,12 +226,13 @@ TEXT reflect·call(SB), 7, $0
|
||||
// Return point when leaving stack.
|
||||
TEXT runtime·lessstack(SB), 7, $0
|
||||
// Save return value in m->cret
|
||||
MOVL m, BX
|
||||
get_tls(CX)
|
||||
MOVL m(CX), BX
|
||||
MOVL AX, m_cret(BX)
|
||||
|
||||
// Call oldstack on m's scheduling stack.
|
||||
MOVL m_g0(BX), DX
|
||||
MOVL DX, g
|
||||
MOVL DX, g(CX)
|
||||
MOVL (m_sched+gobuf_sp)(BX), SP
|
||||
CALL oldstack(SB)
|
||||
MOVL $0, 0x1004 // crash if oldstack returns
|
||||
@ -248,6 +258,25 @@ TEXT cas(SB), 7, $0
|
||||
MOVL $1, AX
|
||||
RET
|
||||
|
||||
// bool casp(void **p, void *old, void *new)
|
||||
// Atomically:
|
||||
// if(*p == old){
|
||||
// *p = new;
|
||||
// return 1;
|
||||
// }else
|
||||
// return 0;
|
||||
TEXT casp(SB), 7, $0
|
||||
MOVL 4(SP), BX
|
||||
MOVL 8(SP), AX
|
||||
MOVL 12(SP), CX
|
||||
LOCK
|
||||
CMPXCHGL CX, 0(BX)
|
||||
JZ 3(PC)
|
||||
MOVL $0, AX
|
||||
RET
|
||||
MOVL $1, AX
|
||||
RET
|
||||
|
||||
// void jmpdefer(fn, sp);
|
||||
// called from deferreturn.
|
||||
// 1. pop the caller
|
||||
@ -308,9 +337,10 @@ TEXT runcgo(SB),7,$16
|
||||
MOVL SP, CX
|
||||
|
||||
// Figure out if we need to switch to m->g0 stack.
|
||||
MOVL m, DX
|
||||
get_tls(DI)
|
||||
MOVL m(DI), DX
|
||||
MOVL m_g0(DX), SI
|
||||
CMPL g, SI
|
||||
CMPL g(DI), SI
|
||||
JEQ 2(PC)
|
||||
MOVL (m_sched+gobuf_sp)(DX), SP
|
||||
|
||||
@ -325,7 +355,8 @@ TEXT runcgo(SB),7,$16
|
||||
|
||||
// check that SP is in range [g->stackbase, g->stackguard)
|
||||
TEXT stackcheck(SB), 7, $0
|
||||
MOVL g, AX
|
||||
get_tls(CX)
|
||||
MOVL g(CX), AX
|
||||
CMPL g_stackbase(AX), SP
|
||||
JHI 2(PC)
|
||||
INT $3
|
||||
|
@ -17,7 +17,8 @@ CFLAGS_64=-D_64BIT
|
||||
# TODO(kaib): fix register allocation to honor extern register so we
|
||||
# can enable optimizations again.
|
||||
CFLAGS_arm=-N
|
||||
CFLAGS=-I$(GOOS) -I$(GOOS)/$(GOARCH) -wF $(CFLAGS_$(SIZE)) $(CFLAGS_$(GOARCH))
|
||||
CFLAGS_mingw=-D__MINGW__
|
||||
CFLAGS=-I$(GOOS) -I$(GOOS)/$(GOARCH) -wF $(CFLAGS_$(SIZE)) $(CFLAGS_$(GOARCH)) $(CFLAGS_$(GOOS))
|
||||
|
||||
GOFILES=\
|
||||
extern.go\
|
||||
@ -118,4 +119,4 @@ cgo2c: cgo2c.c
|
||||
|
||||
# for discovering offsets inside structs when debugging
|
||||
runtime.acid.$(GOARCH): runtime.h proc.c
|
||||
$(QUOTED_GOBIN)/$(CC) -a proc.c >$@
|
||||
$(QUOTED_GOBIN)/$(CC) $(CFLAGS) -a proc.c >$@
|
||||
|
@ -64,9 +64,10 @@ TEXT sigtramp(SB),7,$40
|
||||
MOVW BX, GS
|
||||
|
||||
// g = m->gsignal
|
||||
MOVL m, BP
|
||||
get_tls(CX)
|
||||
MOVL m(CX), BP
|
||||
MOVL m_gsignal(BP), BP
|
||||
MOVL BP, g
|
||||
MOVL BP, g(CX)
|
||||
|
||||
MOVL handler+0(FP), DI
|
||||
// 4(FP) is sigstyle
|
||||
@ -80,9 +81,10 @@ TEXT sigtramp(SB),7,$40
|
||||
CALL DI
|
||||
|
||||
// g = m->curg
|
||||
MOVL m, BP
|
||||
get_tls(CX)
|
||||
MOVL m(CX), BP
|
||||
MOVL m_curg(BP), BP
|
||||
MOVL BP, g
|
||||
MOVL BP, g(CX)
|
||||
|
||||
MOVL context+16(FP), CX
|
||||
MOVL style+4(FP), BX
|
||||
@ -150,8 +152,9 @@ TEXT bsdthread_start(SB),7,$0
|
||||
POPAL
|
||||
|
||||
// Now segment is established. Initialize m, g.
|
||||
MOVL AX, g
|
||||
MOVL DX, m
|
||||
get_tls(BP)
|
||||
MOVL AX, g(BP)
|
||||
MOVL DX, m(BP)
|
||||
MOVL BX, m_procid(DX) // m->procid = thread port (for debuggers)
|
||||
CALL stackcheck(SB) // smashes AX
|
||||
CALL CX // fn()
|
||||
|
@ -36,21 +36,6 @@ initsema(uint32 *psema)
|
||||
}
|
||||
|
||||
|
||||
// Atomic add and return new value.
|
||||
static uint32
|
||||
xadd(uint32 volatile *val, int32 delta)
|
||||
{
|
||||
uint32 oval, nval;
|
||||
|
||||
for(;;){
|
||||
oval = *val;
|
||||
nval = oval + delta;
|
||||
if(cas(val, oval, nval))
|
||||
return nval;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Blocking locks.
|
||||
|
||||
// Implement Locks, using semaphores.
|
||||
|
@ -33,8 +33,10 @@ TEXT thr_start(SB),7,$0
|
||||
POPL AX
|
||||
POPL AX
|
||||
POPAL
|
||||
MOVL BX, g
|
||||
MOVL AX, m
|
||||
get_tls(CX)
|
||||
MOVL BX, g(CX)
|
||||
|
||||
MOVL AX, m(CX)
|
||||
CALL stackcheck(SB) // smashes AX
|
||||
CALL mstart(SB)
|
||||
MOVL 0, AX // crash (not reached)
|
||||
@ -80,9 +82,10 @@ TEXT sigaction(SB),7,$-4
|
||||
|
||||
TEXT sigtramp(SB),7,$40
|
||||
// g = m->gsignal
|
||||
MOVL m, BP
|
||||
get_tls(DX)
|
||||
MOVL m(DX), BP
|
||||
MOVL m_gsignal(BP), BP
|
||||
MOVL BP, g
|
||||
MOVL BP, g(DX)
|
||||
|
||||
MOVL signo+0(FP), AX
|
||||
MOVL siginfo+4(FP), BX
|
||||
@ -94,9 +97,10 @@ TEXT sigtramp(SB),7,$40
|
||||
CALL sighandler(SB)
|
||||
|
||||
// g = m->curg
|
||||
MOVL m, BP
|
||||
get_tls(DX)
|
||||
MOVL m(DX), BP
|
||||
MOVL m_curg(BP), BP
|
||||
MOVL BP, g
|
||||
MOVL BP, g(DX)
|
||||
|
||||
MOVL context+8(FP), AX
|
||||
|
||||
|
@ -40,9 +40,10 @@ TEXT rt_sigaction(SB),7,$0
|
||||
RET
|
||||
|
||||
TEXT sigtramp(SB),7,$0
|
||||
MOVL m, BP
|
||||
get_tls(CX)
|
||||
MOVL m(CX), BP
|
||||
MOVL m_gsignal(BP), AX
|
||||
MOVL AX, g
|
||||
MOVL AX, g(CX)
|
||||
JMP sighandler(SB)
|
||||
|
||||
TEXT sigignore(SB),7,$0
|
||||
@ -50,9 +51,10 @@ TEXT sigignore(SB),7,$0
|
||||
|
||||
TEXT sigreturn(SB),7,$0
|
||||
// g = m->curg
|
||||
MOVL m, BP
|
||||
get_tls(CX)
|
||||
MOVL m(CX), BP
|
||||
MOVL m_curg(BP), BP
|
||||
MOVL BP, g
|
||||
MOVL BP, g(CX)
|
||||
MOVL $173, AX // rt_sigreturn
|
||||
INT $0x80
|
||||
INT $3 // not reached
|
||||
@ -149,8 +151,9 @@ TEXT clone(SB),7,$0
|
||||
MOVW DI, GS
|
||||
|
||||
// Now segment is established. Initialize m, g.
|
||||
MOVL DX, g
|
||||
MOVL BX, m
|
||||
get_tls(AX)
|
||||
MOVL DX, g(AX)
|
||||
MOVL BX, m(AX)
|
||||
|
||||
CALL stackcheck(SB) // smashes AX
|
||||
MOVL 0(DX), DX // paranoia; check they are not nil
|
||||
|
@ -73,8 +73,12 @@ scanstack(G *gp)
|
||||
{
|
||||
Stktop *stk;
|
||||
byte *sp;
|
||||
// TODO(rsc): Change 8g not to assume that extern register
|
||||
// variables are directly addressable. Declaring the
|
||||
// local variable here works around the bug.
|
||||
G* gg = g;
|
||||
|
||||
if(gp == g)
|
||||
if(gp == gg)
|
||||
sp = (byte*)&gp;
|
||||
else
|
||||
sp = gp->sched.sp;
|
||||
@ -89,7 +93,11 @@ scanstack(G *gp)
|
||||
static void
|
||||
mark(void)
|
||||
{
|
||||
G *gp;
|
||||
G* gp;
|
||||
// TODO(rsc): Change 8g not to assume that extern register
|
||||
// variables are directly addressable. Declaring the
|
||||
// local variable here works around the bug.
|
||||
G* gg = g;
|
||||
|
||||
// mark data+bss.
|
||||
// skip mheap itself, which has no interesting pointers
|
||||
@ -106,7 +114,7 @@ mark(void)
|
||||
case Gdead:
|
||||
break;
|
||||
case Grunning:
|
||||
if(gp != g)
|
||||
if(gp != gg)
|
||||
throw("mark - world not stopped");
|
||||
scanstack(gp);
|
||||
break;
|
||||
|
17
src/pkg/runtime/mingw/386/defs.h
Normal file
17
src/pkg/runtime/mingw/386/defs.h
Normal file
@ -0,0 +1,17 @@
|
||||
// c:\Users\Hector\Code\go\bin\godefs.exe defs.c
|
||||
|
||||
// MACHINE GENERATED - DO NOT EDIT.
|
||||
|
||||
// Constants
|
||||
enum {
|
||||
PROT_NONE = 0,
|
||||
PROT_READ = 0x1,
|
||||
PROT_WRITE = 0x2,
|
||||
PROT_EXEC = 0x4,
|
||||
MAP_ANON = 0x1,
|
||||
MAP_PRIVATE = 0x2,
|
||||
};
|
||||
|
||||
// Types
|
||||
#pragma pack on
|
||||
#pragma pack off
|
6
src/pkg/runtime/mingw/386/rt0.s
Normal file
6
src/pkg/runtime/mingw/386/rt0.s
Normal file
@ -0,0 +1,6 @@
|
||||
// Copyright 2009 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
TEXT _rt0_386_mingw(SB),7,$0
|
||||
JMP _rt0_386(SB)
|
8
src/pkg/runtime/mingw/386/signal.c
Normal file
8
src/pkg/runtime/mingw/386/signal.c
Normal file
@ -0,0 +1,8 @@
|
||||
// Copyright 2009 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
void
|
||||
initsig(void)
|
||||
{
|
||||
}
|
87
src/pkg/runtime/mingw/386/sys.s
Normal file
87
src/pkg/runtime/mingw/386/sys.s
Normal file
@ -0,0 +1,87 @@
|
||||
// Copyright 2009 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
#include "386/asm.h"
|
||||
|
||||
TEXT get_kernel_module(SB),7,$0
|
||||
MOVL 0x30(FS), AX // get PEB
|
||||
MOVL 0x0c(AX), AX // get PEB_LDR_DATA
|
||||
MOVL 0x1c(AX), AX // get init order module list
|
||||
MOVL (AX), AX // get next entry (kernel module)
|
||||
MOVL 0x08(AX), AX // get base of module
|
||||
RET
|
||||
|
||||
// TODO(rsc,hectorchu): Switch to m stack before call.
|
||||
TEXT stdcall(SB),7,$0
|
||||
CALL runtime·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 runtime·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)
|
||||
RET
|
||||
|
||||
TEXT threadstart(SB),7,$0
|
||||
MOVL 4(SP), AX // threadstart param
|
||||
MOVL 0(AX), BX // newosproc arg stack
|
||||
MOVL 0(BX), CX // m
|
||||
MOVL 4(BX), DX // g
|
||||
|
||||
// set up tls
|
||||
LEAL m_tls(CX), SI
|
||||
MOVL SI, 0x2c(FS)
|
||||
MOVL CX, m(SI)
|
||||
MOVL DX, g(SI)
|
||||
MOVL SP, m_os_stack_pointer(CX)
|
||||
|
||||
PUSHL 8(BX) // stk
|
||||
PUSHL 12(BX) // fn
|
||||
PUSHL 4(AX) // event_handle
|
||||
|
||||
// signal that we're done with thread args
|
||||
MOVL SetEvent(SB), BX
|
||||
CALL BX // SetEvent(event_handle)
|
||||
POPL BX // fn
|
||||
POPL SP // stk
|
||||
|
||||
CALL stackcheck(SB) // clobbers AX,CX
|
||||
CALL BX // fn()
|
||||
|
||||
// cleanup stack before returning as we are stdcall
|
||||
get_tls(CX)
|
||||
MOVL m(CX), CX
|
||||
MOVL m_os_stack_pointer(CX), SP
|
||||
POPL AX // return address
|
||||
MOVL AX, (SP)
|
||||
XORL AX, AX
|
||||
RET
|
||||
|
||||
// setldt(int entry, int address, int limit)
|
||||
TEXT setldt(SB),7,$0
|
||||
MOVL address+4(FP), CX
|
||||
MOVL CX, 0x2c(FS)
|
||||
RET
|
13
src/pkg/runtime/mingw/defs.c
Normal file
13
src/pkg/runtime/mingw/defs.c
Normal file
@ -0,0 +1,13 @@
|
||||
// Copyright 2009 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
enum {
|
||||
$PROT_NONE = 0,
|
||||
$PROT_READ = 1,
|
||||
$PROT_WRITE = 2,
|
||||
$PROT_EXEC = 4,
|
||||
|
||||
$MAP_ANON = 1,
|
||||
$MAP_PRIVATE = 2,
|
||||
};
|
18
src/pkg/runtime/mingw/os.h
Normal file
18
src/pkg/runtime/mingw/os.h
Normal file
@ -0,0 +1,18 @@
|
||||
// Copyright 2009 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// The following function allows one to dynamically
|
||||
// resolve DLL function names.
|
||||
// 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, ...);
|
||||
|
||||
#define goargs mingw_goargs
|
||||
void mingw_goargs(void);
|
||||
|
||||
// Get start address of symbol data in memory.
|
||||
void *get_symdat_addr(void);
|
265
src/pkg/runtime/mingw/thread.c
Normal file
265
src/pkg/runtime/mingw/thread.c
Normal file
@ -0,0 +1,265 @@
|
||||
// Copyright 2009 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
#include "runtime.h"
|
||||
#include "os.h"
|
||||
|
||||
#define stdcall stdcall_raw
|
||||
|
||||
extern void *get_kernel_module(void);
|
||||
|
||||
// Also referenced by external packages
|
||||
void *CloseHandle;
|
||||
void *ExitProcess;
|
||||
void *GetStdHandle;
|
||||
void *SetEvent;
|
||||
void *WriteFile;
|
||||
|
||||
static void *CreateEvent;
|
||||
static void *CreateThread;
|
||||
static void *GetModuleHandle;
|
||||
static void *GetProcAddress;
|
||||
static void *LoadLibraryEx;
|
||||
static void *VirtualAlloc;
|
||||
static void *WaitForSingleObject;
|
||||
|
||||
static void*
|
||||
get_proc_addr2(byte *base, byte *name)
|
||||
{
|
||||
byte *pe_header, *exports;
|
||||
uint32 entries, *addr, *names, i;
|
||||
uint16 *ordinals;
|
||||
|
||||
pe_header = base+*(uint32*)(base+0x3c);
|
||||
exports = base+*(uint32*)(pe_header+0x78);
|
||||
entries = *(uint32*)(exports+0x18);
|
||||
addr = (uint32*)(base+*(uint32*)(exports+0x1c));
|
||||
names = (uint32*)(base+*(uint32*)(exports+0x20));
|
||||
ordinals = (uint16*)(base+*(uint32*)(exports+0x24));
|
||||
for(i=0; i<entries; i++) {
|
||||
byte *s = base+names[i];
|
||||
if(!strcmp(name, s))
|
||||
break;
|
||||
}
|
||||
if(i == entries)
|
||||
return 0;
|
||||
return base+addr[ordinals[i]];
|
||||
}
|
||||
|
||||
void
|
||||
osinit(void)
|
||||
{
|
||||
void *base;
|
||||
|
||||
base = get_kernel_module();
|
||||
GetProcAddress = get_proc_addr2(base, (byte*)"GetProcAddress");
|
||||
LoadLibraryEx = get_proc_addr2(base, (byte*)"LoadLibraryExA");
|
||||
CloseHandle = get_proc_addr("kernel32.dll", "CloseHandle");
|
||||
CreateEvent = get_proc_addr("kernel32.dll", "CreateEventA");
|
||||
CreateThread = get_proc_addr("kernel32.dll", "CreateThread");
|
||||
ExitProcess = get_proc_addr("kernel32.dll", "ExitProcess");
|
||||
GetModuleHandle = get_proc_addr("kernel32.dll", "GetModuleHandleA");
|
||||
GetStdHandle = get_proc_addr("kernel32.dll", "GetStdHandle");
|
||||
SetEvent = get_proc_addr("kernel32.dll", "SetEvent");
|
||||
VirtualAlloc = get_proc_addr("kernel32.dll", "VirtualAlloc");
|
||||
WaitForSingleObject = get_proc_addr("kernel32.dll", "WaitForSingleObject");
|
||||
WriteFile = get_proc_addr("kernel32.dll", "WriteFile");
|
||||
}
|
||||
|
||||
// The arguments are strings.
|
||||
void*
|
||||
get_proc_addr(void *library, void *name)
|
||||
{
|
||||
void *base;
|
||||
|
||||
base = stdcall(LoadLibraryEx, library, 0, 0);
|
||||
return stdcall(GetProcAddress, base, name);
|
||||
}
|
||||
|
||||
void
|
||||
mingw_goargs(void)
|
||||
{
|
||||
extern Slice os·Args;
|
||||
extern Slice os·Envs;
|
||||
|
||||
void *gcl, *clta, *ges;
|
||||
uint16 *cmd, *env, **argv;
|
||||
String *gargv;
|
||||
String *genvv;
|
||||
int32 i, argc, envc;
|
||||
uint16 *envp;
|
||||
|
||||
gcl = get_proc_addr("kernel32.dll", "GetCommandLineW");
|
||||
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);
|
||||
|
||||
envc = 0;
|
||||
for(envp=env; *envp; envc++)
|
||||
envp += findnullw(envp)+1;
|
||||
|
||||
gargv = malloc(argc*sizeof gargv[0]);
|
||||
genvv = malloc(envc*sizeof genvv[0]);
|
||||
|
||||
for(i=0; i<argc; i++)
|
||||
gargv[i] = gostringw(argv[i]);
|
||||
os·Args.array = (byte*)gargv;
|
||||
os·Args.len = argc;
|
||||
os·Args.cap = argc;
|
||||
|
||||
envp = env;
|
||||
for(i=0; i<envc; i++) {
|
||||
genvv[i] = gostringw(envp);
|
||||
envp += findnullw(envp)+1;
|
||||
}
|
||||
os·Envs.array = (byte*)genvv;
|
||||
os·Envs.len = envc;
|
||||
os·Envs.cap = envc;
|
||||
}
|
||||
|
||||
void
|
||||
exit(int32 code)
|
||||
{
|
||||
stdcall(ExitProcess, code);
|
||||
}
|
||||
|
||||
int32
|
||||
write(int32 fd, void *buf, int32 n)
|
||||
{
|
||||
void *handle;
|
||||
uint32 written;
|
||||
|
||||
written = 0;
|
||||
switch(fd) {
|
||||
case 1:
|
||||
handle = stdcall(GetStdHandle, -11);
|
||||
break;
|
||||
case 2:
|
||||
handle = stdcall(GetStdHandle, -12);
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
stdcall(WriteFile, handle, buf, n, &written, 0);
|
||||
return written;
|
||||
}
|
||||
|
||||
uint8*
|
||||
runtime_mmap(byte *addr, uint32 len, int32 prot,
|
||||
int32 flags, int32 fd, uint32 off)
|
||||
{
|
||||
USED(prot, flags, fd, off);
|
||||
return stdcall(VirtualAlloc, addr, len, 0x3000, 0x40);
|
||||
}
|
||||
|
||||
void*
|
||||
get_symdat_addr(void)
|
||||
{
|
||||
byte *mod, *p;
|
||||
uint32 peh, add;
|
||||
uint16 oph;
|
||||
|
||||
mod = stdcall(GetModuleHandle, 0);
|
||||
peh = *(uint32*)(mod+0x3c);
|
||||
p = mod+peh+4;
|
||||
oph = *(uint16*)(p+0x10);
|
||||
p += 0x14+oph;
|
||||
while(strcmp(p, (byte*)".symdat"))
|
||||
p += 40;
|
||||
add = *(uint32*)(p+0x0c);
|
||||
return mod+add;
|
||||
}
|
||||
|
||||
// Thread-safe allocation of an event.
|
||||
static void
|
||||
initevent(void **pevent)
|
||||
{
|
||||
void *event;
|
||||
|
||||
event = stdcall(CreateEvent, 0, 0, 0, 0);
|
||||
if(!casp(pevent, 0, event)) {
|
||||
// Someone else filled it in. Use theirs.
|
||||
stdcall(CloseHandle, event);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
eventlock(Lock *l)
|
||||
{
|
||||
// Allocate event if needed.
|
||||
if(l->event == 0)
|
||||
initevent(&l->event);
|
||||
|
||||
if(xadd(&l->key, 1) > 1) // someone else has it; wait
|
||||
stdcall(WaitForSingleObject, l->event, -1);
|
||||
}
|
||||
|
||||
static void
|
||||
eventunlock(Lock *l)
|
||||
{
|
||||
if(xadd(&l->key, -1) > 0) // someone else is waiting
|
||||
stdcall(SetEvent, l->event);
|
||||
}
|
||||
|
||||
void
|
||||
lock(Lock *l)
|
||||
{
|
||||
if(m->locks < 0)
|
||||
throw("lock count");
|
||||
m->locks++;
|
||||
eventlock(l);
|
||||
}
|
||||
|
||||
void
|
||||
unlock(Lock *l)
|
||||
{
|
||||
m->locks--;
|
||||
if(m->locks < 0)
|
||||
throw("lock count");
|
||||
eventunlock(l);
|
||||
}
|
||||
|
||||
void
|
||||
noteclear(Note *n)
|
||||
{
|
||||
eventlock(&n->lock);
|
||||
}
|
||||
|
||||
void
|
||||
notewakeup(Note *n)
|
||||
{
|
||||
eventunlock(&n->lock);
|
||||
}
|
||||
|
||||
void
|
||||
notesleep(Note *n)
|
||||
{
|
||||
eventlock(&n->lock);
|
||||
eventunlock(&n->lock); // Let other sleepers find out too.
|
||||
}
|
||||
|
||||
void
|
||||
newosproc(M *m, G *g, void *stk, void (*fn)(void))
|
||||
{
|
||||
struct {
|
||||
void *args;
|
||||
void *event_handle;
|
||||
} param = { &m };
|
||||
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);
|
||||
}
|
||||
|
||||
// Called to initialize a new m (including the bootstrap m).
|
||||
void
|
||||
minit(void)
|
||||
{
|
||||
}
|
@ -18,8 +18,18 @@ case "$GOARCH" in
|
||||
# ../../cmd/8l/pass.c:/D_GS
|
||||
# ../../libcgo/linux_386.c:/^start
|
||||
# ../../libcgo/darwin_386.c:/^start
|
||||
echo '#define g 0(GS)'
|
||||
echo '#define m 4(GS)'
|
||||
case "$GOOS" in
|
||||
mingw)
|
||||
echo '#define get_tls(r) MOVL 0x2c(FS), r'
|
||||
echo '#define g(r) 0(r)'
|
||||
echo '#define m(r) 4(r)'
|
||||
;;
|
||||
*)
|
||||
echo '#define get_tls(r)'
|
||||
echo '#define g(r) 0(GS)'
|
||||
echo '#define m(r) 4(GS)'
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
amd64)
|
||||
# These registers are also known to:
|
||||
|
@ -3,7 +3,9 @@
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
#include "runtime.h"
|
||||
#include "defs.h"
|
||||
#include "malloc.h"
|
||||
#include "os.h"
|
||||
|
||||
typedef struct Sched Sched;
|
||||
|
||||
@ -386,7 +388,12 @@ starttheworld(void)
|
||||
void
|
||||
mstart(void)
|
||||
{
|
||||
if(g != m->g0)
|
||||
// TODO(rsc): Change 8g not to assume that extern register
|
||||
// variables are directly addressable. Declaring the
|
||||
// local variable here works around the bug.
|
||||
G* gg = g;
|
||||
|
||||
if(gg != m->g0)
|
||||
throw("bad mstart");
|
||||
if(m->mcache == nil)
|
||||
m->mcache = allocmcache();
|
||||
@ -517,7 +524,12 @@ scheduler(void)
|
||||
void
|
||||
gosched(void)
|
||||
{
|
||||
if(g == m->g0)
|
||||
// TODO(rsc): Change 8g not to assume that extern register
|
||||
// variables are directly addressable. Declaring the
|
||||
// local variable here works around the bug.
|
||||
G* gg = g;
|
||||
|
||||
if(gg == m->g0)
|
||||
throw("gosched of g0");
|
||||
if(gosave(&g->sched) == 0)
|
||||
gogo(&m->sched, 1);
|
||||
|
@ -165,6 +165,20 @@ goargs(void)
|
||||
os·Envs.cap = envc;
|
||||
}
|
||||
|
||||
// Atomic add and return new value.
|
||||
uint32
|
||||
xadd(uint32 volatile *val, int32 delta)
|
||||
{
|
||||
uint32 oval, nval;
|
||||
|
||||
for(;;){
|
||||
oval = *val;
|
||||
nval = oval + delta;
|
||||
if(cas(val, oval, nval))
|
||||
return nval;
|
||||
}
|
||||
}
|
||||
|
||||
byte*
|
||||
getenv(int8 *s)
|
||||
{
|
||||
|
@ -109,7 +109,11 @@ enum
|
||||
struct Lock
|
||||
{
|
||||
uint32 key;
|
||||
#ifdef __MINGW__
|
||||
void* event;
|
||||
#else
|
||||
uint32 sema; // for OS X
|
||||
#endif
|
||||
};
|
||||
struct Usema
|
||||
{
|
||||
@ -204,6 +208,11 @@ struct M
|
||||
uint32 machport; // Return address for Mach IPC (OS X)
|
||||
MCache *mcache;
|
||||
G* lockedg;
|
||||
#ifdef __MINGW__
|
||||
void* return_address; // saved return address and stack
|
||||
void* stack_pointer; // pointer for Windows stdcall
|
||||
void* os_stack_pointer;
|
||||
#endif
|
||||
};
|
||||
struct Stktop
|
||||
{
|
||||
@ -314,6 +323,7 @@ int8* goos;
|
||||
*/
|
||||
int32 strcmp(byte*, byte*);
|
||||
int32 findnull(byte*);
|
||||
int32 findnullw(uint16*);
|
||||
void dump(byte*, int32);
|
||||
int32 runetochar(byte*, int32);
|
||||
int32 charntorune(int32*, uint8*, int32);
|
||||
@ -339,6 +349,7 @@ void memmove(void*, void*, uint32);
|
||||
void* mal(uint32);
|
||||
uint32 cmpstring(String, String);
|
||||
String gostring(byte*);
|
||||
String gostringw(uint16*);
|
||||
void initsig(void);
|
||||
int32 gotraceback(void);
|
||||
void traceback(uint8 *pc, uint8 *sp, G* gp);
|
||||
@ -346,6 +357,8 @@ void tracebackothers(G*);
|
||||
int32 open(byte*, int32, ...);
|
||||
int32 write(int32, void*, int32);
|
||||
bool cas(uint32*, uint32, uint32);
|
||||
bool casp(void**, void*, void*);
|
||||
uint32 xadd(uint32 volatile*, int32);
|
||||
void jmpdefer(byte*, void*);
|
||||
void exit1(int32);
|
||||
void ready(G*);
|
||||
|
@ -19,6 +19,18 @@ findnull(byte *s)
|
||||
return l;
|
||||
}
|
||||
|
||||
int32
|
||||
findnullw(uint16 *s)
|
||||
{
|
||||
int32 l;
|
||||
|
||||
if(s == nil)
|
||||
return 0;
|
||||
for(l=0; s[l]!=0; l++)
|
||||
;
|
||||
return l;
|
||||
}
|
||||
|
||||
int32 maxstring;
|
||||
|
||||
String
|
||||
@ -47,6 +59,24 @@ gostring(byte *str)
|
||||
return s;
|
||||
}
|
||||
|
||||
String
|
||||
gostringw(uint16 *str)
|
||||
{
|
||||
int32 n, i;
|
||||
byte buf[8];
|
||||
String s;
|
||||
|
||||
n = 0;
|
||||
for(i=0; str[i]; i++)
|
||||
n += runetochar(buf, str[i]);
|
||||
s = gostringsize(n+4);
|
||||
n = 0;
|
||||
for(i=0; str[i]; i++)
|
||||
n += runetochar(s.str+n, str[i]);
|
||||
s.len = n;
|
||||
return s;
|
||||
}
|
||||
|
||||
func catstring(s1 String, s2 String) (s3 String) {
|
||||
if(s1.len == 0) {
|
||||
s3 = s2;
|
||||
|
@ -13,6 +13,8 @@
|
||||
// and figure out exactly what we want.
|
||||
|
||||
#include "runtime.h"
|
||||
#include "defs.h"
|
||||
#include "os.h"
|
||||
|
||||
// TODO(rsc): Move this *under* the text segment.
|
||||
// Then define names for these addresses instead of hard-coding magic ones.
|
||||
@ -45,8 +47,13 @@ walksymtab(void (*fn)(Sym*))
|
||||
if(goos != nil && strcmp((uint8*)goos, (uint8*)"nacl") == 0)
|
||||
return;
|
||||
|
||||
#ifdef __MINGW__
|
||||
v = get_symdat_addr();
|
||||
p = (byte*)v+8;
|
||||
#else
|
||||
v = SYMCOUNTS;
|
||||
p = SYMDATA;
|
||||
#endif
|
||||
ep = p + v[0];
|
||||
while(p < ep) {
|
||||
if(p + 7 > ep)
|
||||
@ -246,8 +253,13 @@ splitpcln(void)
|
||||
return;
|
||||
|
||||
// pc/ln table bounds
|
||||
#ifdef __MINGW__
|
||||
v = get_symdat_addr();
|
||||
p = (byte*)v+8;
|
||||
#else
|
||||
v = SYMCOUNTS;
|
||||
p = SYMDATA;
|
||||
#endif
|
||||
p += v[0];
|
||||
ep = p+v[1];
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user