From dfc8649854eeb569598cabfbc8e408c3ef07a539 Mon Sep 17 00:00:00 2001 From: Hyang-Ah Hana Kim Date: Fri, 16 Oct 2015 14:04:29 -0400 Subject: [PATCH] runtime, cmd: TLS setup for android/amd64. 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 --- src/cmd/internal/obj/x86/asm6.go | 6 ++ src/cmd/internal/obj/x86/obj6.go | 10 ++++ src/cmd/link/internal/ld/data.go | 10 +++- src/cmd/link/internal/ld/sym.go | 10 +++- src/runtime/cgo/gcc_android_amd64.c | 92 +++++++++++++++++++++++++++++ src/runtime/cgo/gcc_linux_amd64.c | 12 ++++ src/runtime/rt0_android_amd64.s | 33 +++++++++++ src/runtime/sys_linux_amd64.s | 8 ++- 8 files changed, 175 insertions(+), 6 deletions(-) create mode 100644 src/runtime/cgo/gcc_android_amd64.c create mode 100644 src/runtime/rt0_android_amd64.s diff --git a/src/cmd/internal/obj/x86/asm6.go b/src/cmd/internal/obj/x86/asm6.go index 29d33f92af..f03df5bf00 100644 --- a/src/cmd/internal/obj/x86/asm6.go +++ b/src/cmd/internal/obj/x86/asm6.go @@ -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 { diff --git a/src/cmd/internal/obj/x86/obj6.go b/src/cmd/internal/obj/x86/obj6.go index 8fbe865219..49fa22aef0 100644 --- a/src/cmd/internal/obj/x86/obj6.go +++ b/src/cmd/internal/obj/x86/obj6.go @@ -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, diff --git a/src/cmd/link/internal/ld/data.go b/src/cmd/link/internal/ld/data.go index 2855e55181..8843e62936 100644 --- a/src/cmd/link/internal/ld/data.go +++ b/src/cmd/link/internal/ld/data.go @@ -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 diff --git a/src/cmd/link/internal/ld/sym.go b/src/cmd/link/internal/ld/sym.go index c0ab90a170..da5776d351 100644 --- a/src/cmd/link/internal/ld/sym.go +++ b/src/cmd/link/internal/ld/sym.go @@ -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 index 0000000000..4cea459748 --- /dev/null +++ b/src/runtime/cgo/gcc_android_amd64.c @@ -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 /* for strerror */ +#include +#include +#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; istacklo = (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 index 0000000000..9af6cab16f --- /dev/null +++ b/src/runtime/rt0_android_amd64.s @@ -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 diff --git a/src/runtime/sys_linux_amd64.s b/src/runtime/sys_linux_amd64.s index df72a77afc..aed85cb0aa 100644 --- a/src/runtime/sys_linux_amd64.s +++ b/src/runtime/sys_linux_amd64.s @@ -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 -- 2.48.1