]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/link,runtime/cgo: enable PT_TLS generation on OpenBSD
authorJoel Sing <joel@sing.id.au>
Tue, 11 Apr 2017 15:10:01 +0000 (01:10 +1000)
committerJoel Sing <joel@sing.id.au>
Tue, 11 Apr 2017 16:33:16 +0000 (16:33 +0000)
OpenBSD 6.0 and later have support for PT_TLS in ld.so(1). Now that OpenBSD
6.1 has been released, OpenBSD 5.9 is no longer officially supported and Go
can start generating PT_TLS for OpenBSD cgo binaries. This also allows us
to remove the workarounds in the OpenBSD cgo runtime.

This change also removes the environ and progname exports - these are now
provided directly by ld.so(1) itself.

Fixes #19932

Change-Id: I42e75ef9feb5dcd4696add5233497e3cbc48ad52
Reviewed-on: https://go-review.googlesource.com/40331
Reviewed-by: Ian Lance Taylor <iant@golang.org>
src/cmd/link/internal/ld/data.go
src/cmd/link/internal/ld/elf.go
src/cmd/link/internal/ld/lib.go
src/runtime/cgo/gcc_libinit.c
src/runtime/cgo/gcc_libinit_openbsd.c
src/runtime/cgo/gcc_openbsd_386.c
src/runtime/cgo/gcc_openbsd_amd64.c
src/runtime/cgo/openbsd.go

