]> Cypherpunks repositories - gostls13.git/commitdiff
runtime, cmd: TLS setup for android/amd64.
authorHyang-Ah Hana Kim <hyangah@gmail.com>
Fri, 16 Oct 2015 18:04:29 +0000 (14:04 -0400)
committerHyang-Ah Hana Kim <hyangah@gmail.com>
Wed, 28 Oct 2015 20:54:28 +0000 (20:54 +0000)
Android linker does not handle TLS for us. We set up the TLS slot
for g, as darwin/386,amd64 handle instead. This is disgusting and
fragile. We will eventually fix this ugly hack by taking advantage
of the recent TLS IE model implementation. (Instead of referencing
an GOT entry, make the code sequence look into the TLS variable that
holds the offset.)

The TLS slot for g in android/amd64 assumes a fixed offset from %fs.
See runtime/cgo/gcc_android_amd64.c for details.

For golang/go#10743

Change-Id: I1a3fc207946c665515f79026a56ea19134ede2dd
Reviewed-on: https://go-review.googlesource.com/15991
Reviewed-by: David Crawshaw <crawshaw@golang.org>
src/cmd/internal/obj/x86/asm6.go
src/cmd/internal/obj/x86/obj6.go
src/cmd/link/internal/ld/data.go
src/cmd/link/internal/ld/sym.go
src/runtime/cgo/gcc_android_amd64.c [new file with mode: 0644]
src/runtime/cgo/gcc_linux_amd64.c
src/runtime/rt0_android_amd64.s [new file with mode: 0644]
src/runtime/sys_linux_amd64.s

index 29d33f92afe5cd85176d7bc36502036fcb4af50e..f03df5bf00d757c9c405b920372de134f9240f2d 100644 (file)
@@ -1921,6 +1921,8 @@ func instinit() {
        }
 }
 
