cgo: windows/386 port

R=rsc, peterGo, brainman
CC=golang-dev
https://golang.org/cl/3733046
diff --git a/src/pkg/Makefile b/src/pkg/Makefile
index b9031d3..3494e1c 100644
--- a/src/pkg/Makefile
+++ b/src/pkg/Makefile
@@ -151,10 +151,6 @@
 
 endif
 
-ifeq ($(GOOS),windows)
-DIRS:=$(filter-out runtime/cgo,$(DIRS))
-endif
-
 NOTEST=\
 	debug/proc\
 	exp/draw/x11\
diff --git a/src/pkg/debug/pe/file.go b/src/pkg/debug/pe/file.go
index 904d2f8..82c0240 100644
--- a/src/pkg/debug/pe/file.go
+++ b/src/pkg/debug/pe/file.go
@@ -49,6 +49,17 @@
 	sr *io.SectionReader
 }
 
+type ImportDirectory struct {
+	OriginalFirstThunk uint32
+	TimeDateStamp      uint32
+	ForwarderChain     uint32
+	Name               uint32
+	FirstThunk         uint32
+
+	dll string
+	rva []uint32
+}
+
 // Data reads and returns the contents of the PE section.
 func (s *Section) Data() ([]byte, os.Error) {
 	dat := make([]byte, s.sr.Size())
@@ -229,3 +240,70 @@
 	abbrev, info, str := dat[0], dat[1], dat[2]
 	return dwarf.New(abbrev, nil, nil, info, nil, nil, nil, str)
 }
+
+// ImportedSymbols returns the names of all symbols
+// referred to by the binary f that are expected to be
+// satisfied by other libraries at dynamic load time.
+// It does not return weak symbols.
+func (f *File) ImportedSymbols() ([]string, os.Error) {
+	ds := f.Section(".idata")
+	if ds == nil {
+		// not dynamic, so no libraries
+		return nil, nil
+	}
+	d, err := ds.Data()
+	if err != nil {
+		return nil, err
+	}
+	var ida []ImportDirectory
+	for len(d) > 0 {
+		var dt ImportDirectory
+		dt.OriginalFirstThunk = binary.LittleEndian.Uint32(d[0:4])
+		dt.Name = binary.LittleEndian.Uint32(d[12:16])
+		dt.FirstThunk = binary.LittleEndian.Uint32(d[16:20])
+		d = d[20:]
+		if dt.OriginalFirstThunk == 0 {
+			break
+		}
+		ida = append(ida, dt)
+	}
+	for i, _ := range ida {
+		for len(d) > 0 {
+			va := binary.LittleEndian.Uint32(d[0:4])
+			d = d[4:]
+			if va == 0 {
+				break
+			}
+			ida[i].rva = append(ida[i].rva, va)
+		}
+	}
+	for _, _ = range ida {
+		for len(d) > 0 {
+			va := binary.LittleEndian.Uint32(d[0:4])
+			d = d[4:]
+			if va == 0 {
+				break
+			}
+		}
+	}
+	names, _ := ds.Data()
+	var all []string
+	for _, dt := range ida {
+		dt.dll, _ = getString(names, int(dt.Name-ds.VirtualAddress))
+		for _, va := range dt.rva {
+			fn, _ := getString(names, int(va-ds.VirtualAddress+2))
+			all = append(all, fn+":"+dt.dll)
+		}
+	}
+
+	return all, nil
+}
+
+// ImportedLibraries returns the names of all libraries
+// referred to by the binary f that are expected to be
+// linked with the binary at dynamic link time.
+func (f *File) ImportedLibraries() ([]string, os.Error) {
+	// TODO
+	// cgo -dynimport don't use this for windows PE, so just return.
+	return nil, nil
+}
diff --git a/src/pkg/runtime/386/asm.s b/src/pkg/runtime/386/asm.s
index 101a0cf..58ca712 100644
--- a/src/pkg/runtime/386/asm.s
+++ b/src/pkg/runtime/386/asm.s
@@ -18,9 +18,10 @@
 	// we set up GS ourselves.
 	MOVL	initcgo(SB), AX
 	TESTL	AX, AX
-	JZ	3(PC)
+	JZ	4(PC)
 	CALL	AX
-	JMP	ok
+	CMPL runtime·iswindows(SB), $0
+	JEQ ok
 
 	// set up %gs
 	CALL	runtime·ldt0setup(SB)
diff --git a/src/pkg/runtime/cgo/Makefile b/src/pkg/runtime/cgo/Makefile
index dc9ffb4..a2ce902 100644
--- a/src/pkg/runtime/cgo/Makefile
+++ b/src/pkg/runtime/cgo/Makefile
@@ -30,7 +30,11 @@
 	_cgo_import.$O\
 	$(CGO_OFILES)\
 
+ifeq ($(GOOS),windows)
+CGO_LDFLAGS=-lm -mthreads
+else
 CGO_LDFLAGS=-lpthread
+endif
 
 ifeq ($(GOOS),freebsd)
 OFILES+=\
diff --git a/src/pkg/runtime/cgo/windows_386.c b/src/pkg/runtime/cgo/windows_386.c
index 5f5235b..f39309c 100755
--- a/src/pkg/runtime/cgo/windows_386.c
+++ b/src/pkg/runtime/cgo/windows_386.c
@@ -30,6 +30,7 @@
 threadentry(void *v)
 {
 	ThreadStart ts;
+	void *tls0;
 
 	ts = *(ThreadStart*)v;
 	free(v);
@@ -45,13 +46,17 @@
 	/*
 	 * Set specific keys in thread local storage.
 	 */
+	tls0 = (void*)LocalAlloc(LPTR, 32);
 	asm volatile (
-		"MOVL %%fs:0x2c, %%eax\n"	// MOVL 0x24(FS), tmp
-		"movl %0, 0(%%eax)\n"	// MOVL g, 0(FS)
-		"movl %1, 4(%%eax)\n"	// MOVL m, 4(FS)
-		:: "r"(ts.g), "r"(ts.m) : "%eax"
+		"movl %0, %%fs:0x2c\n"	// MOVL tls0, 0x2c(FS)
+		"movl %%fs:0x2c, %%eax\n"	// MOVL 0x2c(FS), tmp
+		"movl %1, 0(%%eax)\n"	// MOVL g, 0(FS)
+		"movl %2, 4(%%eax)\n"	// MOVL m, 4(FS)
+		:: "r"(tls0), "r"(ts.g), "r"(ts.m) : "%eax"
 	);
 	
 	crosscall_386(ts.fn);
+	
+	LocalFree(tls0);
 	return nil;
 }
diff --git a/src/pkg/runtime/runtime.c b/src/pkg/runtime/runtime.c
index 5136752..8d36750 100644
--- a/src/pkg/runtime/runtime.c
+++ b/src/pkg/runtime/runtime.c
@@ -153,6 +153,7 @@
 }
 
 int32 runtime·isplan9;
+int32 runtime·iswindows;
 
 void
 runtime·goargs(void)
diff --git a/src/pkg/runtime/windows/386/rt0.s b/src/pkg/runtime/windows/386/rt0.s
index 4b67a9f..3b023de 100644
--- a/src/pkg/runtime/windows/386/rt0.s
+++ b/src/pkg/runtime/windows/386/rt0.s
@@ -9,3 +9,6 @@
 	MOVL	SP, 0(FS)
 
 	JMP	_rt0_386(SB)
+
+DATA  runtime·iswindows(SB)/4, $1
+GLOBL runtime·iswindows(SB), $4