]> Cypherpunks repositories - gostls13.git/commitdiff
runtime/cgo: make cgo work with openbsd ABI changes
authorJoel Sing <joel@sing.id.au>
Wed, 18 May 2016 13:39:23 +0000 (23:39 +1000)
committerJoel Sing <joel@sing.id.au>
Thu, 19 May 2016 15:43:37 +0000 (15:43 +0000)
OpenBSD 6.0 (due out November 2016) will support PT_TLS, which will
allow for the OpenBSD cgo pthread_create() workaround to be removed.

However, in order for Go to continue working on supported OpenBSD
releases (the current release and the previous release - 5.9 and 6.0,
once 6.0 is released), we cannot enable PT_TLS immediately. Instead,
adjust the existing code so that it works with the previous TCB
allocation and the new TIB allocation. This allows the same Go
runtime to work on 5.8, 5.9 and later 6.0.

Once OpenBSD 5.9 is no longer supported (May 2017, when 6.1 is
released), PT_TLS can be enabled and the additional cgo runtime
code removed.

Change-Id: I3eed5ec593d80eea78c6656cb12557004b2c0c9a
Reviewed-on: https://go-review.googlesource.com/23197
Reviewed-by: Ian Lance Taylor <iant@golang.org>
Run-TryBot: Joel Sing <joel@sing.id.au>
TryBot-Result: Gobot Gobot <gobot@golang.org>

src/runtime/cgo/gcc_openbsd_386.c
src/runtime/cgo/gcc_openbsd_amd64.c

index 22941a4c6d458ff220587e182fa4b077bbb4e42a..1bc61ff7087bf972366c6589895790e77447eb2f 100644 (file)
 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);
index e84fe6c18b035f9e789cb43b92c561ef5d910d38..4d4d14314c790b11e2aad461d08132b0ed2a7ad7 100644 (file)
 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);
 }