Skip to content

Commit dfc8649

Browse files
committed
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 #10743 Change-Id: I1a3fc207946c665515f79026a56ea19134ede2dd Reviewed-on: https://go-review.googlesource.com/15991 Reviewed-by: David Crawshaw <[email protected]>
1 parent 80d9106 commit dfc8649

File tree

8 files changed

+175
-6
lines changed

8 files changed

+175
-6
lines changed

src/cmd/internal/obj/x86/asm6.go

+6
Original file line numberDiff line numberDiff line change
@@ -1921,6 +1921,8 @@ func instinit() {
19211921
}
19221922
}
19231923

1924+
var isAndroid = (obj.Getgoos() == "android")
1925+
19241926
func prefixof(ctxt *obj.Link, p *obj.Prog, a *obj.Addr) int {
19251927
if a.Reg < REG_CS && a.Index < REG_CS { // fast path
19261928
return 0
@@ -1968,6 +1970,10 @@ func prefixof(ctxt *obj.Link, p *obj.Prog, a *obj.Addr) int {
19681970
log.Fatalf("unknown TLS base register for %s", obj.Headstr(ctxt.Headtype))
19691971

19701972
case obj.Hlinux:
1973+
if isAndroid {
1974+
return 0x64 // FS
1975+
}
1976+
19711977
if ctxt.Flag_shared != 0 {
19721978
log.Fatalf("unknown TLS base register for linux with -shared")
19731979
} else {

src/cmd/internal/obj/x86/obj6.go

+10
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,16 @@ import (
3939
)
4040

4141
func canuse1insntls(ctxt *obj.Link) bool {
42+
if isAndroid {
43+
// For android, we use a disgusting hack that assumes
44+
// the thread-local storage slot for g is allocated
45+
// using pthread_key_create with a fixed offset
46+
// (see src/runtime/cgo/gcc_android_amd64.c).
47+
// This makes access to the TLS storage (for g) doable
48+
// with 1 instruction.
49+
return true
50+
}
51+
4252
if ctxt.Arch.Regsize == 4 {
4353
switch ctxt.Headtype {
4454
case obj.Hlinux,

src/cmd/link/internal/ld/data.go

+7-3
Original file line numberDiff line numberDiff line change
@@ -381,7 +381,9 @@ func relocsym(s *LSym) {
381381
}
382382

383383
case obj.R_TLS_LE:
384-
if Linkmode == LinkExternal && Iself && HEADTYPE != obj.Hopenbsd {
384+
isAndroidX86 := goos == "android" && (Thearch.Thechar == '6' || Thearch.Thechar == '8')
385+
386+
if Linkmode == LinkExternal && Iself && HEADTYPE != obj.Hopenbsd && !isAndroidX86 {
385387
r.Done = 0
386388
if r.Sym == nil {
387389
r.Sym = Ctxt.Tlsg
@@ -404,7 +406,7 @@ func relocsym(s *LSym) {
404406
// related to the fact that our own TLS storage happens
405407
// to take up 8 bytes.
406408
o = 8 + r.Sym.Value
407-
} else if Iself || Ctxt.Headtype == obj.Hplan9 || Ctxt.Headtype == obj.Hdarwin {
409+
} else if Iself || Ctxt.Headtype == obj.Hplan9 || Ctxt.Headtype == obj.Hdarwin || isAndroidX86 {
408410
o = int64(Ctxt.Tlsoffset) + r.Add
409411
} else if Ctxt.Headtype == obj.Hwindows {
410412
o = r.Add
@@ -413,7 +415,9 @@ func relocsym(s *LSym) {
413415
}
414416

415417
case obj.R_TLS_IE:
416-
if Linkmode == LinkExternal && Iself && HEADTYPE != obj.Hopenbsd {
418+
isAndroidX86 := goos == "android" && (Thearch.Thechar == '6' || Thearch.Thechar == '8')
419+
420+
if Linkmode == LinkExternal && Iself && HEADTYPE != obj.Hopenbsd && !isAndroidX86 {
417421
r.Done = 0
418422
if r.Sym == nil {
419423
r.Sym = Ctxt.Tlsg

src/cmd/link/internal/ld/sym.go

+8-2
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,13 @@ func linknew(arch *LinkArch) *Link {
102102
obj.Hopenbsd,
103103
obj.Hdragonfly,
104104
obj.Hsolaris:
105-
ctxt.Tlsoffset = -1 * ctxt.Arch.Ptrsize
105+
if obj.Getgoos() == "android" && ctxt.Arch.Thechar == '6' {
106+
// Android/x86 constant - offset from 0(FS) to our
107+
// TLS slot. Explained in src/runtime/cgo/gcc_android_*.c
108+
ctxt.Tlsoffset = 0x1d0
109+
} else {
110+
ctxt.Tlsoffset = -1 * ctxt.Arch.Ptrsize
111+
}
106112

107113
case obj.Hnacl:
108114
switch ctxt.Arch.Thechar {
@@ -121,7 +127,7 @@ func linknew(arch *LinkArch) *Link {
121127

122128
/*
123129
* OS X system constants - offset from 0(GS) to our TLS.
124-
* Explained in ../../runtime/cgo/gcc_darwin_*.c.
130+
* Explained in src/runtime/cgo/gcc_darwin_*.c.
125131
*/
126132
case obj.Hdarwin:
127133
switch ctxt.Arch.Thechar {

src/runtime/cgo/gcc_android_amd64.c

+92
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
// Copyright 2015 The Go Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
#include <string.h> /* for strerror */
6+
#include <pthread.h>
7+
#include <signal.h>
8+
#include "libcgo.h"
9+
10+
static void* threadentry(void*);
11+
static pthread_key_t k1;
12+
13+
#define magic1 (0x23581321345589ULL)
14+
15+
static void
16+
inittls(void)
17+
{
18+
uint64 x;
19+
pthread_key_t tofree[128], k;
20+
int i, ntofree;
21+
22+
/*
23+
* Same logic, code as gcc_darwin_386.c:/inittls.
24+
* Note that this is a temporary hack that should be fixed soon.
25+
* Android-L and M bionic's pthread implementation differ
26+
* significantly, and can change any time.
27+
* https://android-review.googlesource.com/#/c/134202
28+
*
29+
* We chose %fs:0x1d0 which seems to work in testing with Android
30+
* emulators (API22, API23) but it may break any time.
31+
*
32+
* TODO: fix this.
33+
*
34+
* The linker and runtime hard-code this constant offset
35+
* from %fs where we expect to find g. Disgusting.
36+
*
37+
* Known to src/cmd/link/internal/ld/sym.go:/0x1d0
38+
* and to src/runtime/sys_linux_amd64.s:/0x1d0 or /GOOS_android.
39+
*
40+
* As disgusting as on the darwin/386, darwin/amd64.
41+
*/
42+
ntofree = 0;
43+
for(;;) {
44+
if(pthread_key_create(&k, nil) < 0) {
45+
fprintf(stderr, "runtime/cgo: pthread_key_create failed\n");
46+
abort();
47+
}
48+
pthread_setspecific(k, (void*)magic1);
49+
asm volatile("movq %%fs:0x1d0, %0" : "=r"(x));
50+
pthread_setspecific(k, 0);
51+
if(x == magic1) {
52+
k1 = k;
53+
break;
54+
}
55+
if(ntofree >= nelem(tofree)) {
56+
fprintf(stderr, "runtime/cgo: could not obtain pthread_keys\n");
57+
fprintf(stderr, "\ttried");
58+
for(i=0; i<ntofree; i++)
59+
fprintf(stderr, " %#x", (unsigned)tofree[i]);
60+
fprintf(stderr, "\n");
61+
abort();
62+
}
63+
tofree[ntofree++] = k;
64+
}
65+
// TODO: output to stderr is not useful for apps.
66+
// Can we fall back to Android's log library?
67+
68+
/*
69+
* We got the key we wanted. Free the others.
70+
*/
71+
for(i=0; i<ntofree; i++) {
72+
pthread_key_delete(tofree[i]);
73+
}
74+
}
75+
76+
77+
static void*
78+
threadentry(void *v)
79+
{
80+
ThreadStart ts;
81+
82+
ts = *(ThreadStart*)v;
83+
free(v);
84+
85+
pthread_setspecific(k1, (void*)ts.g);
86+
87+
crosscall_amd64(ts.fn);
88+
return nil;
89+
}
90+
91+
void (*x_cgo_inittls)(void) = inittls;
92+
void* (*x_cgo_threadentry)(void*) = threadentry;

src/runtime/cgo/gcc_linux_amd64.c

+12
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,10 @@
1212
static void* threadentry(void*);
1313
static void (*setg_gcc)(void*);
1414

15+
// These will be set in gcc_android_amd64.c for android-specific customization.
16+
void (*x_cgo_inittls)(void);
17+
void* (*x_cgo_threadentry)(void*);
18+
1519
void
1620
x_cgo_init(G* g, void (*setg)(void*))
1721
{
@@ -43,6 +47,10 @@ x_cgo_init(G* g, void (*setg)(void*))
4347
g->stacklo = (uintptr)&size - size + 4096;
4448
pthread_attr_destroy(attr);
4549
free(attr);
50+
51+
if (x_cgo_inittls) {
52+
x_cgo_inittls();
53+
}
4654
}
4755

4856

@@ -74,6 +82,10 @@ _cgo_sys_thread_start(ThreadStart *ts)
7482
static void*
7583
threadentry(void *v)
7684
{
85+
if (x_cgo_threadentry) {
86+
return x_cgo_threadentry(v);
87+
}
88+
7789
ThreadStart ts;
7890

7991
ts = *(ThreadStart*)v;

src/runtime/rt0_android_amd64.s

+33
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
// Copyright 2015 The Go Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
#include "textflag.h"
6+
7+
TEXT _rt0_amd64_android(SB),NOSPLIT,$-8
8+
MOVQ 0(SP), DI // argc
9+
LEAQ 8(SP), SI // argv
10+
MOVQ $main(SB), AX
11+
JMP AX
12+
13+
TEXT _rt0_amd64_android_lib(SB),NOSPLIT,$0
14+
MOVQ $1, DI // argc
15+
MOVQ $_rt0_amd64_android_argv(SB), SI // argv
16+
MOVQ $_rt0_amd64_linux_lib(SB), AX
17+
JMP AX
18+
19+
DATA _rt0_amd64_android_argv+0x00(SB)/8,$_rt0_amd64_android_argv0(SB)
20+
DATA _rt0_amd64_android_argv+0x08(SB)/8,$0
21+
DATA _rt0_amd64_android_argv+0x10(SB)/8,$0
22+
DATA _rt0_amd64_android_argv+0x18(SB)/8,$15 // AT_PLATFORM
23+
DATA _rt0_amd64_android_argv+0x20(SB)/8,$_rt0_amd64_android_auxv0(SB)
24+
DATA _rt0_amd64_android_argv+0x28(SB)/8,$0
25+
GLOBL _rt0_amd64_android_argv(SB),NOPTR,$0x30
26+
27+
// TODO: AT_HWCAP necessary? If so, what value?
28+
29+
DATA _rt0_amd64_android_argv0(SB)/8, $"gojni"
30+
GLOBL _rt0_amd64_android_argv0(SB),RODATA,$8
31+
32+
DATA _rt0_amd64_android_auxv0(SB)/8, $"x86_64"
33+
GLOBL _rt0_amd64_android_auxv0(SB),RODATA,$8

src/runtime/sys_linux_amd64.s

+7-1
Original file line numberDiff line numberDiff line change
@@ -371,8 +371,14 @@ TEXT runtime·sigaltstack(SB),NOSPLIT,$-8
371371

372372
// set tls base to DI
373373
TEXT runtime·settls(SB),NOSPLIT,$32
374+
#ifdef GOOS_android
375+
// Same as in sys_darwin_386.s:/ugliness, different constant.
376+
// DI currently holds m->tls, which must be fs:0x1d0.
377+
// See cgo/gcc_android_amd64.c for the derivation of the constant.
378+
SUBQ $0x1d0, DI // In android, the tls base
379+
#else
374380
ADDQ $8, DI // ELF wants to use -8(FS)
375-
381+
#endif
376382
MOVQ DI, SI
377383
MOVQ $0x1002, DI // ARCH_SET_FS
378384
MOVQ $158, AX // arch_prctl

0 commit comments

Comments
 (0)