summaryrefslogtreecommitdiff
path: root/src/pkg/runtime/cgo
diff options
context:
space:
mode:
Diffstat (limited to 'src/pkg/runtime/cgo')
-rw-r--r--src/pkg/runtime/cgo/asm_386.s29
-rw-r--r--src/pkg/runtime/cgo/asm_amd64.s45
-rw-r--r--src/pkg/runtime/cgo/asm_arm.s23
-rw-r--r--src/pkg/runtime/cgo/callbacks.c22
-rw-r--r--src/pkg/runtime/cgo/cgo.go2
-rw-r--r--src/pkg/runtime/cgo/cgo_arm.c12
-rw-r--r--src/pkg/runtime/cgo/gcc_386.S25
-rw-r--r--src/pkg/runtime/cgo/gcc_amd64.S48
-rw-r--r--src/pkg/runtime/cgo/gcc_arm.S37
-rw-r--r--src/pkg/runtime/cgo/gcc_darwin_386.c13
-rw-r--r--src/pkg/runtime/cgo/gcc_darwin_amd64.c11
-rw-r--r--src/pkg/runtime/cgo/gcc_freebsd_386.c10
-rw-r--r--src/pkg/runtime/cgo/gcc_freebsd_amd64.c10
-rw-r--r--src/pkg/runtime/cgo/gcc_freebsd_arm.c114
-rw-r--r--src/pkg/runtime/cgo/gcc_linux_386.c9
-rw-r--r--src/pkg/runtime/cgo/gcc_linux_amd64.c7
-rw-r--r--src/pkg/runtime/cgo/gcc_linux_arm.c108
-rw-r--r--src/pkg/runtime/cgo/gcc_netbsd_386.c80
-rw-r--r--src/pkg/runtime/cgo/gcc_netbsd_amd64.c80
-rw-r--r--src/pkg/runtime/cgo/gcc_netbsd_arm.c122
-rw-r--r--src/pkg/runtime/cgo/gcc_openbsd_386.c169
-rw-r--r--src/pkg/runtime/cgo/gcc_openbsd_amd64.c169
-rw-r--r--src/pkg/runtime/cgo/gcc_setenv.c8
-rw-r--r--src/pkg/runtime/cgo/gcc_util.c16
-rw-r--r--src/pkg/runtime/cgo/gcc_windows_386.c13
-rw-r--r--src/pkg/runtime/cgo/gcc_windows_amd64.c13
-rw-r--r--src/pkg/runtime/cgo/libcgo.h8
-rw-r--r--src/pkg/runtime/cgo/netbsd.c13
-rw-r--r--src/pkg/runtime/cgo/openbsd.c21
-rw-r--r--src/pkg/runtime/cgo/setenv.c10
30 files changed, 1100 insertions, 147 deletions
diff --git a/src/pkg/runtime/cgo/asm_386.s b/src/pkg/runtime/cgo/asm_386.s
new file mode 100644
index 000000000..7faaa4097
--- /dev/null
+++ b/src/pkg/runtime/cgo/asm_386.s
@@ -0,0 +1,29 @@
+// 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 crosscall2(void (*fn)(void*, int32), void*, int32)
+ * Save registers and call fn with two arguments.
+ */
+TEXT crosscall2(SB),7,$0
+ PUSHL BP
+ MOVL SP, BP
+ PUSHL BX
+ PUSHL SI
+ PUSHL DI
+
+ SUBL $8, SP
+ MOVL 16(BP), AX
+ MOVL AX, 4(SP)
+ MOVL 12(BP), AX
+ MOVL AX, 0(SP)
+ MOVL 8(BP), AX
+ CALL AX
+ ADDL $8, SP
+
+ POPL DI
+ POPL SI
+ POPL BX
+ POPL BP
+ RET
diff --git a/src/pkg/runtime/cgo/asm_amd64.s b/src/pkg/runtime/cgo/asm_amd64.s
new file mode 100644
index 000000000..53f7148a2
--- /dev/null
+++ b/src/pkg/runtime/cgo/asm_amd64.s
@@ -0,0 +1,45 @@
+// 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 crosscall2(void (*fn)(void*, int32), void*, int32)
+ * Save registers and call fn with two arguments.
+ */
+TEXT crosscall2(SB),7,$0
+ SUBQ $0x58, SP /* keeps stack pointer 32-byte aligned */
+ MOVQ BX, 0x10(SP)
+ MOVQ BP, 0x18(SP)
+ MOVQ R12, 0x20(SP)
+ MOVQ R13, 0x28(SP)
+ MOVQ R14, 0x30(SP)
+ MOVQ R15, 0x38(SP)
+
+#ifdef GOOS_windows
+ // Win64 save RBX, RBP, RDI, RSI, RSP, R12, R13, R14, and R15
+ MOVQ DI, 0x40(SP)
+ MOVQ SI, 0x48(SP)
+
+ MOVQ DX, 0(SP) /* arg */
+ MOVQ R8, 8(SP) /* argsize (includes padding) */
+
+ CALL CX /* fn */
+
+ MOVQ 0x40(SP), DI
+ MOVQ 0x48(SP), SI
+#else
+ MOVQ SI, 0(SP) /* arg */
+ MOVQ DX, 8(SP) /* argsize (includes padding) */
+
+ CALL DI /* fn */
+#endif
+
+ MOVQ 0x10(SP), BX
+ MOVQ 0x18(SP), BP
+ MOVQ 0x20(SP), R12
+ MOVQ 0x28(SP), R13
+ MOVQ 0x30(SP), R14
+ MOVQ 0x38(SP), R15
+
+ ADDQ $0x58, SP
+ RET
diff --git a/src/pkg/runtime/cgo/asm_arm.s b/src/pkg/runtime/cgo/asm_arm.s
new file mode 100644
index 000000000..a6ea0dc07
--- /dev/null
+++ b/src/pkg/runtime/cgo/asm_arm.s
@@ -0,0 +1,23 @@
+// Copyright 2012 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 crosscall2(void (*fn)(void*, int32), void*, int32)
+ * Save registers and call fn with two arguments.
+ */
+TEXT crosscall2(SB),7,$-4
+ /*
+ * We still need to save all callee save register as before, and then
+ * push 2 args for fn (R1 and R2).
+ * Also note that at procedure entry in 5c/5g world, 4(R13) will be the
+ * first arg, so we must push another dummy reg (R0) for 0(R13).
+ * Additionally, cgo_tls_set_gm will clobber R0, so we need to save R0
+ * nevertheless.
+ */
+ MOVM.WP [R0, R1, R2, R4, R5, R6, R7, R8, R9, R10, R11, R12, R14], (R13)
+ MOVW _cgo_load_gm(SB), R0
+ BL (R0)
+ MOVW PC, R14
+ MOVW 0(R13), PC
+ MOVM.IAW (R13), [R0, R1, R2, R4, R5, R6, R7, R8, R9, R10, R11, R12, PC]
diff --git a/src/pkg/runtime/cgo/callbacks.c b/src/pkg/runtime/cgo/callbacks.c
index f36fb3fd7..51bd529ec 100644
--- a/src/pkg/runtime/cgo/callbacks.c
+++ b/src/pkg/runtime/cgo/callbacks.c
@@ -33,7 +33,13 @@
static void
_cgo_allocate_internal(uintptr len, byte *ret)
{
+ CgoMal *c;
+
ret = runtime·mal(len);
+ c = runtime·mal(sizeof(*c));
+ c->next = m->cgomal;
+ c->alloc = ret;
+ m->cgomal = c;
FLUSH(&ret);
}
@@ -71,3 +77,19 @@ _cgo_panic(void *a, int32 n)
{
runtime·cgocallback((void(*)(void))_cgo_panic_internal, a, n);
}
+
+#pragma cgo_import_static x_cgo_init
+extern void x_cgo_init(G*);
+void (*_cgo_init)(G*) = x_cgo_init;
+
+#pragma cgo_import_static x_cgo_malloc
+extern void x_cgo_malloc(void*);
+void (*_cgo_malloc)(void*) = x_cgo_malloc;
+
+#pragma cgo_import_static x_cgo_free
+extern void x_cgo_free(void*);
+void (*_cgo_free)(void*) = x_cgo_free;
+
+#pragma cgo_import_static x_cgo_thread_start
+extern void x_cgo_thread_start(void*);
+void (*_cgo_thread_start)(void*) = x_cgo_thread_start;
diff --git a/src/pkg/runtime/cgo/cgo.go b/src/pkg/runtime/cgo/cgo.go
index 414f3da36..e0d538668 100644
--- a/src/pkg/runtime/cgo/cgo.go
+++ b/src/pkg/runtime/cgo/cgo.go
@@ -18,6 +18,8 @@ package cgo
#cgo openbsd LDFLAGS: -lpthread
#cgo windows LDFLAGS: -lm -mthreads
+#cgo CFLAGS: -Wall -Werror
+
*/
import "C"
diff --git a/src/pkg/runtime/cgo/cgo_arm.c b/src/pkg/runtime/cgo/cgo_arm.c
new file mode 100644
index 000000000..d23f53e77
--- /dev/null
+++ b/src/pkg/runtime/cgo/cgo_arm.c
@@ -0,0 +1,12 @@
+// Copyright 2013 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.
+
+#pragma cgo_import_static x_cgo_load_gm
+extern void x_cgo_load_gm(void);
+void (*_cgo_load_gm)(void) = x_cgo_load_gm;
+
+#pragma cgo_import_static x_cgo_save_gm
+extern void x_cgo_save_gm(void);
+void (*_cgo_save_gm)(void) = x_cgo_save_gm;
+
diff --git a/src/pkg/runtime/cgo/gcc_386.S b/src/pkg/runtime/cgo/gcc_386.S
index 9abab7ebd..94ba5842f 100644
--- a/src/pkg/runtime/cgo/gcc_386.S
+++ b/src/pkg/runtime/cgo/gcc_386.S
@@ -35,31 +35,6 @@ EXT(crosscall_386):
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:
diff --git a/src/pkg/runtime/cgo/gcc_amd64.S b/src/pkg/runtime/cgo/gcc_amd64.S
index 706ee6b58..81b270195 100644
--- a/src/pkg/runtime/cgo/gcc_amd64.S
+++ b/src/pkg/runtime/cgo/gcc_amd64.S
@@ -19,9 +19,6 @@
* 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):
@@ -45,48 +42,3 @@ EXT(crosscall_amd64):
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)
-
-#if defined(_WIN64)
- // Win64 save RBX, RBP, RDI, RSI, RSP, R12, R13, R14, and R15
- movq %rdi, 0x40(%rsp)
- movq %rsi, 0x48(%rsp)
-
- movq %rdx, 0(%rsp) /* arg */
- movq %r8, 8(%rsp) /* argsize (includes padding) */
-
- call *%rcx /* fn */
-#else
- movq %rsi, 0(%rsp) /* arg */
- movq %rdx, 8(%rsp) /* argsize (includes padding) */
-
- call *%rdi /* fn */
-#endif
-
- movq 0x10(%rsp), %rbx
- movq 0x18(%rsp), %rbp
- movq 0x20(%rsp), %r12
- movq 0x28(%rsp), %r13
- movq 0x30(%rsp), %r14
- movq 0x38(%rsp), %r15
-#if defined(__WIN64)
- movq 0x40(%rsp), %rdi
- movq 0x48(%rsp), %rsi
-#endif
- addq $0x58, %rsp
- ret
diff --git a/src/pkg/runtime/cgo/gcc_arm.S b/src/pkg/runtime/cgo/gcc_arm.S
index 32d862984..809fcb9a0 100644
--- a/src/pkg/runtime/cgo/gcc_arm.S
+++ b/src/pkg/runtime/cgo/gcc_arm.S
@@ -1 +1,36 @@
-/* unimplemented */
+// Copyright 2012 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__)
+#define EXT(s) _##s
+#else
+#define EXT(s) s
+#endif
+
+/*
+ * void crosscall_arm2(void (*fn)(void), void *g, void *m)
+ *
+ * Calling into the 5c tool chain, where all registers are caller save.
+ * Called from standard ARM EABI, where r4-r11 are callee-save, so they
+ * must be saved explicitly.
+ */
+.globl EXT(crosscall_arm2)
+EXT(crosscall_arm2):
+ push {r4, r5, r6, r7, r8, r9, r10, r11, ip, lr}
+ mov r10, r1 // g
+ mov r9, r2 // m
+ mov r3, r0 // save r0, cgo_tls_set_gm will clobber it
+ bl EXT(x_cgo_save_gm) // save current g and m into TLS variable
+ mov lr, pc
+ mov pc, r3
+ pop {r4, r5, r6, r7, r8, r9, r10, r11, ip, pc}
+
+.globl EXT(__stack_chk_fail_local)
+EXT(__stack_chk_fail_local):
+1:
+ b 1b
+
diff --git a/src/pkg/runtime/cgo/gcc_darwin_386.c b/src/pkg/runtime/cgo/gcc_darwin_386.c
index 2c30c666f..ad9fb5abf 100644
--- a/src/pkg/runtime/cgo/gcc_darwin_386.c
+++ b/src/pkg/runtime/cgo/gcc_darwin_386.c
@@ -101,8 +101,8 @@ inittls(void)
pthread_key_delete(tofree[i]);
}
-static void
-xinitcgo(G *g)
+void
+x_cgo_init(G *g)
{
pthread_attr_t attr;
size_t size;
@@ -115,10 +115,9 @@ xinitcgo(G *g)
inittls();
}
-void (*initcgo)(G*) = xinitcgo;
void
-libcgo_sys_thread_start(ThreadStart *ts)
+_cgo_sys_thread_start(ThreadStart *ts)
{
pthread_attr_t attr;
sigset_t ign, oset;
@@ -127,14 +126,14 @@ libcgo_sys_thread_start(ThreadStart *ts)
int err;
sigfillset(&ign);
- sigprocmask(SIG_SETMASK, &ign, &oset);
+ pthread_sigmask(SIG_SETMASK, &ign, &oset);
pthread_attr_init(&attr);
pthread_attr_getstacksize(&attr, &size);
ts->g->stackguard = size;
err = pthread_create(&p, &attr, threadentry, ts);
- sigprocmask(SIG_SETMASK, &oset, nil);
+ pthread_sigmask(SIG_SETMASK, &oset, nil);
if (err != 0) {
fprintf(stderr, "runtime/cgo: pthread_create failed: %s\n", strerror(err));
@@ -153,7 +152,7 @@ threadentry(void *v)
ts.g->stackbase = (uintptr)&ts;
/*
- * libcgo_sys_thread_start set stackguard to stack size;
+ * _cgo_sys_thread_start set stackguard to stack size;
* change to actual guard pointer.
*/
ts.g->stackguard = (uintptr)&ts - ts.g->stackguard + 4096;
diff --git a/src/pkg/runtime/cgo/gcc_darwin_amd64.c b/src/pkg/runtime/cgo/gcc_darwin_amd64.c
index 89dc7a4e8..65d381633 100644
--- a/src/pkg/runtime/cgo/gcc_darwin_amd64.c
+++ b/src/pkg/runtime/cgo/gcc_darwin_amd64.c
@@ -72,7 +72,7 @@ inittls(void)
}
void
-xinitcgo(G *g)
+x_cgo_init(G *g)
{
pthread_attr_t attr;
size_t size;
@@ -85,10 +85,9 @@ xinitcgo(G *g)
inittls();
}
-void (*initcgo)(G*) = xinitcgo;
void
-libcgo_sys_thread_start(ThreadStart *ts)
+_cgo_sys_thread_start(ThreadStart *ts)
{
pthread_attr_t attr;
sigset_t ign, oset;
@@ -97,14 +96,14 @@ libcgo_sys_thread_start(ThreadStart *ts)
int err;
sigfillset(&ign);
- sigprocmask(SIG_SETMASK, &ign, &oset);
+ pthread_sigmask(SIG_SETMASK, &ign, &oset);
pthread_attr_init(&attr);
pthread_attr_getstacksize(&attr, &size);
ts->g->stackguard = size;
err = pthread_create(&p, &attr, threadentry, ts);
- sigprocmask(SIG_SETMASK, &oset, nil);
+ pthread_sigmask(SIG_SETMASK, &oset, nil);
if (err != 0) {
fprintf(stderr, "runtime/cgo: pthread_create failed: %s\n", strerror(err));
@@ -123,7 +122,7 @@ threadentry(void *v)
ts.g->stackbase = (uintptr)&ts;
/*
- * libcgo_sys_thread_start set stackguard to stack size;
+ * _cgo_sys_thread_start set stackguard to stack size;
* change to actual guard pointer.
*/
ts.g->stackguard = (uintptr)&ts - ts.g->stackguard + 4096;
diff --git a/src/pkg/runtime/cgo/gcc_freebsd_386.c b/src/pkg/runtime/cgo/gcc_freebsd_386.c
index 2c97e2a33..7c62a1bc4 100644
--- a/src/pkg/runtime/cgo/gcc_freebsd_386.c
+++ b/src/pkg/runtime/cgo/gcc_freebsd_386.c
@@ -6,12 +6,13 @@
#include <sys/signalvar.h>
#include <pthread.h>
#include <signal.h>
+#include <string.h>
#include "libcgo.h"
static void* threadentry(void*);
-static void
-xinitcgo(G *g)
+void
+x_cgo_init(G *g)
{
pthread_attr_t attr;
size_t size;
@@ -22,10 +23,9 @@ xinitcgo(G *g)
pthread_attr_destroy(&attr);
}
-void (*initcgo)(G*) = xinitcgo;
void
-libcgo_sys_thread_start(ThreadStart *ts)
+_cgo_sys_thread_start(ThreadStart *ts)
{
pthread_attr_t attr;
sigset_t ign, oset;
@@ -60,7 +60,7 @@ threadentry(void *v)
ts.g->stackbase = (uintptr)&ts;
/*
- * libcgo_sys_thread_start set stackguard to stack size;
+ * _cgo_sys_thread_start set stackguard to stack size;
* change to actual guard pointer.
*/
ts.g->stackguard = (uintptr)&ts - ts.g->stackguard + 4096;
diff --git a/src/pkg/runtime/cgo/gcc_freebsd_amd64.c b/src/pkg/runtime/cgo/gcc_freebsd_amd64.c
index 3beb4d7bb..6be8bd251 100644
--- a/src/pkg/runtime/cgo/gcc_freebsd_amd64.c
+++ b/src/pkg/runtime/cgo/gcc_freebsd_amd64.c
@@ -6,12 +6,13 @@
#include <sys/signalvar.h>
#include <pthread.h>
#include <signal.h>
+#include <string.h>
#include "libcgo.h"
static void* threadentry(void*);
-static void
-xinitcgo(G *g)
+void
+x_cgo_init(G *g)
{
pthread_attr_t attr;
size_t size;
@@ -22,10 +23,9 @@ xinitcgo(G *g)
pthread_attr_destroy(&attr);
}
-void (*initcgo)(G*) = xinitcgo;
void
-libcgo_sys_thread_start(ThreadStart *ts)
+_cgo_sys_thread_start(ThreadStart *ts)
{
pthread_attr_t attr;
sigset_t ign, oset;
@@ -61,7 +61,7 @@ threadentry(void *v)
ts.g->stackbase = (uintptr)&ts;
/*
- * libcgo_sys_thread_start set stackguard to stack size;
+ * _cgo_sys_thread_start set stackguard to stack size;
* change to actual guard pointer.
*/
ts.g->stackguard = (uintptr)&ts - ts.g->stackguard + 4096;
diff --git a/src/pkg/runtime/cgo/gcc_freebsd_arm.c b/src/pkg/runtime/cgo/gcc_freebsd_arm.c
new file mode 100644
index 000000000..3bcb0b270
--- /dev/null
+++ b/src/pkg/runtime/cgo/gcc_freebsd_arm.c
@@ -0,0 +1,114 @@
+// Copyright 2012 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*);
+
+// We have to resort to TLS variable to save g(R10) and
+// m(R9). One reason is that external code might trigger
+// SIGSEGV, and our runtime.sigtramp don't even know we
+// are in external code, and will continue to use R10/R9,
+// this might as well result in another SIGSEGV.
+// Note: all three functions will clobber R0, and the last
+// two can be called from 5c ABI code.
+void __aeabi_read_tp(void) __attribute__((naked));
+void x_cgo_save_gm(void) __attribute__((naked));
+void x_cgo_load_gm(void) __attribute__((naked));
+
+void
+__aeabi_read_tp(void)
+{
+ // read @ 0xffff1000
+ __asm__ __volatile__ (
+ "ldr r0, =0xffff1000\n\t"
+ "ldr r0, [r0]\n\t"
+ "mov pc, lr\n\t"
+ );
+}
+
+// g (R10) at 8(TP), m (R9) at 12(TP)
+void
+x_cgo_load_gm(void)
+{
+ __asm__ __volatile__ (
+ "push {lr}\n\t"
+ "bl __aeabi_read_tp\n\t"
+ "ldr r10, [r0, #8]\n\t"
+ "ldr r9, [r0, #12]\n\t"
+ "pop {pc}\n\t"
+ );
+}
+
+void
+x_cgo_save_gm(void)
+{
+ __asm__ __volatile__ (
+ "push {lr}\n\t"
+ "bl __aeabi_read_tp\n\t"
+ "str r10, [r0, #8]\n\t"
+ "str r9, [r0, #12]\n\t"
+ "pop {pc}\n\t"
+ );
+}
+
+void
+x_cgo_init(G *g)
+{
+ pthread_attr_t attr;
+ size_t size;
+ x_cgo_save_gm(); // save g and m for the initial thread
+
+ pthread_attr_init(&attr);
+ pthread_attr_getstacksize(&attr, &size);
+ g->stackguard = (uintptr)&attr - size + 4096;
+ pthread_attr_destroy(&attr);
+}
+
+
+void
+_cgo_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();
+ }
+}
+
+extern void crosscall_arm2(void (*fn)(void), void *g, void *m);
+static void*
+threadentry(void *v)
+{
+ ThreadStart ts;
+
+ ts = *(ThreadStart*)v;
+ free(v);
+
+ ts.g->stackbase = (uintptr)&ts;
+
+ /*
+ * _cgo_sys_thread_start set stackguard to stack size;
+ * change to actual guard pointer.
+ */
+ ts.g->stackguard = (uintptr)&ts - ts.g->stackguard + 4096 * 2;
+
+ crosscall_arm2(ts.fn, (void *)ts.g, (void *)ts.m);
+ return nil;
+}
diff --git a/src/pkg/runtime/cgo/gcc_linux_386.c b/src/pkg/runtime/cgo/gcc_linux_386.c
index 7d84acc11..9357a63f7 100644
--- a/src/pkg/runtime/cgo/gcc_linux_386.c
+++ b/src/pkg/runtime/cgo/gcc_linux_386.c
@@ -9,8 +9,8 @@
static void *threadentry(void*);
-static void
-xinitcgo(G *g)
+void
+x_cgo_init(G *g)
{
pthread_attr_t attr;
size_t size;
@@ -21,10 +21,9 @@ xinitcgo(G *g)
pthread_attr_destroy(&attr);
}
-void (*initcgo)(G*) = xinitcgo;
void
-libcgo_sys_thread_start(ThreadStart *ts)
+_cgo_sys_thread_start(ThreadStart *ts)
{
pthread_attr_t attr;
sigset_t ign, oset;
@@ -64,7 +63,7 @@ threadentry(void *v)
ts.g->stackbase = (uintptr)&ts;
/*
- * libcgo_sys_thread_start set stackguard to stack size;
+ * _cgo_sys_thread_start set stackguard to stack size;
* change to actual guard pointer.
*/
ts.g->stackguard = (uintptr)&ts - ts.g->stackguard + 4096;
diff --git a/src/pkg/runtime/cgo/gcc_linux_amd64.c b/src/pkg/runtime/cgo/gcc_linux_amd64.c
index 28cbf78c5..bc76117d3 100644
--- a/src/pkg/runtime/cgo/gcc_linux_amd64.c
+++ b/src/pkg/runtime/cgo/gcc_linux_amd64.c
@@ -10,7 +10,7 @@
static void* threadentry(void*);
void
-xinitcgo(G* g)
+x_cgo_init(G* g)
{
pthread_attr_t attr;
size_t size;
@@ -21,10 +21,9 @@ xinitcgo(G* g)
pthread_attr_destroy(&attr);
}
-void (*initcgo)(G*) = xinitcgo;
void
-libcgo_sys_thread_start(ThreadStart *ts)
+_cgo_sys_thread_start(ThreadStart *ts)
{
pthread_attr_t attr;
sigset_t ign, oset;
@@ -59,7 +58,7 @@ threadentry(void *v)
ts.g->stackbase = (uintptr)&ts;
/*
- * libcgo_sys_thread_start set stackguard to stack size;
+ * _cgo_sys_thread_start set stackguard to stack size;
* change to actual guard pointer.
*/
ts.g->stackguard = (uintptr)&ts - ts.g->stackguard + 4096;
diff --git a/src/pkg/runtime/cgo/gcc_linux_arm.c b/src/pkg/runtime/cgo/gcc_linux_arm.c
index 8397c75bb..46a1126ad 100644
--- a/src/pkg/runtime/cgo/gcc_linux_arm.c
+++ b/src/pkg/runtime/cgo/gcc_linux_arm.c
@@ -2,19 +2,113 @@
// 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
-xinitcgo(G *g)
+static void *threadentry(void*);
+
+// We have to resort to TLS variable to save g(R10) and
+// m(R9). One reason is that external code might trigger
+// SIGSEGV, and our runtime.sigtramp don't even know we
+// are in external code, and will continue to use R10/R9,
+// this might as well result in another SIGSEGV.
+// Note: all three functions will clobber R0, and the last
+// two can be called from 5c ABI code.
+void __aeabi_read_tp(void) __attribute__((naked));
+void x_cgo_save_gm(void) __attribute__((naked));
+void x_cgo_load_gm(void) __attribute__((naked));
+
+void
+__aeabi_read_tp(void)
+{
+ // b __kuser_get_tls @ 0xffff0fe0
+ __asm__ __volatile__ (
+ "mvn r0, #0xf000\n\t"
+ "sub pc, r0, #31\n\t"
+ "nop\n\tnop\n\t"
+ );
+}
+
+// g (R10) at 8(TP), m (R9) at 12(TP)
+void
+x_cgo_load_gm(void)
+{
+ __asm__ __volatile__ (
+ "push {lr}\n\t"
+ "bl __aeabi_read_tp\n\t"
+ "ldr r10, [r0, #8]\n\t"
+ "ldr r9, [r0, #12]\n\t"
+ "pop {pc}\n\t"
+ );
+}
+
+void
+x_cgo_save_gm(void)
+{
+ __asm__ __volatile__ (
+ "push {lr}\n\t"
+ "bl __aeabi_read_tp\n\t"
+ "str r10, [r0, #8]\n\t"
+ "str r9, [r0, #12]\n\t"
+ "pop {pc}\n\t"
+ );
+}
+
+void
+x_cgo_init(G *g)
{
- // unimplemented
+ pthread_attr_t attr;
+ size_t size;
+ x_cgo_save_gm(); // save g and m for the initial thread
+
+ pthread_attr_init(&attr);
+ pthread_attr_getstacksize(&attr, &size);
+ g->stackguard = (uintptr)&attr - size + 4096;
+ pthread_attr_destroy(&attr);
}
-void (*initcgo)(G*) = xinitcgo;
void
-libcgo_sys_thread_start(ThreadStart *ts)
+_cgo_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();
+ }
+}
+
+extern void crosscall_arm2(void (*fn)(void), void *g, void *m);
+static void*
+threadentry(void *v)
{
- // unimplemented
- *(int*)0 = 0;
+ ThreadStart ts;
+
+ ts = *(ThreadStart*)v;
+ free(v);
+
+ ts.g->stackbase = (uintptr)&ts;
+
+ /*
+ * _cgo_sys_thread_start set stackguard to stack size;
+ * change to actual guard pointer.
+ */
+ ts.g->stackguard = (uintptr)&ts - ts.g->stackguard + 4096 * 2;
+
+ crosscall_arm2(ts.fn, (void *)ts.g, (void *)ts.m);
+ return nil;
}
diff --git a/src/pkg/runtime/cgo/gcc_netbsd_386.c b/src/pkg/runtime/cgo/gcc_netbsd_386.c
new file mode 100644
index 000000000..09b271df4
--- /dev/null
+++ b/src/pkg/runtime/cgo/gcc_netbsd_386.c
@@ -0,0 +1,80 @@
+// 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 <sys/types.h>
+#include <pthread.h>
+#include <signal.h>
+#include <string.h>
+#include "libcgo.h"
+
+static void* threadentry(void*);
+
+void
+x_cgo_init(G *g)
+{
+ pthread_attr_t attr;
+ size_t size;
+
+ pthread_attr_init(&attr);
+ pthread_attr_getstacksize(&attr, &size);
+ g->stackguard = (uintptr)&attr - size + 4096;
+ pthread_attr_destroy(&attr);
+}
+
+
+void
+_cgo_sys_thread_start(ThreadStart *ts)
+{
+ pthread_attr_t attr;
+ sigset_t ign, oset;
+ pthread_t p;
+ size_t size;
+ int err;
+
+ sigfillset(&ign);
+ sigprocmask(SIG_SETMASK, &ign, &oset);
+
+ pthread_attr_init(&attr);
+ pthread_attr_getstacksize(&attr, &size);
+ ts->g->stackguard = size;
+ err = pthread_create(&p, &attr, threadentry, ts);
+
+ sigprocmask(SIG_SETMASK, &oset, nil);
+
+ 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;
+
+ /*
+ * _cgo_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 NetBSD/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/gcc_netbsd_amd64.c b/src/pkg/runtime/cgo/gcc_netbsd_amd64.c
new file mode 100644
index 000000000..080c59ba4
--- /dev/null
+++ b/src/pkg/runtime/cgo/gcc_netbsd_amd64.c
@@ -0,0 +1,80 @@
+// 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 <sys/types.h>
+#include <pthread.h>
+#include <signal.h>
+#include <string.h>
+#include "libcgo.h"
+
+static void* threadentry(void*);
+
+void
+x_cgo_init(G *g)
+{
+ pthread_attr_t attr;
+ size_t size;
+
+ pthread_attr_init(&attr);
+ pthread_attr_getstacksize(&attr, &size);
+ g->stackguard = (uintptr)&attr - size + 4096;
+ pthread_attr_destroy(&attr);
+}
+
+
+void
+_cgo_sys_thread_start(ThreadStart *ts)
+{
+ pthread_attr_t attr;
+ sigset_t ign, oset;
+ pthread_t p;
+ size_t size;
+ int err;
+
+ sigfillset(&ign);
+ sigprocmask(SIG_SETMASK, &ign, &oset);
+
+ pthread_attr_init(&attr);
+ pthread_attr_getstacksize(&attr, &size);
+
+ ts->g->stackguard = size;
+ err = pthread_create(&p, &attr, threadentry, ts);
+
+ sigprocmask(SIG_SETMASK, &oset, nil);
+
+ 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;
+
+ /*
+ * _cgo_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 NetBSD/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/gcc_netbsd_arm.c b/src/pkg/runtime/cgo/gcc_netbsd_arm.c
new file mode 100644
index 000000000..d93b531e7
--- /dev/null
+++ b/src/pkg/runtime/cgo/gcc_netbsd_arm.c
@@ -0,0 +1,122 @@
+// Copyright 2013 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 <sys/types.h>
+#include <pthread.h>
+#include <signal.h>
+#include <string.h>
+#include "libcgo.h"
+
+static void *threadentry(void*);
+
+// We have to resort to TLS variable to save g(R10) and
+// m(R9). One reason is that external code might trigger
+// SIGSEGV, and our runtime.sigtramp don't even know we
+// are in external code, and will continue to use R10/R9,
+// this might as well result in another SIGSEGV.
+// Note: all three functions will clobber R0, and the last
+// two can be called from 5c ABI code.
+void __aeabi_read_tp(void) __attribute__((naked));
+void x_cgo_save_gm(void) __attribute__((naked));
+void x_cgo_load_gm(void) __attribute__((naked));
+
+void
+__aeabi_read_tp(void)
+{
+ // this function is only allowed to clobber r0
+ __asm__ __volatile__ (
+ "mrc p15, 0, r0, c13, c0, 3\n\t"
+ "cmp r0, #0\n\t"
+ "movne pc, lr\n\t"
+ "push {r1,r2,r3,r12}\n\t"
+ "svc 0x00a0013c\n\t" // _lwp_getprivate
+ "pop {r1,r2,r3,r12}\n\t"
+ "mov pc, lr\n\t"
+ );
+}
+
+// g (R10) at 8(TP), m (R9) at 12(TP)
+void
+x_cgo_load_gm(void)
+{
+ __asm__ __volatile__ (
+ "push {lr}\n\t"
+ "bl __aeabi_read_tp\n\t"
+ "ldr r10, [r0, #8]\n\t"
+ "ldr r9, [r0, #12]\n\t"
+ "pop {pc}\n\t"
+ );
+}
+
+void
+x_cgo_save_gm(void)
+{
+ __asm__ __volatile__ (
+ "push {lr}\n\t"
+ "bl __aeabi_read_tp\n\t"
+ "str r10, [r0, #8]\n\t"
+ "str r9, [r0, #12]\n\t"
+ "pop {pc}\n\t"
+ );
+}
+
+void
+x_cgo_init(G *g)
+{
+ pthread_attr_t attr;
+ size_t size;
+ x_cgo_save_gm(); // save g and m for the initial thread
+
+ pthread_attr_init(&attr);
+ pthread_attr_getstacksize(&attr, &size);
+ g->stackguard = (uintptr)&attr - size + 4096;
+ pthread_attr_destroy(&attr);
+}
+
+
+void
+_cgo_sys_thread_start(ThreadStart *ts)
+{
+ pthread_attr_t attr;
+ sigset_t ign, oset;
+ pthread_t p;
+ size_t size;
+ int err;
+
+ sigfillset(&ign);
+ sigprocmask(SIG_SETMASK, &ign, &oset);
+
+ pthread_attr_init(&attr);
+ pthread_attr_getstacksize(&attr, &size);
+ ts->g->stackguard = size;
+ err = pthread_create(&p, &attr, threadentry, ts);
+
+ sigprocmask(SIG_SETMASK, &oset, nil);
+
+ if (err != 0) {
+ fprintf(stderr, "runtime/cgo: pthread_create failed: %s\n", strerror(err));
+ abort();
+ }
+}
+
+extern void crosscall_arm2(void (*fn)(void), void *g, void *m);
+static void*
+threadentry(void *v)
+{
+ ThreadStart ts;
+
+ ts = *(ThreadStart*)v;
+ free(v);
+
+ ts.g->stackbase = (uintptr)&ts;
+
+ /*
+ * _cgo_sys_thread_start set stackguard to stack size;
+ * change to actual guard pointer.
+ */
+ ts.g->stackguard = (uintptr)&ts - ts.g->stackguard + 4096 * 2;
+
+ crosscall_arm2(ts.fn, (void *)ts.g, (void *)ts.m);
+ return nil;
+}
diff --git a/src/pkg/runtime/cgo/gcc_openbsd_386.c b/src/pkg/runtime/cgo/gcc_openbsd_386.c
new file mode 100644
index 000000000..86c1365ad
--- /dev/null
+++ b/src/pkg/runtime/cgo/gcc_openbsd_386.c
@@ -0,0 +1,169 @@
+// 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 <sys/types.h>
+#include <dlfcn.h>
+#include <errno.h>
+#include <pthread.h>
+#include <signal.h>
+#include <string.h>
+#include "libcgo.h"
+
+static void* threadentry(void*);
+
+// TCB_SIZE is sizeof(struct thread_control_block),
+// as defined in /usr/src/lib/librthread/tcb.h
+#define TCB_SIZE (4 * sizeof(void *))
+#define TLS_SIZE (2 * sizeof(void *))
+
+void *__get_tcb(void);
+void __set_tcb(void *);
+
+static int (*sys_pthread_create)(pthread_t *thread, const pthread_attr_t *attr,
+ void *(*start_routine)(void *), void *arg);
+
+struct thread_args {
+ void *(*func)(void *);
+ void *arg;
+};
+
+static void
+tcb_fixup(int mainthread)
+{
+ void *newtcb, *oldtcb;
+
+ // The OpenBSD ld.so(1) does not currently support PT_TLS. As a result,
+ // we need to allocate our own TLS space while preserving the existing
+ // TCB that has been setup via librthread.
+
+ newtcb = malloc(TCB_SIZE + TLS_SIZE);
+ if(newtcb == NULL)
+ abort();
+
+ // The signal trampoline expects the TLS slots to be zeroed.
+ bzero(newtcb, TLS_SIZE);
+
+ oldtcb = __get_tcb();
+ bcopy(oldtcb, newtcb + TLS_SIZE, TCB_SIZE);
+ __set_tcb(newtcb + TLS_SIZE);
+
+ // The main thread TCB is a static allocation - do not try to free it.
+ if(!mainthread)
+ free(oldtcb);
+}
+
+static void *
+thread_start_wrapper(void *arg)
+{
+ struct thread_args args = *(struct thread_args *)arg;
+
+ free(arg);
+ tcb_fixup(0);
+
+ return args.func(args.arg);
+}
+
+int
+pthread_create(pthread_t *thread, const pthread_attr_t *attr,
+ void *(*start_routine)(void *), void *arg)
+{
+ struct thread_args *p;
+
+ p = malloc(sizeof(*p));
+ if(p == NULL) {
+ errno = ENOMEM;
+ return -1;
+ }
+ p->func = start_routine;
+ p->arg = arg;
+
+ return sys_pthread_create(thread, attr, thread_start_wrapper, p);
+}
+
+void
+x_cgo_init(G *g)
+{
+ pthread_attr_t attr;
+ size_t size;
+ void *handle;
+
+ pthread_attr_init(&attr);
+ pthread_attr_getstacksize(&attr, &size);
+ g->stackguard = (uintptr)&attr - size + 4096;
+ pthread_attr_destroy(&attr);
+
+ // Locate symbol for the system pthread_create function.
+ handle = dlopen("libpthread.so", RTLD_LAZY);
+ if(handle == NULL) {
+ fprintf(stderr, "dlopen: failed to load libpthread: %s\n", dlerror());
+ abort();
+ }
+ sys_pthread_create = dlsym(handle, "pthread_create");
+ if(sys_pthread_create == NULL) {
+ fprintf(stderr, "dlsym: failed to find pthread_create: %s\n", dlerror());
+ abort();
+ }
+ dlclose(handle);
+
+ tcb_fixup(1);
+}
+
+
+void
+_cgo_sys_thread_start(ThreadStart *ts)
+{
+ pthread_attr_t attr;
+ sigset_t ign, oset;
+ pthread_t p;
+ size_t size;
+ int err;
+
+ sigfillset(&ign);
+ sigprocmask(SIG_SETMASK, &ign, &oset);
+
+ pthread_attr_init(&attr);
+ pthread_attr_getstacksize(&attr, &size);
+ ts->g->stackguard = size;
+ err = sys_pthread_create(&p, &attr, threadentry, ts);
+
+ sigprocmask(SIG_SETMASK, &oset, nil);
+
+ if (err != 0) {
+ fprintf(stderr, "runtime/cgo: pthread_create failed: %s\n", strerror(err));
+ abort();
+ }
+}
+
+static void*
+threadentry(void *v)
+{
+ ThreadStart ts;
+
+ tcb_fixup(0);
+
+ ts = *(ThreadStart*)v;
+ free(v);
+
+ ts.g->stackbase = (uintptr)&ts;
+
+ /*
+ * _cgo_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 OpenBSD/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/gcc_openbsd_amd64.c b/src/pkg/runtime/cgo/gcc_openbsd_amd64.c
new file mode 100644
index 000000000..d3a5e36b0
--- /dev/null
+++ b/src/pkg/runtime/cgo/gcc_openbsd_amd64.c
@@ -0,0 +1,169 @@
+// 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 <sys/types.h>
+#include <dlfcn.h>
+#include <errno.h>
+#include <pthread.h>
+#include <signal.h>
+#include <string.h>
+#include "libcgo.h"
+
+static void* threadentry(void*);
+
+// TCB_SIZE is sizeof(struct thread_control_block),
+// as defined in /usr/src/lib/librthread/tcb.h
+#define TCB_SIZE (4 * sizeof(void *))
+#define TLS_SIZE (2 * sizeof(void *))
+
+void *__get_tcb(void);
+void __set_tcb(void *);
+
+static int (*sys_pthread_create)(pthread_t *thread, const pthread_attr_t *attr,
+ void *(*start_routine)(void *), void *arg);
+
+struct thread_args {
+ void *(*func)(void *);
+ void *arg;
+};
+
+static void
+tcb_fixup(int mainthread)
+{
+ void *newtcb, *oldtcb;
+
+ // The OpenBSD ld.so(1) does not currently support PT_TLS. As a result,
+ // we need to allocate our own TLS space while preserving the existing
+ // TCB that has been setup via librthread.
+
+ newtcb = malloc(TCB_SIZE + TLS_SIZE);
+ if(newtcb == NULL)
+ abort();
+
+ // The signal trampoline expects the TLS slots to be zeroed.
+ bzero(newtcb, TLS_SIZE);
+
+ oldtcb = __get_tcb();
+ bcopy(oldtcb, newtcb + TLS_SIZE, TCB_SIZE);
+ __set_tcb(newtcb + TLS_SIZE);
+
+ // The main thread TCB is a static allocation - do not try to free it.
+ if(!mainthread)
+ free(oldtcb);
+}
+
+static void *
+thread_start_wrapper(void *arg)
+{
+ struct thread_args args = *(struct thread_args *)arg;
+
+ free(arg);
+ tcb_fixup(0);
+
+ return args.func(args.arg);
+}
+
+int
+pthread_create(pthread_t *thread, const pthread_attr_t *attr,
+ void *(*start_routine)(void *), void *arg)
+{
+ struct thread_args *p;
+
+ p = malloc(sizeof(*p));
+ if(p == NULL) {
+ errno = ENOMEM;
+ return -1;
+ }
+ p->func = start_routine;
+ p->arg = arg;
+
+ return sys_pthread_create(thread, attr, thread_start_wrapper, p);
+}
+
+void
+x_cgo_init(G *g)
+{
+ pthread_attr_t attr;
+ size_t size;
+ void *handle;
+
+ pthread_attr_init(&attr);
+ pthread_attr_getstacksize(&attr, &size);
+ g->stackguard = (uintptr)&attr - size + 4096;
+ pthread_attr_destroy(&attr);
+
+ // Locate symbol for the system pthread_create function.
+ handle = dlopen("libpthread.so", RTLD_LAZY);
+ if(handle == NULL) {
+ fprintf(stderr, "dlopen: failed to load libpthread: %s\n", dlerror());
+ abort();
+ }
+ sys_pthread_create = dlsym(handle, "pthread_create");
+ if(sys_pthread_create == NULL) {
+ fprintf(stderr, "dlsym: failed to find pthread_create: %s\n", dlerror());
+ abort();
+ }
+ dlclose(handle);
+
+ tcb_fixup(1);
+}
+
+
+void
+_cgo_sys_thread_start(ThreadStart *ts)
+{
+ pthread_attr_t attr;
+ sigset_t ign, oset;
+ pthread_t p;
+ size_t size;
+ int err;
+
+ sigfillset(&ign);
+ sigprocmask(SIG_SETMASK, &ign, &oset);
+
+ pthread_attr_init(&attr);
+ pthread_attr_getstacksize(&attr, &size);
+
+ ts->g->stackguard = size;
+ err = sys_pthread_create(&p, &attr, threadentry, ts);
+
+ sigprocmask(SIG_SETMASK, &oset, nil);
+
+ if (err != 0) {
+ fprintf(stderr, "runtime/cgo: pthread_create failed: %s\n", strerror(err));
+ abort();
+ }
+}
+
+static void*
+threadentry(void *v)
+{
+ ThreadStart ts;
+
+ tcb_fixup(0);
+
+ ts = *(ThreadStart*)v;
+ free(v);
+
+ ts.g->stackbase = (uintptr)&ts;
+
+ /*
+ * _cgo_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 OpenBSD/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/gcc_setenv.c b/src/pkg/runtime/cgo/gcc_setenv.c
index 7da4ad915..a0938166d 100644
--- a/src/pkg/runtime/cgo/gcc_setenv.c
+++ b/src/pkg/runtime/cgo/gcc_setenv.c
@@ -1,4 +1,4 @@
-// Copyright 20111 The Go Authors. All rights reserved.
+// 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.
@@ -9,10 +9,8 @@
#include <stdlib.h>
/* Stub for calling setenv */
-static void
-xlibcgo_setenv(char **arg)
+void
+x_cgo_setenv(char **arg)
{
setenv(arg[0], arg[1], 1);
}
-
-void (*libcgo_setenv)(char**) = xlibcgo_setenv;
diff --git a/src/pkg/runtime/cgo/gcc_util.c b/src/pkg/runtime/cgo/gcc_util.c
index e06b6f64d..20913d736 100644
--- a/src/pkg/runtime/cgo/gcc_util.c
+++ b/src/pkg/runtime/cgo/gcc_util.c
@@ -5,7 +5,7 @@
#include "libcgo.h"
/* Stub for calling malloc from Go */
-static void
+void
x_cgo_malloc(void *p)
{
struct a {
@@ -16,10 +16,8 @@ x_cgo_malloc(void *p)
a->ret = malloc(a->n);
}
-void (*_cgo_malloc)(void*) = x_cgo_malloc;
-
/* Stub for calling free from Go */
-static void
+void
x_cgo_free(void *p)
{
struct a {
@@ -29,11 +27,9 @@ x_cgo_free(void *p)
free(a->arg);
}
-void (*_cgo_free)(void*) = x_cgo_free;
-
/* Stub for creating a new thread */
-static void
-xlibcgo_thread_start(ThreadStart *arg)
+void
+x_cgo_thread_start(ThreadStart *arg)
{
ThreadStart *ts;
@@ -45,7 +41,5 @@ xlibcgo_thread_start(ThreadStart *arg)
}
*ts = *arg;
- libcgo_sys_thread_start(ts); /* OS-dependent half */
+ _cgo_sys_thread_start(ts); /* OS-dependent half */
}
-
-void (*libcgo_thread_start)(ThreadStart*) = xlibcgo_thread_start;
diff --git a/src/pkg/runtime/cgo/gcc_windows_386.c b/src/pkg/runtime/cgo/gcc_windows_386.c
index 2b940d362..02eab12e5 100644
--- a/src/pkg/runtime/cgo/gcc_windows_386.c
+++ b/src/pkg/runtime/cgo/gcc_windows_386.c
@@ -4,31 +4,31 @@
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
+#include <process.h>
#include "libcgo.h"
-static void *threadentry(void*);
+static void threadentry(void*);
/* 1MB is default stack size for 32-bit Windows.
Allocation granularity on Windows is typically 64 KB.
The constant is also hardcoded in cmd/ld/pe.c (keep synchronized). */
#define STACKSIZE (1*1024*1024)
-static void
-xinitcgo(G *g)
+void
+x_cgo_init(G *g)
{
int tmp;
g->stackguard = (uintptr)&tmp - STACKSIZE + 8*1024;
}
-void (*initcgo)(G*) = xinitcgo;
void
-libcgo_sys_thread_start(ThreadStart *ts)
+_cgo_sys_thread_start(ThreadStart *ts)
{
_beginthread(threadentry, 0, ts);
}
-static void*
+static void
threadentry(void *v)
{
ThreadStart ts;
@@ -55,5 +55,4 @@ threadentry(void *v)
crosscall_386(ts.fn);
LocalFree(tls0);
- return nil;
}
diff --git a/src/pkg/runtime/cgo/gcc_windows_amd64.c b/src/pkg/runtime/cgo/gcc_windows_amd64.c
index 0d2f5d233..f7695a1cc 100644
--- a/src/pkg/runtime/cgo/gcc_windows_amd64.c
+++ b/src/pkg/runtime/cgo/gcc_windows_amd64.c
@@ -4,31 +4,31 @@
#define WIN64_LEAN_AND_MEAN
#include <windows.h>
+#include <process.h>
#include "libcgo.h"
-static void *threadentry(void*);
+static void threadentry(void*);
/* 2MB is default stack size for 64-bit Windows.
Allocation granularity on Windows is typically 64 KB.
The constant is also hardcoded in cmd/ld/pe.c (keep synchronized). */
#define STACKSIZE (2*1024*1024)
-static void
-xinitcgo(G *g)
+void
+x_cgo_init(G *g)
{
int tmp;
g->stackguard = (uintptr)&tmp - STACKSIZE + 8*1024;
}
-void (*initcgo)(G*) = xinitcgo;
void
-libcgo_sys_thread_start(ThreadStart *ts)
+_cgo_sys_thread_start(ThreadStart *ts)
{
_beginthread(threadentry, 0, ts);
}
-static void*
+static void
threadentry(void *v)
{
ThreadStart ts;
@@ -53,5 +53,4 @@ threadentry(void *v)
);
crosscall_amd64(ts.fn);
- return nil;
}
diff --git a/src/pkg/runtime/cgo/libcgo.h b/src/pkg/runtime/cgo/libcgo.h
index c31d19d76..41a371c27 100644
--- a/src/pkg/runtime/cgo/libcgo.h
+++ b/src/pkg/runtime/cgo/libcgo.h
@@ -26,7 +26,7 @@ struct G
};
/*
- * Arguments to the libcgo_thread_start call.
+ * Arguments to the _cgo_thread_start call.
* Also known to ../pkg/runtime/runtime.h.
*/
typedef struct ThreadStart ThreadStart;
@@ -40,14 +40,14 @@ struct ThreadStart
/*
* Called by 5c/6c/8c world.
* Makes a local copy of the ThreadStart and
- * calls libcgo_sys_thread_start(ts).
+ * calls _cgo_sys_thread_start(ts).
*/
-extern void (*libcgo_thread_start)(ThreadStart *ts);
+extern void (*_cgo_thread_start)(ThreadStart *ts);
/*
* Creates the new operating system thread (OS, arch dependent).
*/
-void libcgo_sys_thread_start(ThreadStart *ts);
+void _cgo_sys_thread_start(ThreadStart *ts);
/*
* Call fn in the 6c world.
diff --git a/src/pkg/runtime/cgo/netbsd.c b/src/pkg/runtime/cgo/netbsd.c
new file mode 100644
index 000000000..b6403f686
--- /dev/null
+++ b/src/pkg/runtime/cgo/netbsd.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 NetBSD 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/openbsd.c b/src/pkg/runtime/cgo/openbsd.c
new file mode 100644
index 000000000..84e9f9eff
--- /dev/null
+++ b/src/pkg/runtime/cgo/openbsd.c
@@ -0,0 +1,21 @@
+// 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, __progname and __guard_local, because
+// we don't link against the standard OpenBSD crt0.o and
+// the libc dynamic library needs them.
+
+char *environ[1];
+char *__progname;
+long __guard_local;
+
+#pragma dynexport environ environ
+#pragma dynexport __progname __progname
+
+// This is normally marked as hidden and placed in the
+// .openbsd.randomdata section.
+#pragma dynexport __guard_local __guard_local
+
+// We override pthread_create to support PT_TLS.
+#pragma dynexport pthread_create pthread_create
diff --git a/src/pkg/runtime/cgo/setenv.c b/src/pkg/runtime/cgo/setenv.c
new file mode 100644
index 000000000..4c47cdb00
--- /dev/null
+++ b/src/pkg/runtime/cgo/setenv.c
@@ -0,0 +1,10 @@
+// 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.
+
+// +build darwin freebsd linux netbsd openbsd
+
+#pragma cgo_import_static x_cgo_setenv
+
+void x_cgo_setenv(char**);
+void (*_cgo_setenv)(char**) = x_cgo_setenv;