1
0
mirror of https://github.com/golang/go synced 2024-10-03 06:21:21 -06:00

Ported runtime to Windows.

R=rsc
CC=golang-dev
https://golang.org/cl/176066
This commit is contained in:
Hector Chu 2010-01-06 17:58:55 -08:00 committed by Russ Cox
parent 5c07e0c17c
commit 6bfe5f55f4
20 changed files with 600 additions and 60 deletions

View File

@ -26,17 +26,19 @@ TEXT _rt0_386(SB),7,$0
CALL ldt0setup(SB) CALL ldt0setup(SB)
// store through it, to make sure it works // store through it, to make sure it works
MOVL $0x123, 0(GS) get_tls(BX)
MOVL $0x123, g(BX)
MOVL tls0(SB), AX MOVL tls0(SB), AX
CMPL AX, $0x123 CMPL AX, $0x123
JEQ ok JEQ ok
MOVL AX, 0 // abort MOVL AX, 0 // abort
ok: ok:
// set up m and g "registers" // set up m and g "registers"
get_tls(BX)
LEAL g0(SB), CX LEAL g0(SB), CX
MOVL CX, g MOVL CX, g(BX)
LEAL m0(SB), AX LEAL m0(SB), AX
MOVL AX, m MOVL AX, m(BX)
// save m->g0 = g0 // save m->g0 = g0
MOVL CX, m_g0(AX) MOVL CX, m_g0(AX)
@ -100,7 +102,8 @@ TEXT gosave(SB), 7, $0
MOVL BX, gobuf_sp(AX) MOVL BX, gobuf_sp(AX)
MOVL 0(SP), BX // caller's PC MOVL 0(SP), BX // caller's PC
MOVL BX, gobuf_pc(AX) MOVL BX, gobuf_pc(AX)
MOVL g, BX get_tls(CX)
MOVL g(CX), BX
MOVL BX, gobuf_g(AX) MOVL BX, gobuf_g(AX)
MOVL $0, AX // return 0 MOVL $0, AX // return 0
RET RET
@ -112,7 +115,8 @@ TEXT gogo(SB), 7, $0
MOVL 4(SP), BX // gobuf MOVL 4(SP), BX // gobuf
MOVL gobuf_g(BX), DX MOVL gobuf_g(BX), DX
MOVL 0(DX), CX // make sure g != nil 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_sp(BX), SP // restore SP
MOVL gobuf_pc(BX), BX MOVL gobuf_pc(BX), BX
JMP BX JMP BX
@ -124,7 +128,8 @@ TEXT gogocall(SB), 7, $0
MOVL 8(SP), AX // fn MOVL 8(SP), AX // fn
MOVL 4(SP), BX // gobuf MOVL 4(SP), BX // gobuf
MOVL gobuf_g(BX), DX MOVL gobuf_g(BX), DX
MOVL DX, g get_tls(CX)
MOVL DX, g(CX)
MOVL 0(DX), CX // make sure g != nil MOVL 0(DX), CX // make sure g != nil
MOVL gobuf_sp(BX), SP // restore SP MOVL gobuf_sp(BX), SP // restore SP
MOVL gobuf_pc(BX), BX MOVL gobuf_pc(BX), BX
@ -139,9 +144,10 @@ TEXT gogocall(SB), 7, $0
// Called during function prolog when more stack is needed. // Called during function prolog when more stack is needed.
TEXT runtime·morestack(SB),7,$0 TEXT runtime·morestack(SB),7,$0
// Cannot grow scheduler stack (m->g0). // Cannot grow scheduler stack (m->g0).
MOVL m, BX get_tls(CX)
MOVL m(CX), BX
MOVL m_g0(BX), SI MOVL m_g0(BX), SI
CMPL g, SI CMPL g(CX), SI
JNE 2(PC) JNE 2(PC)
INT $3 INT $3
@ -158,7 +164,8 @@ TEXT runtime·morestack(SB),7,$0
LEAL 8(SP), CX // f's caller's SP LEAL 8(SP), CX // f's caller's SP
MOVL CX, (m_morebuf+gobuf_sp)(BX) MOVL CX, (m_morebuf+gobuf_sp)(BX)
MOVL CX, (m_morefp)(BX) MOVL CX, (m_morefp)(BX)
MOVL g, SI get_tls(CX)
MOVL g(CX), SI
MOVL SI, (m_morebuf+gobuf_g)(BX) MOVL SI, (m_morebuf+gobuf_g)(BX)
// Set m->morepc to f's PC. // Set m->morepc to f's PC.
@ -167,7 +174,7 @@ TEXT runtime·morestack(SB),7,$0
// Call newstack on m's scheduling stack. // Call newstack on m's scheduling stack.
MOVL m_g0(BX), BP MOVL m_g0(BX), BP
MOVL BP, g MOVL BP, g(CX)
MOVL (m_sched+gobuf_sp)(BX), SP MOVL (m_sched+gobuf_sp)(BX), SP
CALL newstack(SB) CALL newstack(SB)
MOVL $0, 0x1003 // crash if newstack returns 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). // func call(fn *byte, arg *byte, argsize uint32).
TEXT reflect·call(SB), 7, $0 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 // Save our caller's state as the PC and SP to
// restore when returning from f. // restore when returning from f.
@ -187,7 +195,7 @@ TEXT reflect·call(SB), 7, $0
MOVL AX, (m_morebuf+gobuf_pc)(BX) MOVL AX, (m_morebuf+gobuf_pc)(BX)
LEAL 4(SP), AX // our caller's SP LEAL 4(SP), AX // our caller's SP
MOVL AX, (m_morebuf+gobuf_sp)(BX) MOVL AX, (m_morebuf+gobuf_sp)(BX)
MOVL g, AX MOVL g(CX), AX
MOVL AX, (m_morebuf+gobuf_g)(BX) MOVL AX, (m_morebuf+gobuf_g)(BX)
// Set up morestack arguments to call f on a new stack. // 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. // Call newstack on m's scheduling stack.
MOVL m_g0(BX), BP MOVL m_g0(BX), BP
MOVL BP, g get_tls(CX)
MOVL BP, g(CX)
MOVL (m_sched+gobuf_sp)(BX), SP MOVL (m_sched+gobuf_sp)(BX), SP
CALL newstack(SB) CALL newstack(SB)
MOVL $0, 0x1103 // crash if newstack returns MOVL $0, 0x1103 // crash if newstack returns
@ -217,12 +226,13 @@ TEXT reflect·call(SB), 7, $0
// Return point when leaving stack. // Return point when leaving stack.
TEXT runtime·lessstack(SB), 7, $0 TEXT runtime·lessstack(SB), 7, $0
// Save return value in m->cret // Save return value in m->cret
MOVL m, BX get_tls(CX)
MOVL m(CX), BX
MOVL AX, m_cret(BX) MOVL AX, m_cret(BX)
// Call oldstack on m's scheduling stack. // Call oldstack on m's scheduling stack.
MOVL m_g0(BX), DX MOVL m_g0(BX), DX
MOVL DX, g MOVL DX, g(CX)
MOVL (m_sched+gobuf_sp)(BX), SP MOVL (m_sched+gobuf_sp)(BX), SP
CALL oldstack(SB) CALL oldstack(SB)
MOVL $0, 0x1004 // crash if oldstack returns MOVL $0, 0x1004 // crash if oldstack returns
@ -248,6 +258,25 @@ TEXT cas(SB), 7, $0
MOVL $1, AX MOVL $1, AX
RET 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); // void jmpdefer(fn, sp);
// called from deferreturn. // called from deferreturn.
// 1. pop the caller // 1. pop the caller
@ -308,9 +337,10 @@ TEXT runcgo(SB),7,$16
MOVL SP, CX MOVL SP, CX
// Figure out if we need to switch to m->g0 stack. // 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 MOVL m_g0(DX), SI
CMPL g, SI CMPL g(DI), SI
JEQ 2(PC) JEQ 2(PC)
MOVL (m_sched+gobuf_sp)(DX), SP 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) // check that SP is in range [g->stackbase, g->stackguard)
TEXT stackcheck(SB), 7, $0 TEXT stackcheck(SB), 7, $0
MOVL g, AX get_tls(CX)
MOVL g(CX), AX
CMPL g_stackbase(AX), SP CMPL g_stackbase(AX), SP
JHI 2(PC) JHI 2(PC)
INT $3 INT $3

