diff options
author | Ondřej Surý <ondrej@sury.org> | 2011-09-13 13:13:40 +0200 |
---|---|---|
committer | Ondřej Surý <ondrej@sury.org> | 2011-09-13 13:13:40 +0200 |
commit | 5ff4c17907d5b19510a62e08fd8d3b11e62b431d (patch) | |
tree | c0650497e988f47be9c6f2324fa692a52dea82e1 /src/pkg/runtime/cgo | |
parent | 80f18fc933cf3f3e829c5455a1023d69f7b86e52 (diff) | |
download | golang-5ff4c17907d5b19510a62e08fd8d3b11e62b431d.tar.gz |
Imported Upstream version 60upstream/60
Diffstat (limited to 'src/pkg/runtime/cgo')
-rwxr-xr-x | src/pkg/runtime/cgo/386.S | 67 | ||||
-rw-r--r-- | src/pkg/runtime/cgo/Makefile | 60 | ||||
-rw-r--r-- | src/pkg/runtime/cgo/amd64.S | 73 | ||||
-rw-r--r-- | src/pkg/runtime/cgo/arm.S | 1 | ||||
-rw-r--r-- | src/pkg/runtime/cgo/callbacks.c | 73 | ||||
-rw-r--r-- | src/pkg/runtime/cgo/cgo.go | 17 | ||||
-rw-r--r-- | src/pkg/runtime/cgo/darwin_386.c | 149 | ||||
-rw-r--r-- | src/pkg/runtime/cgo/darwin_amd64.c | 119 | ||||
-rw-r--r-- | src/pkg/runtime/cgo/freebsd.c | 13 | ||||
-rw-r--r-- | src/pkg/runtime/cgo/freebsd_386.c | 64 | ||||
-rw-r--r-- | src/pkg/runtime/cgo/freebsd_amd64.c | 63 | ||||
-rw-r--r-- | src/pkg/runtime/cgo/iscgo.c | 14 | ||||
-rw-r--r-- | src/pkg/runtime/cgo/libcgo.h | 60 | ||||
-rw-r--r-- | src/pkg/runtime/cgo/linux_386.c | 73 | ||||
-rw-r--r-- | src/pkg/runtime/cgo/linux_amd64.c | 63 | ||||
-rw-r--r-- | src/pkg/runtime/cgo/linux_arm.c | 19 | ||||
-rw-r--r-- | src/pkg/runtime/cgo/setenv.c | 16 | ||||
-rw-r--r-- | src/pkg/runtime/cgo/util.c | 51 | ||||
-rwxr-xr-x | src/pkg/runtime/cgo/windows_386.c | 62 | ||||
-rwxr-xr-x | src/pkg/runtime/cgo/windows_amd64.c | 60 |
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; +} |