diff --git a/app/android.c b/app/android.c index 942e4b3..5e98b75 100644 --- a/app/android.c +++ b/app/android.c @@ -48,41 +48,18 @@ static void* init_go_runtime(void* unused) { // Defensively heap-allocate argv0, for setenv. char* argv0 = strdup("gojni"); - // Build argv, including the ELF auxiliary vector, which is loaded - // from /proc/self/auxv. While there does not appear to be any - // spec for this format, there are some notes in - // - // Phrack, V. 0x0b, Issue 0x3a, P. 0x05. - // http://phrack.org/issues/58/5.html - // - // For our needs, we don't need to know the format beyond the fact - // that argv is followed by a meaningless envp, then a series of - // NUL terminated bytes that make up auxv. - + // Build argv, including the ELF auxiliary vector. struct { char* argv[2]; char* envp[2]; - char* auxv[1024]; + uint32_t auxv[64]; } x; x.argv[0] = argv0; x.argv[1] = NULL; x.envp[0] = argv0; x.envp[1] = NULL; - int fd = open("/proc/self/auxv", O_RDONLY, 0); - if (fd == -1) { - __android_log_print(ANDROID_LOG_FATAL, "Go", "cannot open /proc/self/auxv: %s", strerror(errno)); - } - int n = read(fd, &x.auxv, sizeof x.auxv - 1); - if (n < 0) { - __android_log_print(ANDROID_LOG_FATAL, "Go", "error reading /proc/self/auxv: %s", strerror(errno)); - } - if (n == sizeof x.auxv - 1) { // x.auxv should be more than plenty. - __android_log_print(ANDROID_LOG_FATAL, "Go", "/proc/self/auxv too big"); - } - close(fd); - x.auxv[n / sizeof(char*)] = NULL; - + build_auxv(x.auxv, sizeof(x.auxv)/sizeof(uint32_t)); int32_t argc = 1; _rt0_arm_linux1(argc, x.argv); return NULL; diff --git a/app/android.go b/app/android.go index ffcc9c8..d804934 100644 --- a/app/android.go +++ b/app/android.go @@ -33,6 +33,21 @@ int go_started; // OpenJDK there is JNI_GetCreatedJavaVMs, but this is not available // on android. JavaVM* current_vm; + +// build_auxv builds an ELF auxiliary vector for initializing the Go +// runtime. While there does not appear to be any spec for this +// format, there are some notes in +// +// Phrack, V. 0x0b, Issue 0x3a, P. 0x05. +// http://phrack.org/issues/58/5.html +// +// Much of the time on linux the real auxv can be read from the file +// /proc/self/auxv, however there are several conditions under which +// Android apps cannot read this file (see a note to this effect in +// sources/android/cpufeatures/cpu-features.c). So we construct a +// fake one, working backwards from what the Go runtime wants to see +// as defined by the code in src/runtime/os_linux_GOARCH.c. +void build_auxv(uint32_t *auxv, size_t len); */ import "C" import ( diff --git a/app/android_arm.c b/app/android_arm.c new file mode 100644 index 0000000..e9b9b21 --- /dev/null +++ b/app/android_arm.c @@ -0,0 +1,31 @@ +// 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. + +// +build android,arm + +#include +#include +#include +#include "_cgo_export.h" + +#define AT_PLATFORM 15 +#define AT_HWCAP 16 +#define HWCAP_VFP (1 << 6) +#define HWCAP_VFPv3 (1 << 13) + +void build_auxv(uint32_t *auxv, size_t len) { + // Minimum auxv required by runtime/os_linux_arm.go. + int i; + if (len < 5) { + __android_log_print(ANDROID_LOG_FATAL, "Go", "auxv len %d too small", len); + } + auxv[0] = AT_PLATFORM; + *(char**)&auxv[1] = strdup("v7l"); + + auxv[2] = AT_HWCAP; + auxv[3] = HWCAP_VFP | HWCAP_VFPv3; + for (i = 4; i < len; i++) { + auxv[i] = 0; + } +} diff --git a/app/android_x86.c b/app/android_x86.c new file mode 100644 index 0000000..6393422 --- /dev/null +++ b/app/android_x86.c @@ -0,0 +1,38 @@ +// 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. + +// +build android,x86 + +#include +#include +#include +#include +#include +#include +#include +#include "_cgo_export.h" + +void build_auxv(uint32_t *xauxv, size_t xauxv_len) { + char* auxv = (char*)xauxv; + size_t auxv_len = xauxv_len*sizeof(uint32_t); + + // TODO(crawshaw): determine if we can read /proc/self/auxv on + // x86 android release builds. + int fd = open("/proc/self/auxv", O_RDONLY, 0); + if (fd == -1) { + __android_log_print(ANDROID_LOG_FATAL, "Go", "cannot open /proc/self/auxv: %s", strerror(errno)); + } + int n = read(fd, &auxv, auxv_len); + if (n < 0) { + __android_log_print(ANDROID_LOG_FATAL, "Go", "error reading /proc/self/auxv: %s", strerror(errno)); + } + if (n == auxv_len) { // auxv should be more than plenty. + __android_log_print(ANDROID_LOG_FATAL, "Go", "/proc/self/auxv too big"); + } + close(fd); + + for (; n < auxv_len; n++) { + auxv[n] = 0; + } +}