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() {
}
}
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 {
......
......@@ -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,
......
......@@ -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
......
......@@ -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 {
......
// 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 @@
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;
......
// 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
// 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
......
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