diff --git a/src/runtime/cgo/gcc_openbsd_386.c b/src/runtime/cgo/gcc_openbsd_386.c index 22941a4c6d..1bc61ff708 100644 --- a/src/runtime/cgo/gcc_openbsd_386.c +++ b/src/runtime/cgo/gcc_openbsd_386.c @@ -13,9 +13,15 @@ static void* threadentry(void*); static void (*setg_gcc)(void*); -// TCB_SIZE is sizeof(struct thread_control_block), -// as defined in /usr/src/lib/librthread/tcb.h +// TCB_SIZE is sizeof(struct thread_control_block), as defined in +// /usr/src/lib/librthread/tcb.h on OpenBSD 5.9 and earlier. #define TCB_SIZE (4 * sizeof(void *)) + +// TIB_SIZE is sizeof(struct tib), as defined in +// /usr/include/tib.h on OpenBSD 6.0 and later. +#define TIB_SIZE (4 * sizeof(void *) + 6 * sizeof(int)) + +// TLS_SIZE is the size of TLS needed for Go. #define TLS_SIZE (2 * sizeof(void *)) void *__get_tcb(void); @@ -29,25 +35,38 @@ struct thread_args { void *arg; }; +static int has_tib = 0; + static void tcb_fixup(int mainthread) { - void *newtcb, *oldtcb; + void *tls, *newtcb, *oldtcb; + size_t tls_size, tcb_size; + + // TODO(jsing): Remove once OpenBSD 6.1 is released and OpenBSD 5.9 is + // no longer supported. // 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. + // TCB or TIB that has been setup via librthread. - newtcb = malloc(TCB_SIZE + TLS_SIZE); - if(newtcb == NULL) + tcb_size = has_tib ? TIB_SIZE : TCB_SIZE; + tls_size = TLS_SIZE + tcb_size; + tls = malloc(tls_size); + if(tls == NULL) abort(); // The signal trampoline expects the TLS slots to be zeroed. - bzero(newtcb, TLS_SIZE); + bzero(tls, TLS_SIZE); oldtcb = __get_tcb(); - bcopy(oldtcb, newtcb + TLS_SIZE, TCB_SIZE); - __set_tcb(newtcb + TLS_SIZE); + newtcb = tls + TLS_SIZE; + bcopy(oldtcb, newtcb, tcb_size); + if(has_tib) { + // Fix up self pointer. + *(uintptr_t *)(newtcb) = (uintptr_t)newtcb; + } + __set_tcb(newtcb); // NOTE(jsing, minux): we can't free oldtcb without causing double-free // problem. so newtcb will be memory leaks. Get rid of this when OpenBSD @@ -79,6 +98,10 @@ static void init_pthread_wrapper(void) { fprintf(stderr, "runtime/cgo: dlsym failed to find pthread_create: %s\n", dlerror()); abort(); } + // _rthread_init is hidden in OpenBSD librthread that has TIB. + if(dlsym(handle, "_rthread_init") == NULL) { + has_tib = 1; + } dlclose(handle); } @@ -144,6 +167,7 @@ _cgo_sys_thread_start(ThreadStart *ts) pthread_attr_init(&attr); pthread_attr_getstacksize(&attr, &size); + // Leave stacklo=0 and set stackhi=size; mstack will do the rest. ts->g->stackhi = size; err = sys_pthread_create(&p, &attr, threadentry, ts); diff --git a/src/runtime/cgo/gcc_openbsd_amd64.c b/src/runtime/cgo/gcc_openbsd_amd64.c index e84fe6c18b..4d4d14314c 100644 --- a/src/runtime/cgo/gcc_openbsd_amd64.c +++ b/src/runtime/cgo/gcc_openbsd_amd64.c @@ -13,9 +13,15 @@ static void* threadentry(void*); static void (*setg_gcc)(void*); -// TCB_SIZE is sizeof(struct thread_control_block), -// as defined in /usr/src/lib/librthread/tcb.h +// TCB_SIZE is sizeof(struct thread_control_block), as defined in +// /usr/src/lib/librthread/tcb.h on OpenBSD 5.9 and earlier. #define TCB_SIZE (4 * sizeof(void *)) + +// TIB_SIZE is sizeof(struct tib), as defined in +// /usr/include/tib.h on OpenBSD 6.0 and later. +#define TIB_SIZE (4 * sizeof(void *) + 6 * sizeof(int)) + +// TLS_SIZE is the size of TLS needed for Go. #define TLS_SIZE (2 * sizeof(void *)) void *__get_tcb(void); @@ -29,25 +35,38 @@ struct thread_args { void *arg; }; +static int has_tib = 0; + static void tcb_fixup(int mainthread) { - void *newtcb, *oldtcb; + void *tls, *newtcb, *oldtcb; + size_t tls_size, tcb_size; + + // TODO(jsing): Remove once OpenBSD 6.1 is released and OpenBSD 5.9 is + // no longer supported. // 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. + // TCB or TIB that has been setup via librthread. - newtcb = malloc(TCB_SIZE + TLS_SIZE); - if(newtcb == NULL) + tcb_size = has_tib ? TIB_SIZE : TCB_SIZE; + tls_size = TLS_SIZE + tcb_size; + tls = malloc(tls_size); + if(tls == NULL) abort(); // The signal trampoline expects the TLS slots to be zeroed. - bzero(newtcb, TLS_SIZE); + bzero(tls, TLS_SIZE); oldtcb = __get_tcb(); - bcopy(oldtcb, newtcb + TLS_SIZE, TCB_SIZE); - __set_tcb(newtcb + TLS_SIZE); + newtcb = tls + TLS_SIZE; + bcopy(oldtcb, newtcb, tcb_size); + if(has_tib) { + // Fix up self pointer. + *(uintptr_t *)(newtcb) = (uintptr_t)newtcb; + } + __set_tcb(newtcb); // NOTE(jsing, minux): we can't free oldtcb without causing double-free // problem. so newtcb will be memory leaks. Get rid of this when OpenBSD @@ -79,6 +98,10 @@ static void init_pthread_wrapper(void) { fprintf(stderr, "runtime/cgo: dlsym failed to find pthread_create: %s\n", dlerror()); abort(); } + // _rthread_init is hidden in OpenBSD librthread that has TIB. + if(dlsym(handle, "_rthread_init") == NULL) { + has_tib = 1; + } dlclose(handle); }