diff --git a/desktop/src-tauri/build.rs b/desktop/src-tauri/build.rs index e17495c..caf85a4 100644 --- a/desktop/src-tauri/build.rs +++ b/desktop/src-tauri/build.rs @@ -38,6 +38,14 @@ fn build_oboe_android(target: &str) { .file("cpp/getauxval_fix.c") .compile("getauxval_fix"); + // pthread_shim: interpose pthread_create so Rust libstd can't use the + // broken static pthread_create stub (which calls __init_tcb, crashing + // in a .so). Our shim forwards to libc.so's real one via RTLD_NEXT. + // Compiled as its own static lib so the linker links it ahead of libstd. + cc::Build::new() + .file("cpp/pthread_shim.c") + .compile("pthread_shim"); + let oboe_dir = fetch_oboe(); match oboe_dir { Some(oboe_path) => { diff --git a/desktop/src-tauri/cpp/pthread_shim.c b/desktop/src-tauri/cpp/pthread_shim.c new file mode 100644 index 0000000..f56d748 --- /dev/null +++ b/desktop/src-tauri/cpp/pthread_shim.c @@ -0,0 +1,45 @@ +/* pthread_shim.c + * + * Interpose pthread_create to bypass the broken static stub that Rust's + * pre-compiled libstd for aarch64-linux-android drags in. + * + * The stub (from an old NDK libc.a) calls __init_tcb(bionic_tcb*, ...)+4, + * which SIGSEGVs in .so libraries because __init_tcb expects TCB state that + * only the static-libc init path sets up. In a dlopen-loaded shared lib + * nothing ever initialises that state. + * + * By providing our own pthread_create at link time (which takes priority + * over the one dragged in by libstd) and forwarding it via dlsym(RTLD_NEXT) + * to the REAL pthread_create in libc.so, we completely sidestep the static + * stub — libc.so's pthread_create is the fully working runtime version. + * + * The same trick handles `getauxval` via getauxval_fix.c. + */ + +#ifdef __ANDROID__ + +#define _GNU_SOURCE +#include +#include +#include + +typedef int (*pthread_create_fn)(pthread_t *, const pthread_attr_t *, + void *(*)(void *), void *); + +int pthread_create(pthread_t *thread, const pthread_attr_t *attr, + void *(*start_routine)(void *), void *arg) { + static pthread_create_fn real_pthread_create = NULL; + if (real_pthread_create == NULL) { + /* RTLD_NEXT: skip the symbol we're currently defining and return + * the next one in the search order — which is the real pthread_create + * exported from libc.so. */ + real_pthread_create = + (pthread_create_fn)dlsym(RTLD_NEXT, "pthread_create"); + if (real_pthread_create == NULL) { + return -1; + } + } + return real_pthread_create(thread, attr, start_routine, arg); +} + +#endif /* __ANDROID__ */