Commit dfc86498 authored by Hyang-Ah Hana Kim's avatar Hyang-Ah Hana Kim

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/15991Reviewed-by: 's avatarDavid Crawshaw <crawshaw@golang.org>
parent 80d91064
...@@ -1921,6 +1921,8 @@ func instinit() { ...@@ -1921,6 +1921,8 @@ func instinit() {
} }
} }
var isAndroid = (obj.Getgoos() == "android")
func prefixof(ctxt *obj.Link, p *obj.Prog, a *obj.Addr) int { func prefixof(ctxt *obj.Link, p *obj.Prog, a *obj.Addr) int {
if a.Reg < REG_CS && a.Index < REG_CS { // fast path if a.Reg < REG_CS && a.Index < REG_CS { // fast path
return 0 return 0
...@@ -1968,6 +1970,10 @@ func prefixof(ctxt *obj.Link, p *obj.Prog, a *obj.Addr) int { ...@@ -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)) log.Fatalf("unknown TLS base register for %s", obj.Headstr(ctxt.Headtype))
case obj.Hlinux: case obj.Hlinux:
if isAndroid {
return 0x64 // FS
}
if ctxt.Flag_shared != 0 { if ctxt.Flag_shared != 0 {
log.Fatalf("unknown TLS base register for linux with -shared") log.Fatalf("unknown TLS base register for linux with -shared")
} else { } else {
......
...@@ -39,6 +39,16 @@ import ( ...@@ -39,6 +39,16 @@ import (
) )
func canuse1insntls(ctxt *obj.Link) bool { 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 { if ctxt.Arch.Regsize == 4 {
switch ctxt.Headtype { switch ctxt.Headtype {
case obj.Hlinux, case obj.Hlinux,
......
...@@ -381,7 +381,9 @@ func relocsym(s *LSym) { ...@@ -381,7 +381,9 @@ func relocsym(s *LSym) {
} }
case obj.R_TLS_LE: 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 r.Done = 0
if r.Sym == nil { if r.Sym == nil {
r.Sym = Ctxt.Tlsg r.Sym = Ctxt.Tlsg
...@@ -404,7 +406,7 @@ func relocsym(s *LSym) { ...@@ -404,7 +406,7 @@ func relocsym(s *LSym) {
// related to the fact that our own TLS storage happens // related to the fact that our own TLS storage happens
// to take up 8 bytes. // to take up 8 bytes.
o = 8 + r.Sym.Value 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 o = int64(Ctxt.Tlsoffset) + r.Add
} else if Ctxt.Headtype == obj.Hwindows { } else if Ctxt.Headtype == obj.Hwindows {
o = r.Add o = r.Add
...@@ -413,7 +415,9 @@ func relocsym(s *LSym) { ...@@ -413,7 +415,9 @@ func relocsym(s *LSym) {
} }
case obj.R_TLS_IE: 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 r.Done = 0
if r.Sym == nil { if r.Sym == nil {
r.Sym = Ctxt.Tlsg r.Sym = Ctxt.Tlsg
......
...@@ -102,7 +102,13 @@ func linknew(arch *LinkArch) *Link { ...@@ -102,7 +102,13 @@ func linknew(arch *LinkArch) *Link {
obj.Hopenbsd, obj.Hopenbsd,
obj.Hdragonfly, obj.Hdragonfly,
obj.Hsolaris: 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: case obj.Hnacl:
switch ctxt.Arch.Thechar { switch ctxt.Arch.Thechar {
...@@ -121,7 +127,7 @@ func linknew(arch *LinkArch) *Link { ...@@ -121,7 +127,7 @@ func linknew(arch *LinkArch) *Link {
/* /*
* OS X system constants - offset from 0(GS) to our TLS. * 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: case obj.Hdarwin:
switch ctxt.Arch.Thechar { switch ctxt.Arch.Thechar {
......
// 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;
...@@ -12,6 +12,10 @@ ...@@ -12,6 +12,10 @@
static void* threadentry(void*); static void* threadentry(void*);
static void (*setg_gcc)(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 void
x_cgo_init(G* g, void (*setg)(void*)) x_cgo_init(G* g, void (*setg)(void*))
{ {
...@@ -43,6 +47,10 @@ 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; g->stacklo = (uintptr)&size - size + 4096;
pthread_attr_destroy(attr); pthread_attr_destroy(attr);
free(attr); free(attr);
if (x_cgo_inittls) {
x_cgo_inittls();
}
} }
...@@ -74,6 +82,10 @@ _cgo_sys_thread_start(ThreadStart *ts) ...@@ -74,6 +82,10 @@ _cgo_sys_thread_start(ThreadStart *ts)
static void* static void*
threadentry(void *v) threadentry(void *v)
{ {
if (x_cgo_threadentry) {
return x_cgo_threadentry(v);
}
ThreadStart ts; ThreadStart ts;
ts = *(ThreadStart*)v; ts = *(ThreadStart*)v;
......
// 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
...@@ -371,8 +371,14 @@ TEXT runtime·sigaltstack(SB),NOSPLIT,$-8 ...@@ -371,8 +371,14 @@ TEXT runtime·sigaltstack(SB),NOSPLIT,$-8
// set tls base to DI // set tls base to DI
TEXT runtime·settls(SB),NOSPLIT,$32 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) ADDQ $8, DI // ELF wants to use -8(FS)
#endif
MOVQ DI, SI MOVQ DI, SI
MOVQ $0x1002, DI // ARCH_SET_FS MOVQ $0x1002, DI // ARCH_SET_FS
MOVQ $158, AX // arch_prctl MOVQ $158, AX // arch_prctl
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment