linkobj = append(linkobj, p.SysoFiles...)
dynobj := obj + "_cgo_.o"
- if goarch == "arm" && goos == "linux" { // we need to use -pie for Linux/ARM to get accurate imported sym
+ pie := goarch == "arm" && (goos == "linux" || goos == "android")
+ if pie { // we need to use -pie for Linux/ARM to get accurate imported sym
cgoLDFLAGS = append(cgoLDFLAGS, "-pie")
}
if err := b.gccld(p, dynobj, cgoLDFLAGS, linkobj); err != nil {
return nil, nil, err
}
- if goarch == "arm" && goos == "linux" { // but we don't need -pie for normal cgo programs
+ if pie { // but we don't need -pie for normal cgo programs
cgoLDFLAGS = cgoLDFLAGS[0 : len(cgoLDFLAGS)-1]
}
if(r->sym != S && r->sym->type != STLSBSS && !r->sym->reachable)
diag("unreachable sym in relocation: %s %s", s->name, r->sym->name);
+ // Android emulates runtime.tlsg as a regular variable.
+ if (r->type == R_TLS && strcmp(goos, "android") == 0)
+ r->type = R_ADDR;
+
switch(r->type) {
default:
o = 0;
if(sect->rwx & 2)
sh->flags |= SHF_WRITE;
if(strcmp(sect->name, ".tbss") == 0) {
- sh->flags |= SHF_TLS;
+ if(strcmp(goos, "android") != 0)
+ sh->flags |= SHF_TLS; // no TLS on android
sh->type = SHT_NOBITS;
}
if(linkmode != LinkExternal)
linkmode = LinkExternal;
else
linkmode = LinkInternal;
+
+ // Force external linking for android.
+ if(strcmp(goos, "android") == 0)
+ linkmode = LinkExternal;
}
if(linkmode == LinkInternal) {
if(HEADTYPE == -1)
HEADTYPE = headtype(goos);
ctxt->headtype = HEADTYPE;
- if (headstring == nil)
+ if(headstring == nil)
headstring = headstr(HEADTYPE);
archinit();
diag("missing section for %s", s->name);
errorexit();
}
- putelfsyment(putelfstr(s->name), 0, s->size, (STB_LOCAL<<4)|STT_TLS, s->sect->elfsect->shnum, 0);
+ if (strcmp(goos, "android") == 0) {
+ // Android emulates runtime.tlsg as a regular variable.
+ putelfsyment(putelfstr(s->name), 0, s->size, (STB_LOCAL<<4)|STT_OBJECT, s->sect->elfsect->shnum, 0);
+ } else {
+ putelfsyment(putelfstr(s->name), 0, s->size, (STB_LOCAL<<4)|STT_TLS, s->sect->elfsect->shnum, 0);
+ }
s->elfsym = numelfsym++;
}
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build !cgo,!windows,!plan9
+// +build !cgo,!windows,!plan9 android
package user
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin dragonfly freebsd linux netbsd openbsd solaris
+// +build darwin dragonfly freebsd !android,linux netbsd openbsd solaris
// +build cgo
package user
MOVW _cgo_init(SB), R4
CMP $0, R4
B.EQ nocgo
- BL runtime·save_g(SB);
- MOVW g, R0 // first argument of _cgo_init is g
- MOVW $setg_gcc<>(SB), R1 // second argument is address of save_g
- BL (R4) // will clobber R0-R3
+ MRC 15, 0, R0, C13, C0, 3 // load TLS base pointer
+ MOVW R0, R3 // arg 3: TLS base pointer
+ MOVW $runtime·tlsg(SB), R2 // arg 2: tlsg
+ MOVW $setg_gcc<>(SB), R1 // arg 1: setg
+ MOVW g, R0 // arg 0: G
+ BL (R4) // will clobber R0-R3
nocgo:
// update stackguard after _cgo_init
MOVB R7, v+16(FP)
RET
-// We have to resort to TLS variable to save g(R10).
-// One reason is that external code might trigger
-// SIGSEGV, and our runtime.sigtramp don't even know we
-// are in external code, and will continue to use R10,
-// this might as well result in another SIGSEGV.
-// Note: all three functions will clobber R0, and the last
-// two can be called from 5c ABI code.
-
-// save_g saves the g register into pthread-provided
-// thread-local memory, so that we can call externally compiled
-// ARM code that will overwrite those registers.
-// NOTE: runtime.gogo assumes that R1 is preserved by this function.
-// runtime.mcall assumes this function only clobbers R0 and R11.
-TEXT runtime·save_g(SB),NOSPLIT,$0
- MRC 15, 0, R0, C13, C0, 3 // fetch TLS base pointer
- // $runtime.tlsg(SB) is a special linker symbol.
- // It is the offset from the TLS base pointer to our
- // thread-local storage for g.
- MOVW $runtime·tlsg(SB), R11
- ADD R11, R0
- MOVW g, 0(R0)
- RET
-
-// load_g loads the g register from pthread-provided
-// thread-local memory, for use after calling externally compiled
-// ARM code that overwrote those registers.
-TEXT runtime·load_g(SB),NOSPLIT,$0
- MRC 15, 0, R0, C13, C0, 3 // fetch TLS base pointer
- // $runtime.tlsg(SB) is a special linker symbol.
- // It is the offset from the TLS base pointer to our
- // thread-local storage for g.
- MOVW $runtime·tlsg(SB), R11
- ADD R11, R0
- MOVW 0(R0), g
- RET
-
// void setg_gcc(G*); set g called from gcc.
TEXT setg_gcc<>(SB),NOSPLIT,$0
MOVW R0, g
#cgo darwin LDFLAGS: -lpthread
#cgo dragonfly LDFLAGS: -lpthread
#cgo freebsd LDFLAGS: -lpthread
-#cgo linux LDFLAGS: -lpthread
+#cgo android LDFLAGS: -llog
+#cgo !android,linux LDFLAGS: -lpthread
#cgo netbsd LDFLAGS: -lpthread
#cgo openbsd LDFLAGS: -lpthread
#cgo windows LDFLAGS: -lm -mthreads
--- /dev/null
+// Copyright 2014 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 <android/log.h>
+#include <pthread.h>
+#include <signal.h>
+#include <stdio.h>
+#include <sys/limits.h>
+#include "libcgo.h"
+
+#define magic1 (0x23581321U)
+
+// PTHREAD_KEYS_MAX has been added to sys/limits.h at head in bionic:
+// https://android.googlesource.com/platform/bionic/+/master/libc/include/sys/limits.h
+// TODO(crawshaw): remove this definition when a new NDK is released.
+#define PTHREAD_KEYS_MAX 128
+
+// 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.tlsg.
+static void
+inittls(void **tlsg, void **tlsbase)
+{
+ pthread_key_t k;
+ int i, err;
+
+ err = pthread_key_create(&k, nil);
+ if(err != 0) {
+ fprintf(stderr, "runtime/cgo: pthread_key_create failed: %d\n", err);
+ __android_log_print(ANDROID_LOG_FATAL, "runtime/cgo", "pthread_key_create failed: %d", err);
+ abort();
+ }
+ pthread_setspecific(k, (void*)magic1);
+ for (i=0; i<PTHREAD_KEYS_MAX; i++) {
+ if (*(tlsbase+i) == (void*)magic1) {
+ *tlsg = (void*)(i*sizeof(void *));
+ pthread_setspecific(k, 0);
+ return;
+ }
+ }
+ fprintf(stderr, "runtime/cgo: could not find pthread key\n");
+ __android_log_print(ANDROID_LOG_FATAL, "runtime/cgo", "could not find pthread key");
+ abort();
+}
+
+void (*x_cgo_inittls)(void **tlsg, void **tlsbase) = inittls;
static void *threadentry(void*);
-static void (*setg_gcc)(void*);
-
-void
-x_cgo_init(G *g, void (*setg)(void*))
-{
- pthread_attr_t attr;
- size_t size;
-
- setg_gcc = setg;
- pthread_attr_init(&attr);
- pthread_attr_getstacksize(&attr, &size);
- g->stackguard = (uintptr)&attr - size + 4096;
- pthread_attr_destroy(&attr);
-}
-
+void (*setg_gcc)(void*);
void
_cgo_sys_thread_start(ThreadStart *ts)
pthread_sigmask(SIG_SETMASK, &oset, nil);
if (err != 0) {
- fprintf(stderr, "runtime/cgo: pthread_create failed: %s\n", strerror(err));
- abort();
+ fatalf("pthread_create failed: %s", strerror(err));
}
}
crosscall_arm1(ts.fn, setg_gcc, (void*)ts.g);
return nil;
}
+
+void (*x_cgo_inittls)(void **tlsg, void **tlsbase);
+
+void
+x_cgo_init(G *g, void (*setg)(void*), void **tlsg, void **tlsbase)
+{
+ pthread_attr_t attr;
+ size_t size;
+
+ setg_gcc = setg;
+ pthread_attr_init(&attr);
+ pthread_attr_getstacksize(&attr, &size);
+ g->stackguard = (uintptr)&attr - size + 4096;
+ pthread_attr_destroy(&attr);
+
+ if (x_cgo_inittls) {
+ x_cgo_inittls(tlsg, tlsbase);
+ }
+}
--- /dev/null
+// Copyright 2014 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 "zasm_GOOS_GOARCH.h"
+#include "funcdata.h"
+#include "../../cmd/ld/textflag.h"
+
+// We have to resort to TLS variable to save g(R10).
+// One reason is that external code might trigger
+// SIGSEGV, and our runtime.sigtramp don't even know we
+// are in external code, and will continue to use R10,
+// this might as well result in another SIGSEGV.
+// Note: both functions will clobber R0 and R11 and
+// can be called from 5c ABI code.
+
+// On android, runtime.tlsg is a normal variable.
+// TLS offset is computed in x_cgo_inittls.
+
+// save_g saves the g register into pthread-provided
+// thread-local memory, so that we can call externally compiled
+// ARM code that will overwrite those registers.
+// NOTE: runtime.gogo assumes that R1 is preserved by this function.
+// runtime.mcall assumes this function only clobbers R0 and R11.
+TEXT runtime·save_g(SB),NOSPLIT,$0
+ MRC 15, 0, R0, C13, C0, 3 // fetch TLS base pointer
+ // $runtime.tlsg(SB) is a special linker symbol.
+ // It is the offset from the TLS base pointer to our
+ // thread-local storage for g.
+#ifdef GOOS_android
+ MOVW runtime·tlsg(SB), R11
+#else
+ MOVW $runtime·tlsg(SB), R11
+#endif
+ ADD R11, R0
+ MOVW g, 0(R0)
+ RET
+
+// load_g loads the g register from pthread-provided
+// thread-local memory, for use after calling externally compiled
+// ARM code that overwrote those registers.
+TEXT runtime·load_g(SB),NOSPLIT,$0
+ MRC 15, 0, R0, C13, C0, 3 // fetch TLS base pointer
+ // $runtime.tlsg(SB) is a special linker symbol.
+ // It is the offset from the TLS base pointer to our
+ // thread-local storage for g.
+#ifdef GOOS_android
+ MOVW runtime·tlsg(SB), R11
+#else
+ MOVW $runtime·tlsg(SB), R11
+#endif
+ ADD R11, R0
+ MOVW 0(R0), g
+ RET