View File

@ -17,7 +17,8 @@ CFLAGS_64=-D_64BIT
# TODO(kaib): fix register allocation to honor extern register so we # TODO(kaib): fix register allocation to honor extern register so we
# can enable optimizations again. # can enable optimizations again.
CFLAGS_arm=-N 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=\ GOFILES=\
extern.go\ extern.go\
@ -118,4 +119,4 @@ cgo2c: cgo2c.c
# for discovering offsets inside structs when debugging # for discovering offsets inside structs when debugging
runtime.acid.$(GOARCH): runtime.h proc.c runtime.acid.$(GOARCH): runtime.h proc.c
$(QUOTED_GOBIN)/$(CC) -a proc.c >$@ $(QUOTED_GOBIN)/$(CC) $(CFLAGS) -a proc.c >$@

View File

@ -64,9 +64,10 @@ TEXT sigtramp(SB),7,$40
MOVW BX, GS MOVW BX, GS
// g = m->gsignal // g = m->gsignal
MOVL m, BP get_tls(CX)
MOVL m(CX), BP
MOVL m_gsignal(BP), BP MOVL m_gsignal(BP), BP
MOVL BP, g MOVL BP, g(CX)
MOVL handler+0(FP), DI MOVL handler+0(FP), DI
// 4(FP) is sigstyle // 4(FP) is sigstyle
@ -80,9 +81,10 @@ TEXT sigtramp(SB),7,$40
CALL DI CALL DI
// g = m->curg // g = m->curg
MOVL m, BP get_tls(CX)
MOVL m(CX), BP
MOVL m_curg(BP), BP MOVL m_curg(BP), BP
MOVL BP, g MOVL BP, g(CX)
MOVL context+16(FP), CX MOVL context+16(FP), CX
MOVL style+4(FP), BX MOVL style+4(FP), BX
@ -150,8 +152,9 @@ TEXT bsdthread_start(SB),7,$0
POPAL POPAL
// Now segment is established. Initialize m, g. // Now segment is established. Initialize m, g.
MOVL AX, g get_tls(BP)
MOVL DX, m MOVL AX, g(BP)
MOVL DX, m(BP)
MOVL BX, m_procid(DX) // m->procid = thread port (for debuggers) MOVL BX, m_procid(DX) // m->procid = thread port (for debuggers)
CALL stackcheck(SB) // smashes AX CALL stackcheck(SB) // smashes AX
CALL CX // fn() CALL CX // fn()

