aboutsummaryrefslogtreecommitdiff
path: root/src/pkg
diff options
context:
space:
mode:
authorHector Chu <hectorchu@gmail.com>2010-01-06 17:58:55 -0800
committerRuss Cox <rsc@golang.org>2010-01-06 17:58:55 -0800
commit6bfe5f55f4dc110ca43a202a6a5eb70ee477916b (patch)
tree3ef0b1e03a660d7e220471a0ae9485cc16756632 /src/pkg
parent5c07e0c17ce6a0627a2fe4bbc4254b322ec879ce (diff)
downloadgo-6bfe5f55f4dc110ca43a202a6a5eb70ee477916b.tar.xz
Ported runtime to Windows.
R=rsc CC=golang-dev https://golang.org/cl/176066
Diffstat (limited to 'src/pkg')
-rw-r--r--src/pkg/runtime/386/asm.s67
-rw-r--r--src/pkg/runtime/Makefile5
-rw-r--r--src/pkg/runtime/darwin/386/sys.s15
-rw-r--r--src/pkg/runtime/darwin/thread.c15
-rw-r--r--src/pkg/runtime/freebsd/386/sys.s16
-rw-r--r--src/pkg/runtime/linux/386/sys.s15
-rw-r--r--src/pkg/runtime/mgc0.c14
-rw-r--r--src/pkg/runtime/mingw/386/defs.h17
-rw-r--r--src/pkg/runtime/mingw/386/rt0.s6
-rw-r--r--src/pkg/runtime/mingw/386/signal.c8
-rw-r--r--src/pkg/runtime/mingw/386/sys.s87
-rw-r--r--src/pkg/runtime/mingw/defs.c13
-rw-r--r--src/pkg/runtime/mingw/os.h18
-rw-r--r--src/pkg/runtime/mingw/thread.c265
-rwxr-xr-xsrc/pkg/runtime/mkasmh.sh14
-rw-r--r--src/pkg/runtime/proc.c16
-rw-r--r--src/pkg/runtime/runtime.c14
-rw-r--r--src/pkg/runtime/runtime.h13
-rw-r--r--src/pkg/runtime/string.cgo30
-rw-r--r--src/pkg/runtime/symtab.c12
20 files changed, 600 insertions, 60 deletions
diff --git a/src/pkg/runtime/386/asm.s b/src/pkg/runtime/386/asm.s
index 7ec62161d9..11ce3f6b6f 100644
--- a/src/pkg/runtime/386/asm.s
+++ b/src/pkg/runtime/386/asm.s
@@ -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
diff --git a/src/pkg/runtime/Makefile b/src/pkg/runtime/Makefile
index a85c441904..80bb521b31 100644
--- a/src/pkg/runtime/Makefile
+++ b/src/pkg/runtime/Makefile
@@ -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 >$@
diff --git a/src/pkg/runtime/darwin/386/sys.s b/src/pkg/runtime/darwin/386/sys.s
index 38459447f8..b18f390709 100644
--- a/src/pkg/runtime/darwin/386/sys.s
+++ b/src/pkg/runtime/darwin/386/sys.s
@@ -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()
diff --git a/src/pkg/runtime/darwin/thread.c b/src/pkg/runtime/darwin/thread.c
index bf66f86732..f68b63f7ab 100644
--- a/src/pkg/runtime/darwin/thread.c
+++ b/src/pkg/runtime/darwin/thread.c
@@ -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.
diff --git a/src/pkg/runtime/freebsd/386/sys.s b/src/pkg/runtime/freebsd/386/sys.s
index 651ccb2348..7328a90467 100644
--- a/src/pkg/runtime/freebsd/386/sys.s
+++ b/src/pkg/runtime/freebsd/386/sys.s
@@ -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
diff --git a/src/pkg/runtime/linux/386/sys.s b/src/pkg/runtime/linux/386/sys.s
index 72882cb9dc..f734a68338 100644
--- a/src/pkg/runtime/linux/386/sys.s
+++ b/src/pkg/runtime/linux/386/sys.s
@@ -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
diff --git a/src/pkg/runtime/mgc0.c b/src/pkg/runtime/mgc0.c
index f0eafe3fd6..91898270d2 100644
--- a/src/pkg/runtime/mgc0.c
+++ b/src/pkg/runtime/mgc0.c
@@ -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;
diff --git a/src/pkg/runtime/mingw/386/defs.h b/src/pkg/runtime/mingw/386/defs.h
new file mode 100644
index 0000000000..f5a16367eb
--- /dev/null
+++ b/src/pkg/runtime/mingw/386/defs.h
@@ -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
diff --git a/src/pkg/runtime/mingw/386/rt0.s b/src/pkg/runtime/mingw/386/rt0.s
new file mode 100644
index 0000000000..efd8ce3e68
--- /dev/null
+++ b/src/pkg/runtime/mingw/386/rt0.s
@@ -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)
diff --git a/src/pkg/runtime/mingw/386/signal.c b/src/pkg/runtime/mingw/386/signal.c
new file mode 100644
index 0000000000..ba38823911
--- /dev/null
+++ b/src/pkg/runtime/mingw/386/signal.c
@@ -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)
+{
+}
diff --git a/src/pkg/runtime/mingw/386/sys.s b/src/pkg/runtime/mingw/386/sys.s
new file mode 100644
index 0000000000..9bbafc2785
--- /dev/null
+++ b/src/pkg/runtime/mingw/386/sys.s
@@ -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
diff --git a/src/pkg/runtime/mingw/defs.c b/src/pkg/runtime/mingw/defs.c
new file mode 100644
index 0000000000..db5f1400ef
--- /dev/null
+++ b/src/pkg/runtime/mingw/defs.c
@@ -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,
+};
diff --git a/src/pkg/runtime/mingw/os.h b/src/pkg/runtime/mingw/os.h
new file mode 100644
index 0000000000..8470cc0e58
--- /dev/null
+++ b/src/pkg/runtime/mingw/os.h
@@ -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);
diff --git a/src/pkg/runtime/mingw/thread.c b/src/pkg/runtime/mingw/thread.c
new file mode 100644
index 0000000000..979fd42247
--- /dev/null
+++ b/src/pkg/runtime/mingw/thread.c
@@ -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)
+{
+}
diff --git a/src/pkg/runtime/mkasmh.sh b/src/pkg/runtime/mkasmh.sh
index cb4b6d214f..fdd2668406 100755
--- a/src/pkg/runtime/mkasmh.sh
+++ b/src/pkg/runtime/mkasmh.sh
@@ -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:
diff --git a/src/pkg/runtime/proc.c b/src/pkg/runtime/proc.c
index 60d76bc0f7..8dc9243261 100644
--- a/src/pkg/runtime/proc.c
+++ b/src/pkg/runtime/proc.c
@@ -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);
diff --git a/src/pkg/runtime/runtime.c b/src/pkg/runtime/runtime.c
index 4a0309e0c7..8588894624 100644
--- a/src/pkg/runtime/runtime.c
+++ b/src/pkg/runtime/runtime.c
@@ -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)
{
diff --git a/src/pkg/runtime/runtime.h b/src/pkg/runtime/runtime.h
index 8052fd09ca..2d956ea980 100644
--- a/src/pkg/runtime/runtime.h
+++ b/src/pkg/runtime/runtime.h
@@ -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*);
diff --git a/src/pkg/runtime/string.cgo b/src/pkg/runtime/string.cgo
index 6e380a1075..03b05618d8 100644
--- a/src/pkg/runtime/string.cgo
+++ b/src/pkg/runtime/string.cgo
@@ -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;
diff --git a/src/pkg/runtime/symtab.c b/src/pkg/runtime/symtab.c
index 0b5499474f..1a547f230b 100644
--- a/src/pkg/runtime/symtab.c
+++ b/src/pkg/runtime/symtab.c
@@ -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];