index 094df86dceab3a9f989130b4ee5eaa85ab7f0d9d..099a5361ac4921c485f814c66cf16e06cbc2ef06 100644 (file)
@@ -449,7 +449,7 @@ func relocsym(ctxt *Link, s *Symbol) {
                case obj.R_TLS_LE:
                        isAndroidX86 := obj.GOOS == "android" && (SysArch.InFamily(sys.AMD64, sys.I386))
 
-                       if Linkmode == LinkExternal && Iself && Headtype != obj.Hopenbsd && !isAndroidX86 {
+                       if Linkmode == LinkExternal && Iself && !isAndroidX86 {
                                r.Done = 0
                                if r.Sym == nil {
                                        r.Sym = ctxt.Tlsg
@@ -483,7 +483,7 @@ func relocsym(ctxt *Link, s *Symbol) {
                case obj.R_TLS_IE:
                        isAndroidX86 := obj.GOOS == "android" && (SysArch.InFamily(sys.AMD64, sys.I386))
 
-                       if Linkmode == LinkExternal && Iself && Headtype != obj.Hopenbsd && !isAndroidX86 {
+                       if Linkmode == LinkExternal && Iself && !isAndroidX86 {
                                r.Done = 0
                                if r.Sym == nil {
                                        r.Sym = ctxt.Tlsg
@@ -1570,7 +1570,7 @@ func (ctxt *Link) dodata() {
 
        if len(data[obj.STLSBSS]) > 0 {
                var sect *Section
-               if Iself && (Linkmode == LinkExternal || !*FlagD) && Headtype != obj.Hopenbsd {
+               if Iself && (Linkmode == LinkExternal || !*FlagD) {
                        sect = addsection(&Segdata, ".tbss", 06)
                        sect.Align = int32(SysArch.PtrSize)
                        sect.Vaddr = 0
index 1d8a5dd35e6dc21881ef7c581749372e6eca8359..978c166d4da28c6092d4ee2630e8d2d627d2d2f2 100644 (file)
@@ -1894,14 +1894,11 @@ func (ctxt *Link) doelf() {
        Addstring(shstrtab, ".bss")
        Addstring(shstrtab, ".noptrbss")
 
-       // generate .tbss section (except for OpenBSD where it's not supported)
-       // for dynamic internal linker or external linking, so that various
-       // binutils could correctly calculate PT_TLS size.
-       // see https://golang.org/issue/5200.
-       if Headtype != obj.Hopenbsd {
-               if !*FlagD || Linkmode == LinkExternal {
-                       Addstring(shstrtab, ".tbss")
-               }
+       // generate .tbss section for dynamic internal linker or external
+       // linking, so that various binutils could correctly calculate
+       // PT_TLS size. See https://golang.org/issue/5200.
+       if !*FlagD || Linkmode == LinkExternal {
+               Addstring(shstrtab, ".tbss")
        }
        if Headtype == obj.Hnetbsd {
                Addstring(shstrtab, ".note.netbsd.ident")
@@ -2525,24 +2522,19 @@ func Asmbelf(ctxt *Link, symo int64) {
                /*
                 * Thread-local storage segment (really just size).
                 */
-               // Do not emit PT_TLS for OpenBSD since ld.so(1) does
-               // not currently support it. This is handled
-               // appropriately in runtime/cgo.
-               if Headtype != obj.Hopenbsd {
-                       tlssize := uint64(0)
-                       for sect := Segdata.Sect; sect != nil; sect = sect.Next {
-                               if sect.Name == ".tbss" {
-                                       tlssize = sect.Length
-                               }
-                       }
-                       if tlssize != 0 {
-                               ph := newElfPhdr()
-                               ph.type_ = PT_TLS
-                               ph.flags = PF_R
-                               ph.memsz = tlssize
-                               ph.align = uint64(SysArch.RegSize)
+               tlssize := uint64(0)
+               for sect := Segdata.Sect; sect != nil; sect = sect.Next {
+                       if sect.Name == ".tbss" {
+                               tlssize = sect.Length
                        }
                }
+               if tlssize != 0 {
+                       ph := newElfPhdr()
+                       ph.type_ = PT_TLS
+                       ph.flags = PF_R
+                       ph.memsz = tlssize
+                       ph.align = uint64(SysArch.RegSize)
+               }
        }
 
        if Headtype == obj.Hlinux {
index d13c93b9a13fc4ddca5b8363d4edc78147c3f7cb..0319a3edfd2f7f6d1ceb9d680e2e3ae89ab84f77 100644 (file)
@@ -1971,7 +1971,7 @@ func genasmsym(ctxt *Link, put func(*Link, *Symbol, string, SymbolType, int64, *
                        put(ctxt, s, s.Extname, UndefinedSym, 0, nil)
 
                case obj.STLSBSS:
-                       if Linkmode == LinkExternal && Headtype != obj.Hopenbsd {
+                       if Linkmode == LinkExternal {
                                put(ctxt, s, s.Name, TLSSym, Symaddr(s), s.Gotype)
                        }
                }
index f6fbaa3f01efb5d7b76f2ef782a04d7785b51de3..31594addcefb996818efc1f9f91f0dbd005b56f7 100644 (file)
@@ -3,7 +3,7 @@
 // license that can be found in the LICENSE file.
 
 // +build cgo
-// +build darwin dragonfly freebsd linux netbsd solaris
+// +build darwin dragonfly freebsd linux netbsd openbsd solaris
 
 #include <pthread.h>
 #include <errno.h>
index c8308e54c3491d76a40fa1ba4a38eaee3f0a2582..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 100644 (file)
@@ -1,74 +0,0 @@
-// Copyright 2015 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 <errno.h>
-#include <pthread.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include "libcgo.h"
-
-// The context function, used when tracing back C calls into Go.
-static void (*cgo_context_function)(struct context_arg*);
-
-void
-x_cgo_sys_thread_create(void* (*func)(void*), void* arg) {
-       fprintf(stderr, "x_cgo_sys_thread_create not implemented");
-       abort();
-}
-
-uintptr_t
-_cgo_wait_runtime_init_done() {
-       void (*pfn)(struct context_arg*);
-
-       // TODO(spetrovic): implement this method.
-
-       pfn = _cgo_get_context_function();
-       if (pfn != nil) {
-               struct context_arg arg;
-
-               arg.Context = 0;
-               (*pfn)(&arg);
-               return arg.Context;
-       }
-       return 0;
-}
-
-void
-x_cgo_notify_runtime_init_done(void* dummy) {
-       // TODO(spetrovic): implement this method.
-}
-
-// Sets the context function to call to record the traceback context
-// when calling a Go function from C code. Called from runtime.SetCgoTraceback.
-void x_cgo_set_context_function(void (*context)(struct context_arg*)) {
-       // TODO(iant): Needs synchronization.
-       cgo_context_function = context;
-}
-
-// Gets the context function.
-void (*(_cgo_get_context_function(void)))(struct context_arg*) {
-       return cgo_context_function;
-}
-
-// _cgo_try_pthread_create retries sys_pthread_create if it fails with
-// EAGAIN.
-int
-_cgo_openbsd_try_pthread_create(int (*sys_pthread_create)(pthread_t*, const pthread_attr_t*, void* (*)(void*), void*),
-       pthread_t* thread, const pthread_attr_t* attr, void* (*pfn)(void*), void* arg) {
-       int tries;
-       int err;
-       struct timespec ts;
-
-       for (tries = 0; tries < 100; tries++) {
-               err = sys_pthread_create(thread, attr, pfn, arg);
-               if (err != EAGAIN) {
-                       return err;
-               }
-               ts.tv_sec = 0;
-               ts.tv_nsec = (tries + 1) * 1000 * 1000; // Milliseconds.
-               nanosleep(&ts, nil);
-       }
-       return EAGAIN;
-}
index 0cac047ad3045a3a13700bfe583783988797f087..cfc09e504ca654c28e0b42e05e285b5123d9365a 100644 (file)
@@ -3,8 +3,6 @@
 // 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>
 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 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);
-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 int has_tib = 0;
-
-static void
-tcb_fixup(int mainthread)
-{
-       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 or TIB that has been setup via librthread.
-
-       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(tls, TLS_SIZE);
-
-       oldtcb = __get_tcb();
-       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
-       // has proper support for PT_TLS.
-}
-
-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);
-}
-
-static void init_pthread_wrapper(void) {
-       void *handle;
-
-       // Locate symbol for the system pthread_create function.
-       handle = dlopen("libpthread.so", RTLD_LAZY);
-       if(handle == NULL) {
-               fprintf(stderr, "runtime/cgo: dlopen failed to load libpthread: %s\n", dlerror());
-               abort();
-       }
-       sys_pthread_create = dlsym(handle, "pthread_create");
-       if(sys_pthread_create == NULL) {
-               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);
-}
-
-static pthread_once_t init_pthread_wrapper_once = PTHREAD_ONCE_INIT;
-
-int
-pthread_create(pthread_t *thread, const pthread_attr_t *attr,
-       void *(*start_routine)(void *), void *arg)
-{
-       struct thread_args *p;
-
-       // we must initialize our wrapper in pthread_create, because it is valid to call
-       // pthread_create in a static constructor, and in fact, our test for issue 9456
-       // does just that.
-       if(pthread_once(&init_pthread_wrapper_once, init_pthread_wrapper) != 0) {
-               fprintf(stderr, "runtime/cgo: failed to initialize pthread_create wrapper\n");
-               abort();
-       }
-
-       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, void (*setg)(void*))
 {
@@ -144,16 +23,8 @@ x_cgo_init(G *g, void (*setg)(void*))
        pthread_attr_getstacksize(&attr, &size);
        g->stacklo = (uintptr)&attr - size + 4096;
        pthread_attr_destroy(&attr);
-
-       if(pthread_once(&init_pthread_wrapper_once, init_pthread_wrapper) != 0) {
-               fprintf(stderr, "runtime/cgo: failed to initialize pthread_create wrapper\n");
-               abort();
-       }
-
-       tcb_fixup(1);
 }
 
-
 void
 _cgo_sys_thread_start(ThreadStart *ts)
 {
@@ -171,7 +42,7 @@ _cgo_sys_thread_start(ThreadStart *ts)
 
        // Leave stacklo=0 and set stackhi=size; mstack will do the rest.
        ts->g->stackhi = size;
-       err = _cgo_openbsd_try_pthread_create(sys_pthread_create, &p, &attr, threadentry, ts);
+       err = _cgo_try_pthread_create(&p, &attr, threadentry, ts);
 
        pthread_sigmask(SIG_SETMASK, &oset, nil);
 
@@ -186,8 +57,6 @@ threadentry(void *v)
 {
        ThreadStart ts;
 
-       tcb_fixup(0);
-
        ts = *(ThreadStart*)v;
        free(v);
 
index 86a9185a37e6b9905572ba781b08e1bba4a414a7..ce626c4e3745d0a99681976375fa4b2b8d4a15d1 100644 (file)
@@ -3,8 +3,6 @@
 // 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>
 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 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);
-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 int has_tib = 0;
-
-static void
-tcb_fixup(int mainthread)
-{
-       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 or TIB that has been setup via librthread.
-
-       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(tls, TLS_SIZE);
-
-       oldtcb = __get_tcb();
-       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
-       // has proper support for PT_TLS.
-}
-
-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);
-}
-
-static void init_pthread_wrapper(void) {
-       void *handle;
-
-       // Locate symbol for the system pthread_create function.
-       handle = dlopen("libpthread.so", RTLD_LAZY);
-       if(handle == NULL) {
-               fprintf(stderr, "runtime/cgo: dlopen failed to load libpthread: %s\n", dlerror());
-               abort();
-       }
-       sys_pthread_create = dlsym(handle, "pthread_create");
-       if(sys_pthread_create == NULL) {
-               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);
-}
-
-static pthread_once_t init_pthread_wrapper_once = PTHREAD_ONCE_INIT;
-
-int
-pthread_create(pthread_t *thread, const pthread_attr_t *attr,
-       void *(*start_routine)(void *), void *arg)
-{
-       struct thread_args *p;
-
-       // we must initialize our wrapper in pthread_create, because it is valid to call
-       // pthread_create in a static constructor, and in fact, our test for issue 9456
-       // does just that.
-       if(pthread_once(&init_pthread_wrapper_once, init_pthread_wrapper) != 0) {
-               fprintf(stderr, "runtime/cgo: failed to initialize pthread_create wrapper\n");
-               abort();
-       }
-
-       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, void (*setg)(void*))
 {
@@ -144,16 +23,8 @@ x_cgo_init(G *g, void (*setg)(void*))
        pthread_attr_getstacksize(&attr, &size);
        g->stacklo = (uintptr)&attr - size + 4096;
        pthread_attr_destroy(&attr);
-
-       if(pthread_once(&init_pthread_wrapper_once, init_pthread_wrapper) != 0) {
-               fprintf(stderr, "runtime/cgo: failed to initialize pthread_create wrapper\n");
-               abort();
-       }
-
-       tcb_fixup(1);
 }
 
-
 void
 _cgo_sys_thread_start(ThreadStart *ts)
 {
@@ -171,7 +42,7 @@ _cgo_sys_thread_start(ThreadStart *ts)
 
        // Leave stacklo=0 and set stackhi=size; mstack will do the rest.
        ts->g->stackhi = size;
-       err = _cgo_openbsd_try_pthread_create(sys_pthread_create, &p, &attr, threadentry, ts);
+       err = _cgo_try_pthread_create(&p, &attr, threadentry, ts);
 
        pthread_sigmask(SIG_SETMASK, &oset, nil);
 
@@ -186,8 +57,6 @@ threadentry(void *v)
 {
        ThreadStart ts;
 
-       tcb_fixup(0);
-
        ts = *(ThreadStart*)v;
        free(v);
 
index 5c70dbd268b8b83fc3318d6961e37ddacfcad414..81c73bf399311233c259b1a33469387533c40526 100644 (file)
@@ -8,24 +8,13 @@ package cgo
 
 import _ "unsafe" // for go:linkname
 
-// Supply environ, __progname and __guard_local, because
-// we don't link against the standard OpenBSD crt0.o and
-// the libc dynamic library needs them.
+// Supply __guard_local because we don't link against the standard
+// OpenBSD crt0.o and the libc dynamic library needs it.
 
-//go:linkname _environ environ
-//go:linkname _progname __progname
 //go:linkname _guard_local __guard_local
 
-var _environ uintptr
-var _progname uintptr
 var _guard_local uintptr
 
-//go:cgo_export_dynamic environ environ
-//go:cgo_export_dynamic __progname __progname
-
 // This is normally marked as hidden and placed in the
 // .openbsd.randomdata section.
 //go:cgo_export_dynamic __guard_local __guard_local
-
-// We override pthread_create to support PT_TLS.
-//go:cgo_export_dynamic pthread_create pthread_create