fix(android): -Wl,--exclude-libs,ALL + --no-whole-archive to stop symbol leak
llvm-nm on the crashing .so confirmed the research's smoking gun theory: 000000000130c1f0 t _Z10__init_tcbP10bionic_tcbP18pthread_internal_t 0000000000000000 a pthread_create.cpp 0000000001331108 t pthread_create All lowercase 't' (= LOCAL text symbols), zero UND dynamic references for pthread_create. So rustc's link step is pulling bionic's own pthread_create.cpp compilation unit out of libc.a as a whole-archive inclusion and binding those symbols locally inside our .so, instead of letting them stay UND and resolved against libc.so at dlopen time. Rust's libstd thread::spawn then calls the LOCAL (broken) pthread_create which calls the LOCAL __init_tcb with arguments set up for bionic's static-executable layout — crashes at __init_tcb+4 with SEGV_ACCERR. `-Wl,--exclude-libs,ALL` tells the linker to make symbols from static archives NOT appear in the dynamic symbol table of the output .so. `-Wl,--no-whole-archive` tells it to only pull archive objects that satisfy undefined references, not include the whole archive blindly. If this works, the symbol table should show pthread_create as UND (or at least not locally bound) and the app should launch. If it doesn't, the remaining fallback is the research's action #3 — extract the C++ into its own upstream cdylib crate built with cargo-ndk, and dlopen it from the Tauri cdylib at runtime. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -57,6 +57,15 @@ fn main() {
|
|||||||
.file("cpp/cpp_smoke.cpp")
|
.file("cpp/cpp_smoke.cpp")
|
||||||
.compile("wzp_cpp_smoke");
|
.compile("wzp_cpp_smoke");
|
||||||
|
|
||||||
|
// Per rust-lang/rust#104707 + the android-ndk advice: force the
|
||||||
|
// linker to keep bionic symbols (pthread_create, __init_tcb) as
|
||||||
|
// UND dynamic references resolved against libc.so at runtime,
|
||||||
|
// not bound locally from libc.a that cc-rs + cpp(true) drag in.
|
||||||
|
// llvm-nm confirmed these symbols were landing in our .so as
|
||||||
|
// LOCAL (lowercase t), which is exactly the bug.
|
||||||
|
println!("cargo:rustc-link-arg=-Wl,--exclude-libs,ALL");
|
||||||
|
println!("cargo:rustc-link-arg=-Wl,--no-whole-archive");
|
||||||
|
|
||||||
// Copy libc++_shared.so from the NDK sysroot to gen/android jniLibs
|
// Copy libc++_shared.so from the NDK sysroot to gen/android jniLibs
|
||||||
// so the runtime linker can find it at dlopen time (it's now in the
|
// so the runtime linker can find it at dlopen time (it's now in the
|
||||||
// .so's NEEDED list thanks to cpp_link_stdlib("c++_shared") above).
|
// .so's NEEDED list thanks to cpp_link_stdlib("c++_shared") above).
|
||||||
|
|||||||
Reference in New Issue
Block a user