Skip to content

Commit

Permalink
cmd/link/ld,cmd/internal/obj,runtime: make the Android TLS offset dyn…
Browse files Browse the repository at this point in the history
…amic

We're going to need a different TLS offset for Android Q, so the static
offsets used for 386 and amd64 are no longer viable on Android.

Introduce runtime·tls_g and use that for indexing into TLS storage. As
an added benefit, we can then merge the TLS setup code for all android
GOARCHs.

While we're at it, remove a bunch of android special cases no longer
needed.

Updates #29674
Updates #29249 (perhaps fixes it)

Change-Id: I77c7385aec7de8f1f6a4da7c9c79999157e39572
Reviewed-on: https://go-review.googlesource.com/c/go/+/169817
TryBot-Result: Gobot Gobot <[email protected]>
Reviewed-by: Cherry Zhang <[email protected]>
  • Loading branch information
eliasnaur committed Mar 29, 2019
1 parent 2cc3473 commit 1d10b17
Show file tree
Hide file tree
Showing 14 changed files with 102 additions and 275 deletions.
22 changes: 15 additions & 7 deletions src/cmd/internal/obj/x86/obj6.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,13 +41,8 @@ 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
// Android uses a global variable for the tls offset.
return false
}

if ctxt.Arch.Family == sys.I386 {
Expand Down Expand Up @@ -162,6 +157,18 @@ func progedit(ctxt *obj.Link, p *obj.Prog, newprog obj.ProgAlloc) {
}
}

// Android uses a tls offset determined at runtime. Rewrite
// MOVQ TLS, BX
// to
// MOVQ runtime.tls_g(SB), BX
if isAndroid && (p.As == AMOVQ || p.As == AMOVL) && p.From.Type == obj.TYPE_REG && p.From.Reg == REG_TLS && p.To.Type == obj.TYPE_REG && REG_AX <= p.To.Reg && p.To.Reg <= REG_R15 {
p.From.Type = obj.TYPE_MEM
p.From.Name = obj.NAME_EXTERN
p.From.Reg = REG_NONE
p.From.Sym = ctxt.Lookup("runtime.tls_g")
p.From.Index = REG_NONE
}