+var isAndroid = (obj.Getgoos() == "android")
+
 func prefixof(ctxt *obj.Link, p *obj.Prog, a *obj.Addr) int {
        if a.Reg < REG_CS && a.Index < REG_CS { // fast path
                return 0
@@ -1968,6 +1970,10 @@ func prefixof(ctxt *obj.Link, p *obj.Prog, a *obj.Addr) int {
                                log.Fatalf("unknown TLS base register for %s", obj.Headstr(ctxt.Headtype))
 
                        case obj.Hlinux:
+                               if isAndroid {
+                                       return 0x64 // FS
+                               }
+
                                if ctxt.Flag_shared != 0 {
                                        log.Fatalf("unknown TLS base register for linux with -shared")
                                } else {
index 8fbe8652190b3d9a49e88835a957df6dd0063d0c..49fa22aef06c1addd2bcc76930915b46406aaf48 100644 (file)
@@ -39,6 +39,16 @@ import (
 )
 
 func canuse1insntls(ctxt *obj.Link) bool {
+       if isAndroid {
+               // For android, we use a disgusting hack that assumes
+               // the thread-local storage slot for g is allocated
+               // using pthread_key_create with a fixed offset
+               // (see src/runtime/cgo/gcc_android_amd64.c).
+               // This makes access to the TLS storage (for g) doable
+               // with 1 instruction.
+               return true
+       }
+
        if ctxt.Arch.Regsize == 4 {
                switch ctxt.Headtype {
                case obj.Hlinux,
index 2855e55181b7607f99f1a018693871c64372b6fd..8843e62936f36aeee6f0ddb46588c18320fedb55 100644 (file)
@@ -381,7 +381,9 @@ func relocsym(s *LSym) {
                        }
 
                case obj.R_TLS_LE:
-                       if Linkmode == LinkExternal && Iself && HEADTYPE != obj.Hopenbsd {
+                       isAndroidX86 := goos == "android" && (Thearch.Thechar == '6' || Thearch.Thechar == '8')
+
+                       if Linkmode == LinkExternal && Iself && HEADTYPE != obj.Hopenbsd && !isAndroidX86 {
                                r.Done = 0
                                if r.Sym == nil {
                                        r.Sym = Ctxt.Tlsg
@@ -404,7 +406,7 @@ func relocsym(s *LSym) {
                                // related to the fact that our own TLS storage happens
                                // to take up 8 bytes.
                                o = 8 + r.Sym.Value
-                       } else if Iself || Ctxt.Headtype == obj.Hplan9 || Ctxt.Headtype == obj.Hdarwin {
+                       } else if Iself || Ctxt.Headtype == obj.Hplan9 || Ctxt.Headtype == obj.Hdarwin || isAndroidX86 {
                                o = int64(Ctxt.Tlsoffset) + r.Add
                        } else if Ctxt.Headtype == obj.Hwindows {
                                o = r.Add
@@ -413,7 +415,9 @@ func relocsym(s *LSym) {
                        }
 
                case obj.R_TLS_IE:
-                       if Linkmode == LinkExternal && Iself && HEADTYPE != obj.Hopenbsd {
+                       isAndroidX86 := goos == "android" && (Thearch.Thechar == '6' || Thearch.Thechar == '8')
+
+                       if Linkmode == LinkExternal && Iself && HEADTYPE != obj.Hopenbsd && !isAndroidX86 {
                                r.Done = 0
                                if r.Sym == nil {
                                        r.Sym = Ctxt.Tlsg
index c0ab90a170615e379fb863fb99e37d8ee81ec37e..da5776d351c7b1388b67ffbc2e81a572f6669085 100644 (file)
@@ -102,7 +102,13 @@ func linknew(arch *LinkArch) *Link {
                obj.Hopenbsd,
                obj.Hdragonfly,
                obj.Hsolaris:
-               ctxt.Tlsoffset = -1 * ctxt.Arch.Ptrsize
+               if obj.Getgoos() == "android" && ctxt.Arch.Thechar == '6' {
+                       // Android/x86 constant - offset from 0(FS) to our
+                       // TLS slot. Explained in src/runtime/cgo/gcc_android_*.c
+                       ctxt.Tlsoffset = 0x1d0
+               } else {
+                       ctxt.Tlsoffset = -1 * ctxt.Arch.Ptrsize
+               }
 
        case obj.Hnacl:
                switch ctxt.Arch.Thechar {
@@ -121,7 +127,7 @@ func linknew(arch *LinkArch) *Link {
 
                /*
                 * OS X system constants - offset from 0(GS) to our TLS.
-                * Explained in ../../runtime/cgo/gcc_darwin_*.c.
+                * Explained in src/runtime/cgo/gcc_darwin_*.c.
                 */
        case obj.Hdarwin:
                switch ctxt.Arch.Thechar {
diff --git a/src/runtime/cgo/gcc_android_amd64.c b/src/runtime/cgo/gcc_android_amd64.c
new file mode 100644 (file)
index 0000000..4cea459
--- /dev/null
@@ -0,0 +1,92 @@
+// 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 <string.h> /* for strerror */
+#include <pthread.h>
+#include <signal.h>
+#include "libcgo.h"
+
+static void* threadentry(void*);
+static pthread_key_t k1;
+
+#define magic1 (0x23581321345589ULL)
+
+static void
+inittls(void)
+{
+       uint64 x;
+       pthread_key_t tofree[128], k;
+       int i, ntofree;
+
+       /*
+        * Same logic, code as gcc_darwin_386.c:/inittls.
+        * Note that this is a temporary hack that should be fixed soon.
+        * Android-L and M bionic's pthread implementation differ
+        * significantly, and can change any time.
+        * https://android-review.googlesource.com/#/c/134202
+        *
+        * We chose %fs:0x1d0 which seems to work in testing with Android
+        * emulators (API22, API23) but it may break any time.
+        *
+        * TODO: fix this.
+        *
+        * The linker and runtime hard-code this constant offset
+        * from %fs where we expect to find g. Disgusting.
+        *
+        * Known to src/cmd/link/internal/ld/sym.go:/0x1d0
+        * and to src/runtime/sys_linux_amd64.s:/0x1d0 or /GOOS_android.
+        *
+        * As disgusting as on the darwin/386, darwin/amd64.
+        */
+       ntofree = 0;
+       for(;;) {
+               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 %%fs:0x1d0, %0" : "=r"(x));
+               pthread_setspecific(k, 0);
+               if(x == magic1) {
+                       k1 = k;
+                       break;
+               }
+               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;
+       }
+       // TODO: output to stderr is not useful for apps.
+       // Can we fall back to Android's log library?
+
+       /*
+        * We got the key we wanted.  Free the others.
+        */
+       for(i=0; i<ntofree; i++) {
+               pthread_key_delete(tofree[i]);
+       }
+}
+
+
+static void*
+threadentry(void *v)
+{
+       ThreadStart ts;
+
+       ts = *(ThreadStart*)v;
+       free(v);
+
+       pthread_setspecific(k1, (void*)ts.g);
+
+       crosscall_amd64(ts.fn);
+       return nil;
+}
+
+void (*x_cgo_inittls)(void) = inittls;
+void* (*x_cgo_threadentry)(void*) = threadentry;
index c93cacd744b09f1fe96cd2513056dbb473e8efaf..51ca6446cf1a55a999971f5b0fe5554c47cbcb59 100644 (file)
 static void* threadentry(void*);
 static void (*setg_gcc)(void*);
 
+// These will be set in gcc_android_amd64.c for android-specific customization.
+void (*x_cgo_inittls)(void);
+void* (*x_cgo_threadentry)(void*);
+
 void
 x_cgo_init(G* g, void (*setg)(void*))
 {
@@ -43,6 +47,10 @@ x_cgo_init(G* g, void (*setg)(void*))
        g->stacklo = (uintptr)&size - size + 4096;
        pthread_attr_destroy(attr);
        free(attr);
+
+       if (x_cgo_inittls) {
+               x_cgo_inittls();
+       }
 }
 
 
@@ -74,6 +82,10 @@ _cgo_sys_thread_start(ThreadStart *ts)
 static void*
 threadentry(void *v)
 {
+       if (x_cgo_threadentry) {
+               return x_cgo_threadentry(v);
+       }
+
        ThreadStart ts;
 
        ts = *(ThreadStart*)v;
diff --git a/src/runtime/rt0_android_amd64.s b/src/runtime/rt0_android_amd64.s
new file mode 100644 (file)
index 0000000..9af6cab
--- /dev/null
@@ -0,0 +1,33 @@
+// 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 "textflag.h"
+
+TEXT _rt0_amd64_android(SB),NOSPLIT,$-8
+       MOVQ    0(SP), DI // argc
+       LEAQ    8(SP), SI // argv
+       MOVQ    $main(SB), AX
+       JMP     AX
+
+TEXT _rt0_amd64_android_lib(SB),NOSPLIT,$0
+       MOVQ    $1, DI // argc
+       MOVQ    $_rt0_amd64_android_argv(SB), SI  // argv
+       MOVQ    $_rt0_amd64_linux_lib(SB), AX
+       JMP     AX
+
+DATA _rt0_amd64_android_argv+0x00(SB)/8,$_rt0_amd64_android_argv0(SB)
+DATA _rt0_amd64_android_argv+0x08(SB)/8,$0
+DATA _rt0_amd64_android_argv+0x10(SB)/8,$0
+DATA _rt0_amd64_android_argv+0x18(SB)/8,$15  // AT_PLATFORM
+DATA _rt0_amd64_android_argv+0x20(SB)/8,$_rt0_amd64_android_auxv0(SB)
+DATA _rt0_amd64_android_argv+0x28(SB)/8,$0
+GLOBL _rt0_amd64_android_argv(SB),NOPTR,$0x30
+
+// TODO: AT_HWCAP necessary? If so, what value?
+
+DATA _rt0_amd64_android_argv0(SB)/8, $"gojni"
+GLOBL _rt0_amd64_android_argv0(SB),RODATA,$8
+
+DATA _rt0_amd64_android_auxv0(SB)/8, $"x86_64"
+GLOBL _rt0_amd64_android_auxv0(SB),RODATA,$8
index df72a77afc345cb98b47eaa9b84ea65990f7f5cf..aed85cb0aa0aa836b51651d23c2b07a2cab44f50 100644 (file)
@@ -371,8 +371,14 @@ TEXT runtimeĀ·sigaltstack(SB),NOSPLIT,$-8
 
 // set tls base to DI
 TEXT runtimeĀ·settls(SB),NOSPLIT,$32
+#ifdef GOOS_android
+       // Same as in sys_darwin_386.s:/ugliness, different constant.
+       // DI currently holds m->tls, which must be fs:0x1d0.
+       // See cgo/gcc_android_amd64.c for the derivation of the constant.
+       SUBQ    $0x1d0, DI  // In android, the tls base 
+#else
        ADDQ    $8, DI  // ELF wants to use -8(FS)
-
+#endif
        MOVQ    DI, SI
        MOVQ    $0x1002, DI     // ARCH_SET_FS
        MOVQ    $158, AX        // arch_prctl