summaryrefslogtreecommitdiff
path: root/src/pkg/runtime/cgo
diff options
context:
space:
mode:
authorOndřej Surý <ondrej@sury.org>2011-09-13 13:13:40 +0200
committerOndřej Surý <ondrej@sury.org>2011-09-13 13:13:40 +0200
commit5ff4c17907d5b19510a62e08fd8d3b11e62b431d (patch)
treec0650497e988f47be9c6f2324fa692a52dea82e1 /src/pkg/runtime/cgo
parent80f18fc933cf3f3e829c5455a1023d69f7b86e52 (diff)
downloadgolang-5ff4c17907d5b19510a62e08fd8d3b11e62b431d.tar.gz
Imported Upstream version 60upstream/60
Diffstat (limited to 'src/pkg/runtime/cgo')
-rwxr-xr-xsrc/pkg/runtime/cgo/386.S67
-rw-r--r--src/pkg/runtime/cgo/Makefile60
-rw-r--r--src/pkg/runtime/cgo/amd64.S73
-rw-r--r--src/pkg/runtime/cgo/arm.S1
-rw-r--r--src/pkg/runtime/cgo/callbacks.c73
-rw-r--r--src/pkg/runtime/cgo/cgo.go17
-rw-r--r--src/pkg/runtime/cgo/darwin_386.c149
-rw-r--r--src/pkg/runtime/cgo/darwin_amd64.c119
-rw-r--r--src/pkg/runtime/cgo/freebsd.c13
-rw-r--r--src/pkg/runtime/cgo/freebsd_386.c64
-rw-r--r--src/pkg/runtime/cgo/freebsd_amd64.c63
-rw-r--r--src/pkg/runtime/cgo/iscgo.c14
-rw-r--r--src/pkg/runtime/cgo/libcgo.h60
-rw-r--r--src/pkg/runtime/cgo/linux_386.c73
-rw-r--r--src/pkg/runtime/cgo/linux_amd64.c63
-rw-r--r--src/pkg/runtime/cgo/linux_arm.c19
-rw-r--r--src/pkg/runtime/cgo/setenv.c16
-rw-r--r--src/pkg/runtime/cgo/util.c51
-rwxr-xr-xsrc/pkg/runtime/cgo/windows_386.c62
-rwxr-xr-xsrc/pkg/runtime/cgo/windows_amd64.c60
20 files changed, 1117 insertions, 0 deletions
diff --git a/src/pkg/runtime/cgo/386.S b/src/pkg/runtime/cgo/386.S
new file mode 100755
index 000000000..9abab7ebd
--- /dev/null
+++ b/src/pkg/runtime/cgo/386.S
@@ -0,0 +1,67 @@
+// 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.
+
+/*
+ * Apple still insists on underscore prefixes for C function names.
+ */
+#if defined(__APPLE__) || defined(_WIN32)
+#define EXT(s) _##s
+#else
+#define EXT(s) s
+#endif
+
+/*
+ * void crosscall_386(void (*fn)(void))
+ *
+ * Calling into the 8c tool chain, where all registers are caller save.
+ * Called from standard x86 ABI, where %ebp, %ebx, %esi,
+ * and %edi are callee-save, so they must be saved explicitly.
+ */
+.globl EXT(crosscall_386)
+EXT(crosscall_386):
+ pushl %ebp
+ movl %esp, %ebp
+ pushl %ebx
+ pushl %esi
+ pushl %edi
+
+ movl 8(%ebp), %eax /* fn */
+ call *%eax
+
+ popl %edi
+ popl %esi
+ popl %ebx
+ popl %ebp
+ ret
+
+/*
+ * void crosscall2(void (*fn)(void*, int32), void*, int32)
+ *
+ * Save registers and call fn with two arguments.
+ */
+.globl EXT(crosscall2)
+EXT(crosscall2):
+ pushl %ebp
+ movl %esp, %ebp
+ pushl %ebx
+ pushl %esi
+ pushl %edi
+
+ pushl 16(%ebp)
+ pushl 12(%ebp)
+ mov 8(%ebp), %eax
+ call *%eax
+ addl $8,%esp
+
+ popl %edi
+ popl %esi
+ popl %ebx
+ popl %ebp
+ ret
+
+.globl EXT(__stack_chk_fail_local)
+EXT(__stack_chk_fail_local):
+1:
+ jmp 1b
+
diff --git a/src/pkg/runtime/cgo/Makefile b/src/pkg/runtime/cgo/Makefile
new file mode 100644
index 000000000..766794797
--- /dev/null
+++ b/src/pkg/runtime/cgo/Makefile
@@ -0,0 +1,60 @@
+# Copyright 2010 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 ../../../Make.inc
+
+TARG=runtime/cgo
+
+GOFILES=\
+ cgo.go\
+
+ifeq ($(CGO_ENABLED),1)
+
+# Unwarranted chumminess with Make.pkg's cgo rules.
+# Do not try this at home.
+CGO_OFILES=\
+ $(GOARCH).o\
+ $(GOOS)_$(GOARCH).o\
+ util.o\
+
+ifeq ($(GOOS),windows)
+CGO_LDFLAGS=-lm -mthreads
+else
+CGO_LDFLAGS=-lpthread
+CGO_OFILES+=setenv.o\
+
+endif
+
+OFILES=\
+ iscgo.$O\
+ callbacks.$O\
+ _cgo_import.$O\
+ $(CGO_OFILES)\
+
+ifeq ($(GOOS),freebsd)
+OFILES+=\
+ freebsd.$O\
+
+endif
+
+endif
+
+include ../../../Make.pkg
+
+ifeq ($(CGO_ENABLED),1)
+_cgo_defun.c:
+ echo >$@
+
+_cgo_main.c:
+ echo 'int main() { return 0; }' >$@
+endif
+
+$(GOARCH).o: $(GOARCH).S
+ $(HOST_CC) $(_CGO_CFLAGS_$(GOARCH)) -g -O2 -fPIC -o $@ -c $^
+
+$(GOOS)_$(GOARCH).o: $(GOOS)_$(GOARCH).c
+ $(HOST_CC) $(_CGO_CFLAGS_$(GOARCH)) -g -O2 -fPIC -o $@ -c $^
+
+%.o: %.c
+ $(HOST_CC) $(_CGO_CFLAGS_$(GOARCH)) -g -O2 -fPIC -o $@ -c $^
diff --git a/src/pkg/runtime/cgo/amd64.S b/src/pkg/runtime/cgo/amd64.S
new file mode 100644
index 000000000..083c2bc94
--- /dev/null
+++ b/src/pkg/runtime/cgo/amd64.S
@@ -0,0 +1,73 @@
+// 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.
+
+/*
+ * Apple still insists on underscore prefixes for C function names.
+ */
+#if defined(__APPLE__) || defined(_WIN32)
+#define EXT(s) _##s
+#else
+#define EXT(s) s
+#endif
+
+/*
+ * void crosscall_amd64(void (*fn)(void))
+ *
+ * Calling into the 6c tool chain, where all registers are caller save.
+ * Called from standard x86-64 ABI, where %rbx, %rbp, %r12-%r15
+ * are callee-save so they must be saved explicitly.
+ * The standard x86-64 ABI passes the three arguments m, g, fn
+ * in %rdi, %rsi, %rdx.
+ *
+ * Also need to set %r15 to g and %r14 to m (see ../pkg/runtime/mkasmh.sh)
+ * during the call.
+ */
+.globl EXT(crosscall_amd64)
+EXT(crosscall_amd64):
+ pushq %rbx
+ pushq %rbp
+ pushq %r12
+ pushq %r13
+ pushq %r14
+ pushq %r15
+
+ call *%rdi /* fn */
+
+ popq %r15
+ popq %r14
+ popq %r13
+ popq %r12
+ popq %rbp
+ popq %rbx
+ ret
+
+/*
+ * void crosscall2(void (*fn)(void*, int32), void *arg, int32 argsize)
+ *
+ * Save registers and call fn with two arguments. fn is a Go function
+ * which takes parameters on the stack rather than in registers.
+ */
+.globl EXT(crosscall2)
+EXT(crosscall2):
+ subq $0x58, %rsp /* keeps stack pointer 32-byte aligned */
+ movq %rbx, 0x10(%rsp)
+ movq %rbp, 0x18(%rsp)
+ movq %r12, 0x20(%rsp)
+ movq %r13, 0x28(%rsp)
+ movq %r14, 0x30(%rsp)
+ movq %r15, 0x38(%rsp)
+
+ movq %rsi, 0(%rsp) /* arg */
+ movq %rdx, 8(%rsp) /* argsize (includes padding) */
+
+ call *%rdi /* fn */
+
+ movq 0x10(%rsp), %rbx
+ movq 0x18(%rsp), %rbp
+ movq 0x20(%rsp), %r12
+ movq 0x28(%rsp), %r13
+ movq 0x30(%rsp), %r14
+ movq 0x38(%rsp), %r15
+ addq $0x58, %rsp
+ ret
diff --git a/src/pkg/runtime/cgo/arm.S b/src/pkg/runtime/cgo/arm.S
new file mode 100644
index 000000000..32d862984
--- /dev/null
+++ b/src/pkg/runtime/cgo/arm.S
@@ -0,0 +1 @@
+/* unimplemented */
diff --git a/src/pkg/runtime/cgo/callbacks.c b/src/pkg/runtime/cgo/callbacks.c
new file mode 100644
index 000000000..f36fb3fd7
--- /dev/null
+++ b/src/pkg/runtime/cgo/callbacks.c
@@ -0,0 +1,73 @@
+// Copyright 2011 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 "../cgocall.h"
+
+// These utility functions are available to be called from code
+// compiled with gcc via crosscall2.
+
+// The declaration of crosscall2 is:
+// void crosscall2(void (*fn)(void *, int), void *, int);
+//
+// We need to export the symbol crosscall2 in order to support
+// callbacks from shared libraries.
+#pragma dynexport crosscall2 crosscall2
+
+// Allocate memory. This allocates the requested number of bytes in
+// memory controlled by the Go runtime. The allocated memory will be
+// zeroed. You are responsible for ensuring that the Go garbage
+// collector can see a pointer to the allocated memory for as long as
+// it is valid, e.g., by storing a pointer in a local variable in your
+// C function, or in memory allocated by the Go runtime. If the only
+// pointers are in a C global variable or in memory allocated via
+// malloc, then the Go garbage collector may collect the memory.
+
+// Call like this in code compiled with gcc:
+// struct { size_t len; void *ret; } a;
+// a.len = /* number of bytes to allocate */;
+// crosscall2(_cgo_allocate, &a, sizeof a);
+// /* Here a.ret is a pointer to the allocated memory. */
+
+static void
+_cgo_allocate_internal(uintptr len, byte *ret)
+{
+ ret = runtime·mal(len);
+ FLUSH(&ret);
+}
+
+#pragma dynexport _cgo_allocate _cgo_allocate
+void
+_cgo_allocate(void *a, int32 n)
+{
+ runtime·cgocallback((void(*)(void))_cgo_allocate_internal, a, n);
+}
+
+// Panic. The argument is converted into a Go string.
+
+// Call like this in code compiled with gcc:
+// struct { const char *p; } a;
+// a.p = /* string to pass to panic */;
+// crosscall2(_cgo_panic, &a, sizeof a);
+// /* The function call will not return. */
+
+extern void ·cgoStringToEface(String, Eface*);
+
+static void
+_cgo_panic_internal(byte *p)
+{
+ String s;
+ Eface err;
+
+ s = runtime·gostring(p);
+ ·cgoStringToEface(s, &err);
+ runtime·panic(err);
+}
+
+#pragma dynexport _cgo_panic _cgo_panic
+void
+_cgo_panic(void *a, int32 n)
+{
+ runtime·cgocallback((void(*)(void))_cgo_panic_internal, a, n);
+}
diff --git a/src/pkg/runtime/cgo/cgo.go b/src/pkg/runtime/cgo/cgo.go
new file mode 100644
index 000000000..5dcced1e4
--- /dev/null
+++ b/src/pkg/runtime/cgo/cgo.go
@@ -0,0 +1,17 @@
+// Copyright 2010 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.
+
+/*
+Package cgo contains runtime support for code generated
+by the cgo tool. See the documentation for the cgo command
+for details on using cgo.
+*/
+package cgo
+
+// Supports _cgo_panic by converting a string constant to an empty
+// interface.
+
+func cgoStringToEface(s string, ret *interface{}) {
+ *ret = s
+}
diff --git a/src/pkg/runtime/cgo/darwin_386.c b/src/pkg/runtime/cgo/darwin_386.c
new file mode 100644
index 000000000..6d4e259be
--- /dev/null
+++ b/src/pkg/runtime/cgo/darwin_386.c
@@ -0,0 +1,149 @@
+// 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 <pthread.h>
+#include "libcgo.h"
+
+static void* threadentry(void*);
+static pthread_key_t k1, k2;
+
+#define magic1 (0x23581321U)
+
+static void
+inittls(void)
+{
+ uint32 x, y;
+ pthread_key_t tofree[128], k;
+ int i, ntofree;
+ int havek1, havek2;
+
+ /*
+ * Allocate thread-local storage slots for m, g.
+ * The key numbers start at 0x100, and we expect to be
+ * one of the early calls to pthread_key_create, so we
+ * should be able to get pretty low numbers.
+ *
+ * In Darwin/386 pthreads, %gs points at the thread
+ * structure, and each key is an index into the thread-local
+ * storage array that begins at offset 0x48 within in that structure.
+ * It may happen that we are not quite the first function to try
+ * to allocate thread-local storage keys, so instead of depending
+ * on getting 0x100 and 0x101, we try for 0x108 and 0x109,
+ * allocating keys until we get the ones we want and then freeing
+ * the ones we didn't want.
+ *
+ * Thus the final offsets to use in %gs references are
+ * 0x48+4*0x108 = 0x468 and 0x48+4*0x109 = 0x46c.
+ *
+ * The linker and runtime hard-code these constant offsets
+ * from %gs where we expect to find m and g.
+ * Known to ../cmd/8l/obj.c:/468
+ * and to ../pkg/runtime/darwin/386/sys.s:/468
+ *
+ * This is truly disgusting and a bit fragile, but taking care
+ * of it here protects the rest of the system from damage.
+ * The alternative would be to use a global variable that
+ * held the offset and refer to that variable each time we
+ * need a %gs variable (m or g). That approach would
+ * require an extra instruction and memory reference in
+ * every stack growth prolog and would also require
+ * rewriting the code that 8c generates for extern registers.
+ *
+ * Things get more disgusting on OS X 10.7 Lion.
+ * The 0x48 base mentioned above is the offset of the tsd
+ * array within the per-thread structure on Leopard and Snow Leopard.
+ * On Lion, the base moved a little, so while the math above
+ * still applies, the base is different. Thus, we cannot
+ * look for specific key values if we want to build binaries
+ * that run on both systems. Instead, forget about the
+ * specific key values and just allocate and initialize per-thread
+ * storage until we find a key that writes to the memory location
+ * we want. Then keep that key.
+ */
+ havek1 = 0;
+ havek2 = 0;
+ ntofree = 0;
+ while(!havek1 || !havek2) {
+ if(pthread_key_create(&k, nil) < 0) {
+ fprintf(stderr, "runtime/cgo: pthread_key_create failed\n");
+ abort();
+ }
+ pthread_setspecific(k, (void*)magic1);
+ asm volatile("movl %%gs:0x468, %0" : "=r"(x));
+ asm volatile("movl %%gs:0x46c, %0" : "=r"(y));
+ if(x == magic1) {
+ havek1 = 1;
+ k1 = k;
+ } else if(y == magic1) {
+ havek2 = 1;
+ k2 = k;
+ } else {
+ if(ntofree >= nelem(tofree)) {
+ fprintf(stderr, "runtime/cgo: could not obtain pthread_keys\n");
+ fprintf(stderr, "\ttried");
+ for(i=0; i<ntofree; i++)
+ fprintf(stderr, " %#x", (unsigned)tofree[i]);
+ fprintf(stderr, "\n");
+ abort();
+ }
+ tofree[ntofree++] = k;
+ }
+ pthread_setspecific(k, 0);
+ }
+
+ /*
+ * We got the keys we wanted. Free the others.
+ */
+ for(i=0; i<ntofree; i++)
+ pthread_key_delete(tofree[i]);
+}
+
+static void
+xinitcgo(void)
+{
+ inittls();
+}
+
+void (*initcgo)(void) = xinitcgo;
+
+void
+libcgo_sys_thread_start(ThreadStart *ts)
+{
+ pthread_attr_t attr;
+ pthread_t p;
+ size_t size;
+ int err;
+
+ pthread_attr_init(&attr);
+ pthread_attr_getstacksize(&attr, &size);
+ ts->g->stackguard = size;
+ err = pthread_create(&p, &attr, threadentry, ts);
+ if (err != 0) {
+ fprintf(stderr, "runtime/cgo: pthread_create failed: %s\n", strerror(err));
+ abort();
+ }
+}
+
+static void*
+threadentry(void *v)
+{
+ ThreadStart ts;
+
+ ts = *(ThreadStart*)v;
+ free(v);
+
+ ts.g->stackbase = (uintptr)&ts;
+
+ /*
+ * libcgo_sys_thread_start set stackguard to stack size;
+ * change to actual guard pointer.
+ */
+ ts.g->stackguard = (uintptr)&ts - ts.g->stackguard + 4096;
+
+ pthread_setspecific(k1, (void*)ts.g);
+ pthread_setspecific(k2, (void*)ts.m);
+
+ crosscall_386(ts.fn);
+ return nil;
+}
diff --git a/src/pkg/runtime/cgo/darwin_amd64.c b/src/pkg/runtime/cgo/darwin_amd64.c
new file mode 100644
index 000000000..3471044c0
--- /dev/null
+++ b/src/pkg/runtime/cgo/darwin_amd64.c
@@ -0,0 +1,119 @@
+// 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 <pthread.h>
+#include "libcgo.h"
+
+static void* threadentry(void*);
+static pthread_key_t k1, k2;
+
+#define magic1 (0x23581321345589ULL)
+
+static void
+inittls(void)
+{
+ uint64 x, y;
+ pthread_key_t tofree[128], k;
+ int i, ntofree;
+ int havek1, havek2;
+
+ /*
+ * Same logic, code as darwin_386.c:/inittls, except that words
+ * are 8 bytes long now, and the thread-local storage starts
+ * at 0x60 on Leopard / Snow Leopard. So the offsets are
+ * 0x60+8*0x108 = 0x8a0 and 0x60+8*0x109 = 0x8a8.
+ *
+ * The linker and runtime hard-code these constant offsets
+ * from %gs where we expect to find m and g.
+ * Known to ../cmd/6l/obj.c:/8a0
+ * and to ../pkg/runtime/darwin/amd64/sys.s:/8a0
+ *
+ * As disgusting as on the 386; same justification.
+ */
+ havek1 = 0;
+ havek2 = 0;
+ ntofree = 0;
+ while(!havek1 || !havek2) {
+ if(pthread_key_create(&k, nil) < 0) {
+ fprintf(stderr, "runtime/cgo: pthread_key_create failed\n");
+ abort();
+ }
+ pthread_setspecific(k, (void*)magic1);
+ asm volatile("movq %%gs:0x8a0, %0" : "=r"(x));
+ asm volatile("movq %%gs:0x8a8, %0" : "=r"(y));
+ if(x == magic1) {
+ havek1 = 1;
+ k1 = k;
+ } else if(y == magic1) {
+ havek2 = 1;
+ k2 = k;
+ } else {
+ if(ntofree >= nelem(tofree)) {
+ fprintf(stderr, "runtime/cgo: could not obtain pthread_keys\n");
+ fprintf(stderr, "\ttried");
+ for(i=0; i<ntofree; i++)
+ fprintf(stderr, " %#x", (unsigned)tofree[i]);
+ fprintf(stderr, "\n");
+ abort();
+ }
+ tofree[ntofree++] = k;
+ }
+ pthread_setspecific(k, 0);
+ }
+
+ /*
+ * We got the keys we wanted. Free the others.
+ */
+ for(i=0; i<ntofree; i++)
+ pthread_key_delete(tofree[i]);
+}
+
+void
+xinitcgo(void)
+{
+ inittls();
+}
+
+void (*initcgo) = xinitcgo;
+
+void
+libcgo_sys_thread_start(ThreadStart *ts)
+{
+ pthread_attr_t attr;
+ pthread_t p;
+ size_t size;
+ int err;
+
+ pthread_attr_init(&attr);
+ pthread_attr_getstacksize(&attr, &size);
+ ts->g->stackguard = size;
+ err = pthread_create(&p, &attr, threadentry, ts);
+ if (err != 0) {
+ fprintf(stderr, "runtime/cgo: pthread_create failed: %s\n", strerror(err));
+ abort();
+ }
+}
+
+static void*
+threadentry(void *v)
+{
+ ThreadStart ts;
+
+ ts = *(ThreadStart*)v;
+ free(v);
+
+ ts.g->stackbase = (uintptr)&ts;
+
+ /*
+ * libcgo_sys_thread_start set stackguard to stack size;
+ * change to actual guard pointer.
+ */
+ ts.g->stackguard = (uintptr)&ts - ts.g->stackguard + 4096;
+
+ pthread_setspecific(k1, (void*)ts.g);
+ pthread_setspecific(k2, (void*)ts.m);
+
+ crosscall_amd64(ts.fn);
+ return nil;
+}
diff --git a/src/pkg/runtime/cgo/freebsd.c b/src/pkg/runtime/cgo/freebsd.c
new file mode 100644
index 000000000..dfcfa3a21
--- /dev/null
+++ b/src/pkg/runtime/cgo/freebsd.c
@@ -0,0 +1,13 @@
+// Copyright 2010 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.
+
+// Supply environ and __progname, because we don't
+// link against the standard FreeBSD crt0.o and the
+// libc dynamic library needs them.
+
+char *environ[1];
+char *__progname;
+
+#pragma dynexport environ environ
+#pragma dynexport __progname __progname
diff --git a/src/pkg/runtime/cgo/freebsd_386.c b/src/pkg/runtime/cgo/freebsd_386.c
new file mode 100644
index 000000000..ae53201b4
--- /dev/null
+++ b/src/pkg/runtime/cgo/freebsd_386.c
@@ -0,0 +1,64 @@
+// 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 <pthread.h>
+#include "libcgo.h"
+
+static void* threadentry(void*);
+
+static void
+xinitcgo(void)
+{
+}
+
+void (*initcgo)(void) = xinitcgo;
+
+void
+libcgo_sys_thread_start(ThreadStart *ts)
+{
+ pthread_attr_t attr;
+ pthread_t p;
+ size_t size;
+ int err;
+
+ pthread_attr_init(&attr);
+ pthread_attr_getstacksize(&attr, &size);
+ ts->g->stackguard = size;
+ err = pthread_create(&p, &attr, threadentry, ts);
+ if (err != 0) {
+ fprintf(stderr, "runtime/cgo: pthread_create failed: %s\n", strerror(err));
+ abort();
+ }
+}
+
+static void*
+threadentry(void *v)
+{
+ ThreadStart ts;
+
+ ts = *(ThreadStart*)v;
+ free(v);
+
+ ts.g->stackbase = (uintptr)&ts;
+
+ /*
+ * libcgo_sys_thread_start set stackguard to stack size;
+ * change to actual guard pointer.
+ */
+ ts.g->stackguard = (uintptr)&ts - ts.g->stackguard + 4096;
+
+ /*
+ * Set specific keys. On FreeBSD/ELF, the thread local storage
+ * is just before %gs:0. Our dynamic 8.out's reserve 8 bytes
+ * for the two words g and m at %gs:-8 and %gs:-4.
+ */
+ asm volatile (
+ "movl %0, %%gs:-8\n" // MOVL g, -8(GS)
+ "movl %1, %%gs:-4\n" // MOVL m, -4(GS)
+ :: "r"(ts.g), "r"(ts.m)
+ );
+
+ crosscall_386(ts.fn);
+ return nil;
+}
diff --git a/src/pkg/runtime/cgo/freebsd_amd64.c b/src/pkg/runtime/cgo/freebsd_amd64.c
new file mode 100644
index 000000000..5afc1dfea
--- /dev/null
+++ b/src/pkg/runtime/cgo/freebsd_amd64.c
@@ -0,0 +1,63 @@
+// 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 <pthread.h>
+#include "libcgo.h"
+
+static void* threadentry(void*);
+
+static void
+xinitcgo(void)
+{
+}
+
+void (*initcgo)(void) = xinitcgo;
+
+void
+libcgo_sys_thread_start(ThreadStart *ts)
+{
+ pthread_attr_t attr;
+ pthread_t p;
+ size_t size;
+ int err;
+
+ pthread_attr_init(&attr);
+ pthread_attr_getstacksize(&attr, &size);
+ ts->g->stackguard = size;
+ err = pthread_create(&p, &attr, threadentry, ts);
+ if (err != 0) {
+ fprintf(stderr, "runtime/cgo: pthread_create failed: %s\n", strerror(err));
+ abort();
+ }
+}
+
+static void*
+threadentry(void *v)
+{
+ ThreadStart ts;
+
+ ts = *(ThreadStart*)v;
+ free(v);
+
+ ts.g->stackbase = (uintptr)&ts;
+
+ /*
+ * libcgo_sys_thread_start set stackguard to stack size;
+ * change to actual guard pointer.
+ */
+ ts.g->stackguard = (uintptr)&ts - ts.g->stackguard + 4096;
+
+ /*
+ * Set specific keys. On FreeBSD/ELF, the thread local storage
+ * is just before %fs:0. Our dynamic 6.out's reserve 16 bytes
+ * for the two words g and m at %fs:-16 and %fs:-8.
+ */
+ asm volatile (
+ "movq %0, %%fs:-16\n" // MOVL g, -16(FS)
+ "movq %1, %%fs:-8\n" // MOVL m, -8(FS)
+ :: "r"(ts.g), "r"(ts.m)
+ );
+ crosscall_amd64(ts.fn);
+ return nil;
+}
diff --git a/src/pkg/runtime/cgo/iscgo.c b/src/pkg/runtime/cgo/iscgo.c
new file mode 100644
index 000000000..eb6f5c09d
--- /dev/null
+++ b/src/pkg/runtime/cgo/iscgo.c
@@ -0,0 +1,14 @@
+// Copyright 2010 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 runtime package contains an uninitialized definition
+// for runtime·iscgo. Override it to tell the runtime we're here.
+// There are various function pointers that should be set too,
+// but those depend on dynamic linker magic to get initialized
+// correctly, and sometimes they break. This variable is a
+// backup: it depends only on old C style static linking rules.
+
+#include "../runtime.h"
+
+bool runtime·iscgo = 1;
diff --git a/src/pkg/runtime/cgo/libcgo.h b/src/pkg/runtime/cgo/libcgo.h
new file mode 100644
index 000000000..91032959c
--- /dev/null
+++ b/src/pkg/runtime/cgo/libcgo.h
@@ -0,0 +1,60 @@
+// 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 <stdint.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#define nil ((void*)0)
+#define nelem(x) (sizeof(x)/sizeof((x)[0]))
+
+typedef uint32_t uint32;
+typedef uint64_t uint64;
+typedef uintptr_t uintptr;
+
+/*
+ * The beginning of the per-goroutine structure,
+ * as defined in ../pkg/runtime/runtime.h.
+ * Just enough to edit these two fields.
+ */
+typedef struct G G;
+struct G
+{
+ uintptr stackguard;
+ uintptr stackbase;
+};
+
+/*
+ * Arguments to the libcgo_thread_start call.
+ * Also known to ../pkg/runtime/runtime.h.
+ */
+typedef struct ThreadStart ThreadStart;
+struct ThreadStart
+{
+ uintptr m;
+ G *g;
+ void (*fn)(void);
+};
+
+/*
+ * Called by 5c/6c/8c world.
+ * Makes a local copy of the ThreadStart and
+ * calls libcgo_sys_thread_start(ts).
+ */
+void (*libcgo_thread_start)(ThreadStart *ts);
+
+/*
+ * Creates the new operating system thread (OS, arch dependent).
+ */
+void libcgo_sys_thread_start(ThreadStart *ts);
+
+/*
+ * Call fn in the 6c world.
+ */
+void crosscall_amd64(void (*fn)(void));
+
+/*
+ * Call fn in the 8c world.
+ */
+void crosscall_386(void (*fn)(void));
diff --git a/src/pkg/runtime/cgo/linux_386.c b/src/pkg/runtime/cgo/linux_386.c
new file mode 100644
index 000000000..e9df5ffdc
--- /dev/null
+++ b/src/pkg/runtime/cgo/linux_386.c
@@ -0,0 +1,73 @@
+// 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 <pthread.h>
+#include <string.h>
+#include "libcgo.h"
+
+static void *threadentry(void*);
+
+static void
+xinitcgo(void)
+{
+}
+
+void (*initcgo) = xinitcgo;
+
+void
+libcgo_sys_thread_start(ThreadStart *ts)
+{
+ pthread_attr_t attr;
+ pthread_t p;
+ size_t size;
+ int err;
+
+ // Not sure why the memset is necessary here,
+ // but without it, we get a bogus stack size
+ // out of pthread_attr_getstacksize. C'est la Linux.
+ memset(&attr, 0, sizeof attr);
+ pthread_attr_init(&attr);
+ size = 0;
+ pthread_attr_getstacksize(&attr, &size);
+ ts->g->stackguard = size;
+ err = pthread_create(&p, &attr, threadentry, ts);
+ if (err != 0) {
+ fprintf(stderr, "runtime/cgo: pthread_create failed: %s\n", strerror(err));
+ abort();
+ }
+}
+
+static void*
+threadentry(void *v)
+{
+ ThreadStart ts;
+
+ ts = *(ThreadStart*)v;
+ free(v);
+
+ ts.g->stackbase = (uintptr)&ts;
+
+ /*
+ * libcgo_sys_thread_start set stackguard to stack size;
+ * change to actual guard pointer.
+ */
+ ts.g->stackguard = (uintptr)&ts - ts.g->stackguard + 4096;
+
+ /*
+ * Set specific keys. On Linux/ELF, the thread local storage
+ * is just before %gs:0. Our dynamic 8.out's reserve 8 bytes
+ * for the two words g and m at %gs:-8 and %gs:-4.
+ * Xen requires us to access those words indirect from %gs:0
+ * which points at itself.
+ */
+ asm volatile (
+ "movl %%gs:0, %%eax\n" // MOVL 0(GS), tmp
+ "movl %0, -8(%%eax)\n" // MOVL g, -8(GS)
+ "movl %1, -4(%%eax)\n" // MOVL m, -4(GS)
+ :: "r"(ts.g), "r"(ts.m) : "%eax"
+ );
+
+ crosscall_386(ts.fn);
+ return nil;
+}
diff --git a/src/pkg/runtime/cgo/linux_amd64.c b/src/pkg/runtime/cgo/linux_amd64.c
new file mode 100644
index 000000000..d9b8b3706
--- /dev/null
+++ b/src/pkg/runtime/cgo/linux_amd64.c
@@ -0,0 +1,63 @@
+// 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 <pthread.h>
+#include "libcgo.h"
+
+static void* threadentry(void*);
+
+void
+xinitcgo(void)
+{
+}
+
+void (*initcgo)(void) = xinitcgo;
+
+void
+libcgo_sys_thread_start(ThreadStart *ts)
+{
+ pthread_attr_t attr;
+ pthread_t p;
+ size_t size;
+ int err;
+
+ pthread_attr_init(&attr);
+ pthread_attr_getstacksize(&attr, &size);
+ ts->g->stackguard = size;
+ err = pthread_create(&p, &attr, threadentry, ts);
+ if (err != 0) {
+ fprintf(stderr, "runtime/cgo: pthread_create failed: %s\n", strerror(err));
+ abort();
+ }
+}
+
+static void*
+threadentry(void *v)
+{
+ ThreadStart ts;
+
+ ts = *(ThreadStart*)v;
+ free(v);
+
+ ts.g->stackbase = (uintptr)&ts;
+
+ /*
+ * libcgo_sys_thread_start set stackguard to stack size;
+ * change to actual guard pointer.
+ */
+ ts.g->stackguard = (uintptr)&ts - ts.g->stackguard + 4096;
+
+ /*
+ * Set specific keys. On Linux/ELF, the thread local storage
+ * is just before %fs:0. Our dynamic 6.out's reserve 16 bytes
+ * for the two words g and m at %fs:-16 and %fs:-8.
+ */
+ asm volatile (
+ "movq %0, %%fs:-16\n" // MOVL g, -16(FS)
+ "movq %1, %%fs:-8\n" // MOVL m, -8(FS)
+ :: "r"(ts.g), "r"(ts.m)
+ );
+ crosscall_amd64(ts.fn);
+ return nil;
+}
diff --git a/src/pkg/runtime/cgo/linux_arm.c b/src/pkg/runtime/cgo/linux_arm.c
new file mode 100644
index 000000000..e556c433c
--- /dev/null
+++ b/src/pkg/runtime/cgo/linux_arm.c
@@ -0,0 +1,19 @@
+// Copyright 2010 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 "libcgo.h"
+
+static void
+xinitcgo(void)
+{
+}
+
+void (*initcgo)(void) = xinitcgo;
+
+void
+libcgo_sys_thread_start(ThreadStart *ts)
+{
+ // unimplemented
+ *(int*)0 = 0;
+}
diff --git a/src/pkg/runtime/cgo/setenv.c b/src/pkg/runtime/cgo/setenv.c
new file mode 100644
index 000000000..c911b8392
--- /dev/null
+++ b/src/pkg/runtime/cgo/setenv.c
@@ -0,0 +1,16 @@
+// Copyright 20111 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 "libcgo.h"
+
+#include <stdlib.h>
+
+/* Stub for calling setenv */
+static void
+xlibcgo_setenv(char **arg)
+{
+ setenv(arg[0], arg[1], 1);
+}
+
+void (*libcgo_setenv)(char**) = xlibcgo_setenv;
diff --git a/src/pkg/runtime/cgo/util.c b/src/pkg/runtime/cgo/util.c
new file mode 100644
index 000000000..9d96521f5
--- /dev/null
+++ b/src/pkg/runtime/cgo/util.c
@@ -0,0 +1,51 @@
+// 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 "libcgo.h"
+
+/* Stub for calling malloc from Go */
+static void
+x_cgo_malloc(void *p)
+{
+ struct a {
+ long long n;
+ void *ret;
+ } *a = p;
+
+ a->ret = malloc(a->n);
+}
+
+void (*_cgo_malloc)(void*) = x_cgo_malloc;
+
+/* Stub for calling from Go */
+static void
+x_cgo_free(void *p)
+{
+ struct a {
+ void *arg;
+ } *a = p;
+
+ free(a->arg);
+}
+
+void (*_cgo_free)(void*) = x_cgo_free;
+
+/* Stub for creating a new thread */
+static void
+xlibcgo_thread_start(ThreadStart *arg)
+{
+ ThreadStart *ts;
+
+ /* Make our own copy that can persist after we return. */
+ ts = malloc(sizeof *ts);
+ if(ts == nil) {
+ fprintf(stderr, "runtime/cgo: out of memory in thread_start\n");
+ abort();
+ }
+ *ts = *arg;
+
+ libcgo_sys_thread_start(ts); /* OS-dependent half */
+}
+
+void (*libcgo_thread_start)(ThreadStart*) = xlibcgo_thread_start;
diff --git a/src/pkg/runtime/cgo/windows_386.c b/src/pkg/runtime/cgo/windows_386.c
new file mode 100755
index 000000000..f39309cb1
--- /dev/null
+++ b/src/pkg/runtime/cgo/windows_386.c
@@ -0,0 +1,62 @@
+// 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.
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#include "libcgo.h"
+
+static void *threadentry(void*);
+
+/* From what I've read 1MB is default for 32-bit Linux.
+ Allocation granularity on Windows is typically 64 KB. */
+#define STACKSIZE (1*1024*1024)
+
+static void
+xinitcgo(void)
+{
+}
+
+void (*initcgo)(void) = xinitcgo;
+
+void
+libcgo_sys_thread_start(ThreadStart *ts)
+{
+ ts->g->stackguard = STACKSIZE;
+ _beginthread(threadentry, STACKSIZE, ts);
+}
+
+static void*
+threadentry(void *v)
+{
+ ThreadStart ts;
+ void *tls0;
+
+ ts = *(ThreadStart*)v;
+ free(v);
+
+ ts.g->stackbase = (uintptr)&ts;
+
+ /*
+ * libcgo_sys_thread_start set stackguard to stack size;
+ * change to actual guard pointer.
+ */
+ ts.g->stackguard = (uintptr)&ts - ts.g->stackguard + 4096;
+
+ /*
+ * Set specific keys in thread local storage.
+ */
+ tls0 = (void*)LocalAlloc(LPTR, 32);
+ asm volatile (
+ "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/cgo/windows_amd64.c b/src/pkg/runtime/cgo/windows_amd64.c
new file mode 100755
index 000000000..e8313e250
--- /dev/null
+++ b/src/pkg/runtime/cgo/windows_amd64.c
@@ -0,0 +1,60 @@
+// 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.
+
+#define WIN64_LEAN_AND_MEAN
+#include <windows.h>
+#include "libcgo.h"
+
+static void *threadentry(void*);
+
+/* From what I've read 2MB is default for 64-bit Linux.
+ Allocation granularity on Windows is typically 64 KB. */
+#define STACKSIZE (2*1024*1024)
+
+static void
+xinitcgo(void)
+{
+}
+
+void (*initcgo)(void) = xinitcgo;
+
+void
+libcgo_sys_thread_start(ThreadStart *ts)
+{
+ ts->g->stackguard = STACKSIZE;
+ _beginthread(threadentry, STACKSIZE, ts);
+}
+
+static void*
+threadentry(void *v)
+{
+ ThreadStart ts;
+ void *tls0;
+
+ ts = *(ThreadStart*)v;
+ free(v);
+
+ ts.g->stackbase = (uintptr)&ts;
+
+ /*
+ * libcgo_sys_thread_start set stackguard to stack size;
+ * change to actual guard pointer.
+ */
+ ts.g->stackguard = (uintptr)&ts - ts.g->stackguard + 4096;
+
+ /*
+ * Set specific keys in thread local storage.
+ */
+ tls0 = (void*)LocalAlloc(LPTR, 64);
+ asm volatile (
+ "movq %0, %%gs:0x58\n" // MOVL tls0, 0x58(GS)
+ "movq %%gs:0x58, %%rax\n" // MOVQ 0x58(GS), tmp
+ "movq %1, 0(%%rax)\n" // MOVQ g, 0(GS)
+ "movq %2, 8(%%rax)\n" // MOVQ m, 8(GS)
+ :: "r"(tls0), "r"(ts.g), "r"(ts.m) : "%rax"
+ );
+
+ crosscall_amd64(ts.fn);
+ return nil;
+}