// TODO: Remove.
if ctxt.Headtype == objabi.Hwindows && ctxt.Arch.Family == sys.AMD64 || ctxt.Headtype == objabi.Hplan9 {
if p.From.Scale == 1 && p.From.Index == REG_TLS {
Expand Down Expand Up @@ -1007,6 +1014,7 @@ func load_g_cx(ctxt *obj.Link, p *obj.Prog, newprog obj.ProgAlloc) *obj.Prog {
progedit(ctxt, p, newprog)
for p.Link != next {
p = p.Link
progedit(ctxt, p, newprog)
}

if p.From.Index == REG_TLS {
Expand Down
10 changes: 3 additions & 7 deletions src/cmd/link/internal/ld/data.go
Original file line number Diff line number Diff line change
Expand Up @@ -218,9 +218,7 @@ func relocsym(ctxt *Link, s *sym.Symbol) {
Errorf(s, "unknown reloc to %v: %d (%s)", r.Sym.Name, r.Type, sym.RelocName(ctxt.Arch, r.Type))
}
case objabi.R_TLS_LE:
isAndroidX86 := objabi.GOOS == "android" && (ctxt.Arch.InFamily(sys.AMD64, sys.I386))

if ctxt.LinkMode == LinkExternal && ctxt.IsELF && !isAndroidX86 {
if ctxt.LinkMode == LinkExternal && ctxt.IsELF {
r.Done = false
if r.Sym == nil {
r.Sym = ctxt.Tlsg
Expand All @@ -243,17 +241,15 @@ func relocsym(ctxt *Link, s *sym.Symbol) {
// related to the fact that our own TLS storage happens
// to take up 8 bytes.
o = 8 + r.Sym.Value
} else if ctxt.IsELF || ctxt.HeadType == objabi.Hplan9 || ctxt.HeadType == objabi.Hdarwin || isAndroidX86 {
} else if ctxt.IsELF || ctxt.HeadType == objabi.Hplan9 || ctxt.HeadType == objabi.Hdarwin {
o = int64(ctxt.Tlsoffset) + r.Add
} else if ctxt.HeadType == objabi.Hwindows {
o = r.Add
} else {
log.Fatalf("unexpected R_TLS_LE relocation for %v", ctxt.HeadType)
}
case objabi.R_TLS_IE:
isAndroidX86 := objabi.GOOS == "android" && (ctxt.Arch.InFamily(sys.AMD64, sys.I386))

if ctxt.LinkMode == LinkExternal && ctxt.IsELF && !isAndroidX86 {
if ctxt.LinkMode == LinkExternal && ctxt.IsELF {
r.Done = false
if r.Sym == nil {
r.Sym = ctxt.Tlsg
Expand Down
17 changes: 2 additions & 15 deletions src/cmd/link/internal/ld/sym.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ func linknew(arch *sys.Arch) *Link {
}

// computeTLSOffset records the thread-local storage offset.
// Not used for Android where the TLS offset is determined at runtime.
func (ctxt *Link) computeTLSOffset() {
switch ctxt.HeadType {
default:
Expand All @@ -80,21 +81,7 @@ func (ctxt *Link) computeTLSOffset() {
objabi.Hopenbsd,
objabi.Hdragonfly,
objabi.Hsolaris:
if objabi.GOOS == "android" {
switch ctxt.Arch.Family {
case sys.AMD64:
// Android/amd64 constant - offset from 0(FS) to our TLS slot.
// Explained in src/runtime/cgo/gcc_android_*.c
ctxt.Tlsoffset = 0x1d0
case sys.I386:
// Android/386 constant - offset from 0(GS) to our TLS slot.
ctxt.Tlsoffset = 0xf8
default:
ctxt.Tlsoffset = -1 * ctxt.Arch.PtrSize
}
} else {
ctxt.Tlsoffset = -1 * ctxt.Arch.PtrSize
}
ctxt.Tlsoffset = -1 * ctxt.Arch.PtrSize

case objabi.Hnacl:
switch ctxt.Arch.Family {
Expand Down
17 changes: 15 additions & 2 deletions src/runtime/asm_386.s
Original file line number Diff line number Diff line change
Expand Up @@ -171,9 +171,18 @@ nocpuinfo:
MOVL _cgo_init(SB), AX
TESTL AX, AX
JZ needtls
#ifdef GOOS_android
MOVL 0(TLS), BX
MOVL BX, 12(SP) // arg 4: TLS base, stored in the first slot (TLS_SLOT_SELF).
MOVL $runtime·tls_g(SB), 8(SP) // arg 3: &tls_g
#else
MOVL $0, BX
MOVL BX, 12(SP) // arg 3,4: not used when using platform's TLS
MOVL BX, 8(SP)
#endif
MOVL $setg_gcc<>(SB), BX
MOVL BX, 4(SP)
MOVL BP, 0(SP)
MOVL BX, 4(SP) // arg 2: setg_gcc
MOVL BP, 0(SP) // arg 1: g0
CALL AX

// update stackguard after _cgo_init
Expand Down Expand Up @@ -1553,3 +1562,7 @@ TEXT runtime·panicExtendSlice3CU(SB),NOSPLIT,$0-12
MOVL AX, lo+4(FP)
MOVL CX, y+8(FP)
JMP runtime·goPanicExtendSlice3CU(SB)

#ifdef GOOS_android
GLOBL runtime·tls_g+0(SB), NOPTR, $4
#endif
23 changes: 20 additions & 3 deletions src/runtime/asm_amd64.s
Original file line number Diff line number Diff line change
Expand Up @@ -132,9 +132,22 @@ nocpuinfo:
MOVQ _cgo_init(SB), AX
TESTQ AX, AX
JZ needtls
// g0 already in DI
MOVQ DI, CX // Win64 uses CX for first parameter
MOVQ $setg_gcc<>(SB), SI
// arg 1: g0, already in DI
MOVQ $setg_gcc<>(SB), SI // arg 2: setg_gcc
#ifdef GOOS_android
MOVQ $runtime·tls_g(SB), DX // arg 3: &tls_g
MOVQ 0(TLS), CX // arg 4: TLS base, stored in the first slot (TLS_SLOT_SELF).
#else
MOVQ $0, DX // arg 3, 4: not used when using platform's TLS
MOVQ $0, CX
#endif
#ifdef GOOS_windows
// Adjust for the Win64 calling convention.
MOVQ CX, R9 // arg 4
MOVQ DX, R8 // arg 3
MOVQ SI, DX // arg 2
MOVQ DI, CX // arg 1
#endif
CALL AX

// update stackguard after _cgo_init
Expand Down Expand Up @@ -1698,3 +1711,7 @@ TEXT runtime·panicSlice3CU(SB),NOSPLIT,$0-16
MOVQ AX, x+0(FP)
MOVQ CX, y+8(FP)
JMP runtime·goPanicSlice3CU(SB)

#ifdef GOOS_android
GLOBL runtime·tls_g+0(SB), NOPTR, $8
#endif
35 changes: 35 additions & 0 deletions src/runtime/cgo/gcc_android.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

#include <stdarg.h>
#include <android/log.h>
#include <pthread.h>
#include "libcgo.h"

void
Expand All @@ -29,3 +30,37 @@ fatalf(const char* format, ...)

abort();
}

// Truncated to a different magic value on 32-bit; that's ok.
#define magic1 (0x23581321345589ULL)

// inittls allocates a thread-local storage slot for g.
//
// It finds the first available slot using pthread_key_create and uses
// it as the offset value for runtime.tls_g.
static void
inittls(void **tlsg, void **tlsbase)
{
pthread_key_t k;
int i, err;

err = pthread_key_create(&k, nil);
if(err != 0) {
fatalf("pthread_key_create failed: %d", err);
}
pthread_setspecific(k, (void*)magic1);
// If thread local slots are laid out as we expect, our magic word will
// be located at some low offset from tlsbase. However, just in case something went
// wrong, the search is limited to sensible offsets. PTHREAD_KEYS_MAX was the
// original limit, but issue 19472 made a higher limit necessary.
for (i=0; i<384; i++) {
if (*(tlsbase+i) == (void*)magic1) {
*tlsg = (void*)(i*sizeof(void *));
pthread_setspecific(k, 0);
return;
}
}
fatalf("could not find pthread key");
}

void (*x_cgo_inittls)(void **tlsg, void **tlsbase) = inittls;
67 changes: 0 additions & 67 deletions src/runtime/cgo/gcc_android_386.c

This file was deleted.

72 changes: 0 additions & 72 deletions src/runtime/cgo/gcc_android_amd64.c

This file was deleted.

42 changes: 0 additions & 42 deletions src/runtime/cgo/gcc_android_arm.c

This file was deleted.

Loading

0 comments on commit 1d10b17

Please sign in to comment.