View File

@ -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. // Blocking locks.
// Implement Locks, using semaphores. // Implement Locks, using semaphores.

View File

@ -33,8 +33,10 @@ TEXT thr_start(SB),7,$0
POPL AX POPL AX
POPL AX POPL AX
POPAL POPAL
MOVL BX, g get_tls(CX)
MOVL AX, m MOVL BX, g(CX)
MOVL AX, m(CX)
CALL stackcheck(SB) // smashes AX CALL stackcheck(SB) // smashes AX
CALL mstart(SB) CALL mstart(SB)
MOVL 0, AX // crash (not reached) MOVL 0, AX // crash (not reached)
@ -80,9 +82,10 @@ TEXT sigaction(SB),7,$-4
TEXT sigtramp(SB),7,$40 TEXT sigtramp(SB),7,$40
// g = m->gsignal // g = m->gsignal
MOVL m, BP get_tls(DX)
MOVL m(DX), BP
MOVL m_gsignal(BP), BP MOVL m_gsignal(BP), BP
MOVL BP, g MOVL BP, g(DX)
MOVL signo+0(FP), AX MOVL signo+0(FP), AX
MOVL siginfo+4(FP), BX MOVL siginfo+4(FP), BX
@ -94,9 +97,10 @@ TEXT sigtramp(SB),7,$40
CALL sighandler(SB) CALL sighandler(SB)
// g = m->curg // g = m->curg
MOVL m, BP get_tls(DX)
MOVL m(DX), BP
MOVL m_curg(BP), BP MOVL m_curg(BP), BP
MOVL BP, g MOVL BP, g(DX)
MOVL context+8(FP), AX MOVL context+8(FP), AX

