1
0
mirror of https://github.com/golang/go synced 2024-11-22 13:14:55 -07:00

cgo: enable cgo on openbsd

Enable cgo on OpenBSD.

The OpenBSD ld.so(1) does not currently support PT_TLS sections. Work
around this by fixing up the TCB that has been provided by librthread
and reallocating a TCB with additional space for TLS. Also provide a
wrapper for pthread_create, allowing zeroed TLS to be allocated for
threads created externally to Go.

Joint work with Shenghou Ma (minux).

Requires change 6846064.

Fixes #3205.

R=golang-dev, minux.ma, iant, rsc, iant
CC=golang-dev
https://golang.org/cl/6853059
This commit is contained in:
Joel Sing 2012-12-21 01:43:19 +11:00
parent e6ca125f14
commit 708db79011
9 changed files with 390 additions and 3 deletions

View File

@ -45,6 +45,10 @@ fi
if [ "$goos" == "netbsd" ]; then if [ "$goos" == "netbsd" ]; then
c_go_cgo="" c_go_cgo=""
fi fi
# cgo3 and cgo4 don't run on openbsd, since cgo cannot handle stdout correctly
if [ "$goos" == "openbsd" ]; then
c_go_cgo="cgo1 cgo2"
fi
timeout=" timeout="
timeout1 timeout1

View File

@ -56,6 +56,7 @@ int add(int x, int y) {
*/ */
import "C" import "C"
import ( import (
"runtime"
"syscall" "syscall"
"testing" "testing"
"unsafe" "unsafe"
@ -119,7 +120,12 @@ func testErrno(t *testing.T) {
func testMultipleAssign(t *testing.T) { func testMultipleAssign(t *testing.T) {
p := C.CString("234") p := C.CString("234")
n, m := C.strtol(p, nil, 345), C.strtol(p, nil, 10) n, m := C.strtol(p, nil, 345), C.strtol(p, nil, 10)
if n != 0 || m != 234 { if runtime.GOOS == "openbsd" {
// Bug in OpenBSD strtol(3) - base > 36 succeeds.
if (n != 0 && n != 239089) || m != 234 {
t.Fatal("Strtol x2: ", n, m)
}
} else if n != 0 || m != 234 {
t.Fatal("Strtol x2: ", n, m) t.Fatal("Strtol x2: ", n, m)
} }
C.free(unsafe.Pointer(p)) C.free(unsafe.Pointer(p))

View File

@ -222,6 +222,8 @@ var cgoEnabled = map[string]bool{
"linux/arm": true, "linux/arm": true,
"netbsd/386": true, "netbsd/386": true,
"netbsd/amd64": true, "netbsd/amd64": true,
"openbsd/386": true,
"openbsd/amd64": true,
"windows/386": true, "windows/386": true,
"windows/amd64": true, "windows/amd64": true,
} }

View File

@ -0,0 +1,14 @@
// 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.
package net
/*
#include <netdb.h>
*/
import "C"
func cgoAddrInfoFlags() C.int {
return C.AI_CANONNAME
}

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
// +build darwin freebsd linux netbsd // +build darwin freebsd linux netbsd openbsd
package net package net

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
// +build darwin freebsd linux netbsd // +build darwin freebsd linux netbsd openbsd
// +build cgo // +build cgo
package user package user

View File

@ -0,0 +1,170 @@
// 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);
}
static void
xinitcgo(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 (*initcgo)(G*) = xinitcgo;
void
libcgo_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;
/*
* 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 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;
}

View File

@ -0,0 +1,170 @@
// 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);
}
static void
xinitcgo(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 (*initcgo)(G*) = xinitcgo;
void
libcgo_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;
/*
* 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 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;
}

View File

@ -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