Brad Fitzpatrick | 5194744 | 2016-03-01 22:57:46 +0000 | [diff] [blame] | 1 | // Copyright 2014 The Go Authors. All rights reserved. |
David Crawshaw | 72faffb | 2014-07-03 21:04:48 -0400 | [diff] [blame] | 2 | // Use of this source code is governed by a BSD-style |
| 3 | // license that can be found in the LICENSE file. |
| 4 | |
David Crawshaw | 72faffb | 2014-07-03 21:04:48 -0400 | [diff] [blame] | 5 | #include <stdarg.h> |
| 6 | #include <android/log.h> |
Elias Naur | 1d10b17 | 2019-03-28 13:11:53 +0100 | [diff] [blame] | 7 | #include <pthread.h> |
Elias Naur | 95f1875 | 2019-03-29 12:13:02 +0100 | [diff] [blame] | 8 | #include <dlfcn.h> |
David Crawshaw | 72faffb | 2014-07-03 21:04:48 -0400 | [diff] [blame] | 9 | #include "libcgo.h" |
| 10 | |
| 11 | void |
| 12 | fatalf(const char* format, ...) |
| 13 | { |
| 14 | va_list ap; |
| 15 | |
| 16 | // Write to both stderr and logcat. |
| 17 | // |
| 18 | // When running from an .apk, /dev/stderr and /dev/stdout |
| 19 | // redirect to /dev/null. And when running a test binary |
| 20 | // via adb shell, it's easy to miss logcat. |
| 21 | |
| 22 | fprintf(stderr, "runtime/cgo: "); |
| 23 | va_start(ap, format); |
| 24 | vfprintf(stderr, format, ap); |
| 25 | va_end(ap); |
| 26 | fprintf(stderr, "\n"); |
| 27 | |
| 28 | va_start(ap, format); |
| 29 | __android_log_vprint(ANDROID_LOG_FATAL, "runtime/cgo", format, ap); |
| 30 | va_end(ap); |
| 31 | |
| 32 | abort(); |
| 33 | } |
Elias Naur | 1d10b17 | 2019-03-28 13:11:53 +0100 | [diff] [blame] | 34 | |
| 35 | // Truncated to a different magic value on 32-bit; that's ok. |
| 36 | #define magic1 (0x23581321345589ULL) |
| 37 | |
Alberto Donizetti | c9442dc | 2020-05-09 17:10:32 +0200 | [diff] [blame] | 38 | // From https://android.googlesource.com/platform/bionic/+/refs/heads/android10-tests-release/libc/private/bionic_asm_tls.h#69. |
Elias Naur | 95f1875 | 2019-03-29 12:13:02 +0100 | [diff] [blame] | 39 | #define TLS_SLOT_APP 2 |
| 40 | |
Elias Naur | 1d10b17 | 2019-03-28 13:11:53 +0100 | [diff] [blame] | 41 | // inittls allocates a thread-local storage slot for g. |
| 42 | // |
| 43 | // It finds the first available slot using pthread_key_create and uses |
| 44 | // it as the offset value for runtime.tls_g. |
| 45 | static void |
| 46 | inittls(void **tlsg, void **tlsbase) |
| 47 | { |
| 48 | pthread_key_t k; |
| 49 | int i, err; |
Elias Naur | f18c31a | 2019-04-08 17:57:53 +0200 | [diff] [blame] | 50 | void *handle, *get_ver, *off; |
Elias Naur | 95f1875 | 2019-03-29 12:13:02 +0100 | [diff] [blame] | 51 | |
| 52 | // Check for Android Q where we can use the free TLS_SLOT_APP slot. |
Elias Naur | fc7ac2e | 2019-04-02 23:58:43 +0200 | [diff] [blame] | 53 | handle = dlopen("libc.so", RTLD_LAZY); |
Elias Naur | 95f1875 | 2019-03-29 12:13:02 +0100 | [diff] [blame] | 54 | if (handle == NULL) { |
| 55 | fatalf("inittls: failed to dlopen main program"); |
| 56 | return; |
| 57 | } |
| 58 | // android_get_device_api_level is introduced in Android Q, so its mere presence |
| 59 | // is enough. |
| 60 | get_ver = dlsym(handle, "android_get_device_api_level"); |
| 61 | dlclose(handle); |
| 62 | if (get_ver != NULL) { |
Elias Naur | f18c31a | 2019-04-08 17:57:53 +0200 | [diff] [blame] | 63 | off = (void *)(TLS_SLOT_APP*sizeof(void *)); |
| 64 | // tlsg is initialized to Q's free TLS slot. Verify it while we're here. |
| 65 | if (*tlsg != off) { |
| 66 | fatalf("tlsg offset wrong, got %ld want %ld\n", *tlsg, off); |
| 67 | } |
Elias Naur | 95f1875 | 2019-03-29 12:13:02 +0100 | [diff] [blame] | 68 | return; |
| 69 | } |
Elias Naur | 1d10b17 | 2019-03-28 13:11:53 +0100 | [diff] [blame] | 70 | |
| 71 | err = pthread_key_create(&k, nil); |
| 72 | if(err != 0) { |
| 73 | fatalf("pthread_key_create failed: %d", err); |
| 74 | } |
| 75 | pthread_setspecific(k, (void*)magic1); |
| 76 | // If thread local slots are laid out as we expect, our magic word will |
| 77 | // be located at some low offset from tlsbase. However, just in case something went |
| 78 | // wrong, the search is limited to sensible offsets. PTHREAD_KEYS_MAX was the |
| 79 | // original limit, but issue 19472 made a higher limit necessary. |
| 80 | for (i=0; i<384; i++) { |
| 81 | if (*(tlsbase+i) == (void*)magic1) { |
| 82 | *tlsg = (void*)(i*sizeof(void *)); |
| 83 | pthread_setspecific(k, 0); |
| 84 | return; |
| 85 | } |
| 86 | } |
Elias Naur | 95f1875 | 2019-03-29 12:13:02 +0100 | [diff] [blame] | 87 | fatalf("inittls: could not find pthread key"); |
Elias Naur | 1d10b17 | 2019-03-28 13:11:53 +0100 | [diff] [blame] | 88 | } |
| 89 | |
| 90 | void (*x_cgo_inittls)(void **tlsg, void **tlsbase) = inittls; |