View File

@ -40,9 +40,10 @@ TEXT rt_sigaction(SB),7,$0
RET RET
TEXT sigtramp(SB),7,$0 TEXT sigtramp(SB),7,$0
MOVL m, BP get_tls(CX)
MOVL m(CX), BP
MOVL m_gsignal(BP), AX MOVL m_gsignal(BP), AX
MOVL AX, g MOVL AX, g(CX)
JMP sighandler(SB) JMP sighandler(SB)
TEXT sigignore(SB),7,$0 TEXT sigignore(SB),7,$0
@ -50,9 +51,10 @@ TEXT sigignore(SB),7,$0
TEXT sigreturn(SB),7,$0 TEXT sigreturn(SB),7,$0
// g = m->curg // g = m->curg
MOVL m, BP get_tls(CX)
MOVL m(CX), BP
MOVL m_curg(BP), BP MOVL m_curg(BP), BP
MOVL BP, g MOVL BP, g(CX)
MOVL $173, AX // rt_sigreturn MOVL $173, AX // rt_sigreturn
INT $0x80 INT $0x80
INT $3 // not reached INT $3 // not reached
@ -149,8 +151,9 @@ TEXT clone(SB),7,$0
MOVW DI, GS MOVW DI, GS
// Now segment is established. Initialize m, g. // Now segment is established. Initialize m, g.
MOVL DX, g get_tls(AX)
MOVL BX, m MOVL DX, g(AX)
MOVL BX, m(AX)
CALL stackcheck(SB) // smashes AX CALL stackcheck(SB) // smashes AX
MOVL 0(DX), DX // paranoia; check they are not nil MOVL 0(DX), DX // paranoia; check they are not nil

View File

@ -73,8 +73,12 @@ scanstack(G *gp)
{ {
Stktop *stk; Stktop *stk;
byte *sp; 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; sp = (byte*)&gp;
else else
sp = gp->sched.sp; sp = gp->sched.sp;
@ -90,6 +94,10 @@ static void
mark(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. // mark data+bss.
// skip mheap itself, which has no interesting pointers // skip mheap itself, which has no interesting pointers
@ -106,7 +114,7 @@ mark(void)
case Gdead: case Gdead:
break; break;
case Grunning: case Grunning:
if(gp != g) if(gp != gg)
throw("mark - world not stopped"); throw("mark - world not stopped");
scanstack(gp); scanstack(gp);
break; break;

View 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

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

View 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)
{
}

View 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

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

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

View 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, &param, 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)
{
}

View File

@ -18,8 +18,18 @@ case "$GOARCH" in
# ../../cmd/8l/pass.c:/D_GS # ../../cmd/8l/pass.c:/D_GS
# ../../libcgo/linux_386.c:/^start # ../../libcgo/linux_386.c:/^start
# ../../libcgo/darwin_386.c:/^start # ../../libcgo/darwin_386.c:/^start
echo '#define g 0(GS)' case "$GOOS" in
echo '#define m 4(GS)' 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) amd64)
# These registers are also known to: # These registers are also known to:

View File

@ -3,7 +3,9 @@
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
#include "runtime.h" #include "runtime.h"
#include "defs.h"
#include "malloc.h" #include "malloc.h"
#include "os.h"
typedef struct Sched Sched; typedef struct Sched Sched;
@ -386,7 +388,12 @@ starttheworld(void)
void void
mstart(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"); throw("bad mstart");
if(m->mcache == nil) if(m->mcache == nil)
m->mcache = allocmcache(); m->mcache = allocmcache();
@ -517,7 +524,12 @@ scheduler(void)
void void
gosched(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"); throw("gosched of g0");
if(gosave(&g->sched) == 0) if(gosave(&g->sched) == 0)
gogo(&m->sched, 1); gogo(&m->sched, 1);

View File

@ -165,6 +165,20 @@ goargs(void)
os·Envs.cap = envc; 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* byte*
getenv(int8 *s) getenv(int8 *s)
{ {

View File

@ -109,7 +109,11 @@ enum
struct Lock struct Lock
{ {
uint32 key; uint32 key;
#ifdef __MINGW__
void* event;
#else
uint32 sema; // for OS X uint32 sema; // for OS X
#endif
}; };
struct Usema struct Usema
{ {
@ -204,6 +208,11 @@ struct M
uint32 machport; // Return address for Mach IPC (OS X) uint32 machport; // Return address for Mach IPC (OS X)
MCache *mcache; MCache *mcache;
G* lockedg; 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 struct Stktop
{ {
@ -314,6 +323,7 @@ int8* goos;
*/ */
int32 strcmp(byte*, byte*); int32 strcmp(byte*, byte*);
int32 findnull(byte*); int32 findnull(byte*);
int32 findnullw(uint16*);
void dump(byte*, int32); void dump(byte*, int32);
int32 runetochar(byte*, int32); int32 runetochar(byte*, int32);
int32 charntorune(int32*, uint8*, int32); int32 charntorune(int32*, uint8*, int32);
@ -339,6 +349,7 @@ void memmove(void*, void*, uint32);
void* mal(uint32); void* mal(uint32);
uint32 cmpstring(String, String); uint32 cmpstring(String, String);
String gostring(byte*); String gostring(byte*);
String gostringw(uint16*);
void initsig(void); void initsig(void);
int32 gotraceback(void); int32 gotraceback(void);
void traceback(uint8 *pc, uint8 *sp, G* gp); void traceback(uint8 *pc, uint8 *sp, G* gp);
@ -346,6 +357,8 @@ void tracebackothers(G*);
int32 open(byte*, int32, ...); int32 open(byte*, int32, ...);
int32 write(int32, void*, int32); int32 write(int32, void*, int32);
bool cas(uint32*, uint32, uint32); bool cas(uint32*, uint32, uint32);
bool casp(void**, void*, void*);
uint32 xadd(uint32 volatile*, int32);
void jmpdefer(byte*, void*); void jmpdefer(byte*, void*);
void exit1(int32); void exit1(int32);
void ready(G*); void ready(G*);

View File

@ -19,6 +19,18 @@ findnull(byte *s)
return l; return l;
} }
int32
findnullw(uint16 *s)
{
int32 l;
if(s == nil)
return 0;
for(l=0; s[l]!=0; l++)
;
return l;
}
int32 maxstring; int32 maxstring;
String String
@ -47,6 +59,24 @@ gostring(byte *str)
return s; 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) { func catstring(s1 String, s2 String) (s3 String) {
if(s1.len == 0) { if(s1.len == 0) {
s3 = s2; s3 = s2;

View File

@ -13,6 +13,8 @@
// and figure out exactly what we want. // and figure out exactly what we want.
#include "runtime.h" #include "runtime.h"
#include "defs.h"
#include "os.h"
// TODO(rsc): Move this *under* the text segment. // TODO(rsc): Move this *under* the text segment.
// Then define names for these addresses instead of hard-coding magic ones. // 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) if(goos != nil && strcmp((uint8*)goos, (uint8*)"nacl") == 0)
return; return;
#ifdef __MINGW__
v = get_symdat_addr();
p = (byte*)v+8;
#else
v = SYMCOUNTS; v = SYMCOUNTS;
p = SYMDATA; p = SYMDATA;
#endif
ep = p + v[0]; ep = p + v[0];
while(p < ep) { while(p < ep) {
if(p + 7 > ep) if(p + 7 > ep)
@ -246,8 +253,13 @@ splitpcln(void)
return; return;
// pc/ln table bounds // pc/ln table bounds
#ifdef __MINGW__
v = get_symdat_addr();
p = (byte*)v+8;
#else
v = SYMCOUNTS; v = SYMCOUNTS;
p = SYMDATA; p = SYMDATA;
#endif
p += v[0]; p += v[0];
ep = p+v[1]; ep = p+v[1];