Linking for Android


#1

Hi,

I am trying to build a library for Android in Rust. The library is not loadable by JNI, which fails with:

java.lang.UnsatisfiedLinkError: dlopen failed: cannot locate symbol "rust_begin_unwind" referenced by "/data/app/<name-of-app>/lib/x86/lib<name-of-lib>.so"...

The build/link command is:

cargo rustc --target=i686-linux-android -- -C linker=tmp/ndk.x86/bin/i686-linux-android-gcc

where tmp/ndk.x86 is a so-called “standalone build” of the NDK.

The error seems to be saying that the library is missing some symbols related to Rust exception handling. It stands to reason that everything from Rust these should be statically linked; but it’s not clear how to accomplish this (what options to pass, &c).

There are some templates online and I am just about to the point of using them; but it would be nice to understand what is going wrong here.

Kind Regards,
Jason Dusek


#2

Do you really need unwinding in library? Maybe try -C panic=abort?


#3

Still seems to get in there somehow:

:;  nm -D target/i686-linux-android/debug/libinstaconst.so | fgrep rust_
         U rust_begin_unwind

Although panic = "abort" is being picked up from Cargo.toml:

:;  cargo build -v --target=i686-linux-android
   Compiling libc v0.2.15
     Running `rustc /Users/solidsnack/.cargo/registry/src/github.com-1ecc6299db9ec823/libc-0.2.15/src/lib.rs --crate-name libc --crate-type lib -C panic=abort ...`
   Compiling jni-sys v0.1.0
     Running `rustc /Users/solidsnack/.cargo/registry/src/github.com-1ecc6299db9ec823/jni-sys-0.1.0/src/lib.rs --crate-name jni_sys --crate-type lib -C panic=abort ...`
    [...]
    Finished debug [unoptimized + debuginfo] target(s) in 2.31 secs

#4

You should try compiling your library as a cdylib if you’re not doing so.
I’m not familiar with how all that linking works, but the cdylib crate type is meant specifically for Rust libraries that are going to be opened/used from a non-Rust environment.


#5

Presently, I am compiling with the cdylib. When compiled against the default target (Mac), the library has t for rust_begin_unwind instead of U:

:;  nm target/debug/libinstaconst.dylib | fgrep rust_
00000000000059d0 t __ZN3std9panicking20rust_panic_with_hook17h2224f33fb7bf2f4cE
0000000000007880 T ___rust_allocate
00000000000078c0 T ___rust_deallocate
0000000000005e00 T ___rust_maybe_catch_panic
00000000000078d0 T ___rust_reallocate
0000000000007960 T ___rust_reallocate_inplace
0000000000005e10 T ___rust_start_panic
0000000000007970 T ___rust_usable_size
0000000000005810 t _rust_begin_unwind
0000000000005e20 T _rust_eh_personality
0000000000005bb0 t _rust_panic

#6

According to Advanced Linking, “Pure-Rust dependencies are statically linked by default…”. This would seem to suggest that rust_begin_unwind would be linked into the project from libstd. However, this is not actually happening.


#7

Is this a #![no_std] crate? Can you post here what arguments does rustc give to gcc?


#8

It’s not a no_std crate.

How do I print the linker args during build?


#9

rustc -g ... and such does not seem to do anything.

Ditto setting VERBOSE=1, RUST_VERBOSE=1, CARGO_VERBOSE=1.


#10

Please find below a sample tree.

/Users/solidsnack/.multirust/toolchains/nightly-x86_64-apple-darwin/lib/rustlib/i686-linux-android/lib/libunwind-411f48d3.rlib is in there as is libstd. I’m not sure what it means to pass an rlib to GCC.

─┬= 33459 solidsnack -bash
 └─┬= 63992 solidsnack /Applications/Xcode.app/Contents/Developer/usr/bin/make
   └─┬─ 63993 solidsnack cargo build -v --target=i686-linux-android
     └─┬─ 63994 solidsnack /Users/solidsnack/.multirust/toolchains/nightly-x86_64-apple-darwin/bin/cargo build -v --target=i686-linux-android
       └─┬─ 64091 solidsnack rustc src/lib.rs --crate-name instaconst --crate-type cdylib -g -C metadata=db879da4fb129e1e --out-dir /Users/solidsnack/sandbox/RustNDK/instaconst/target/i686-linux-android/debug/deps --emit=dep-info,link --target i686-linux-android -C ar=/Users/solidsnack/sandbox/RustNDK/instaconst/tmp/ndk.x86/bin/i686-linux-android-ar -C linker=/Users/solidsnack/sandbox/RustNDK/instaconst/tmp/ndk.x86/bin/i686-linux-android-gcc -L dependency=/Users/solidsnack/sandbox/RustNDK/instaconst/target/i686-linux-android/debug/deps --extern jni_sys=/Users/solidsnack/sandbox/RustNDK/instaconst/target/i686-linux-android/debug/deps/libjni_sys-4216f697fadf9126.rlib
         └─┬─ 64094 solidsnack /Users/solidsnack/.multirust/toolchains/nightly-x86_64-apple-darwin/bin/rustc src/lib.rs --crate-name instaconst --crate-type cdylib -g -C metadata=db879da4fb129e1e --out-dir /Users/solidsnack/sandbox/RustNDK/instaconst/target/i686-linux-android/debug/deps --emit=dep-info,link --target i686-linux-android -C ar=/Users/solidsnack/sandbox/RustNDK/instaconst/tmp/ndk.x86/bin/i686-linux-android-ar -C linker=/Users/solidsnack/sandbox/RustNDK/instaconst/tmp/ndk.x86/bin/i686-linux-android-gcc -L dependency=/Users/solidsnack/sandbox/RustNDK/instaconst/target/i686-linux-android/debug/deps --extern jni_sys=/Users/solidsnack/sandbox/RustNDK/instaconst/target/i686-linux-android/debug/deps/libjni_sys-4216f697fadf9126.rlib
           └─┬─ 64101 solidsnack /Users/solidsnack/sandbox/RustNDK/instaconst/tmp/ndk.x86/bin/i686-linux-android-gcc -Wl,--as-needed -Wl,-z,noexecstack -Wl,--allow-multiple-definition -L /Users/solidsnack/.multirust/toolchains/nightly-x86_64-apple-darwin/lib/rustlib/i686-linux-android/lib /Users/solidsnack/sandbox/RustNDK/instaconst/target/i686-linux-android/debug/deps/instaconst.0.o -o /Users/solidsnack/sandbox/RustNDK/instaconst/target/i686-linux-android/debug/deps/libinstaconst.so -Wl,--retain-symbols-file=/var/folders/0r/d4jxxrk51wsg1plg1ltj3fg00000gn/T/rustc.GpAxKXglMnqo/list -Wl,--gc-sections -nodefaultlibs -L /Users/solidsnack/sandbox/RustNDK/instaconst/target/i686-linux-android/debug/deps -L /Users/solidsnack/.multirust/toolchains/nightly-x86_64-apple-darwin/lib/rustlib/i686-linux-android/lib -Wl,-Bstatic -Wl,-Bdynamic /Users/solidsnack/sandbox/RustNDK/instaconst/target/i686-linux-android/debug/deps/libjni_sys-4216f697fadf9126.rlib /Users/solidsnack/sandbox/RustNDK/instaconst/target/i686-linux-android/debug/deps/liblibc-1bd8847afb79f283.rlib /Users/solidsnack/.multirust/toolchains/nightly-x86_64-apple-darwin/lib/rustlib/i686-linux-android/lib/libstd-411f48d3.rlib /Users/solidsnack/.multirust/toolchains/nightly-x86_64-apple-darwin/lib/rustlib/i686-linux-android/lib/libpanic_unwind-411f48d3.rlib /Users/solidsnack/.multirust/toolchains/nightly-x86_64-apple-darwin/lib/rustlib/i686-linux-android/lib/libunwind-411f48d3.rlib /Users/solidsnack/.multirust/toolchains/nightly-x86_64-apple-darwin/lib/rustlib/i686-linux-android/lib/librand-411f48d3.rlib /Users/solidsnack/.multirust/toolchains/nightly-x86_64-apple-darwin/lib/rustlib/i686-linux-android/lib/libcollections-411f48d3.rlib /Users/solidsnack/.multirust/toolchains/nightly-x86_64-apple-darwin/lib/rustlib/i686-linux-android/lib/librustc_unicode-411f48d3.rlib /Users/solidsnack/.multirust/toolchains/nightly-x86_64-apple-darwin/lib/rustlib/i686-linux-android/lib/liballoc-411f48d3.rlib /Users/solidsnack/.multirust/toolchains/nightly-x86_64-apple-darwin/lib/rustlib/i686-linux-android/lib/liballoc_system-411f48d3.rlib /Users/solidsnack/.multirust/toolchains/nightly-x86_64-apple-darwin/lib/rustlib/i686-linux-android/lib/liblibc-411f48d3.rlib /Users/solidsnack/.multirust/toolchains/nightly-x86_64-apple-darwin/lib/rustlib/i686-linux-android/lib/libcore-411f48d3.rlib -l dl -l log -l gcc -l gcc -l c -l m -shared -l compiler-rt
             └─┬─ 64102 solidsnack /Users/solidsnack/sandbox/RustNDK/instaconst/tmp/ndk.x86/bin/../libexec/gcc/i686-linux-android/4.9.x/collect2 -plugin /Users/solidsnack/sandbox/RustNDK/instaconst/tmp/ndk.x86/bin/../libexec/gcc/i686-linux-android/4.9.x/liblto_plugin.so -plugin-opt=/Users/solidsnack/sandbox/RustNDK/instaconst/tmp/ndk.x86/bin/../libexec/gcc/i686-linux-android/4.9.x/lto-wrapper -plugin-opt=-fresolution=/var/folders/0r/d4jxxrk51wsg1plg1ltj3fg00000gn/T//cc3vVDUr.res --sysroot=/Users/solidsnack/sandbox/RustNDK/instaconst/tmp/ndk.x86/bin/../sysroot --eh-frame-hdr -m elf_i386 -shared -Bsymbolic -z noexecstack -z relro -z now -o /Users/solidsnack/sandbox/RustNDK/instaconst/target/i686-linux-android/debug/deps/libinstaconst.so /Users/solidsnack/sandbox/RustNDK/instaconst/tmp/ndk.x86/bin/../sysroot/usr/lib/crtbegin_so.o -L/Users/solidsnack/.multirust/toolchains/nightly-x86_64-apple-darwin/lib/rustlib/i686-linux-android/lib -L/Users/solidsnack/sandbox/RustNDK/instaconst/target/i686-linux-android/debug/deps -L/Users/solidsnack/.multirust/toolchains/nightly-x86_64-apple-darwin/lib/rustlib/i686-linux-android/lib -L/Users/solidsnack/sandbox/RustNDK/instaconst/tmp/ndk.x86/bin/../lib/gcc/i686-linux-android/4.9.x -L/Users/solidsnack/sandbox/RustNDK/instaconst/tmp/ndk.x86/bin/../lib/gcc -L/Users/solidsnack/sandbox/RustNDK/instaconst/tmp/ndk.x86/bin/../lib/gcc/i686-linux-android/4.9.x/../../../../i686-linux-android/lib -L/Users/solidsnack/sandbox/RustNDK/instaconst/tmp/ndk.x86/bin/../sysroot/usr/lib --as-needed -z noexecstack --allow-multiple-definition /Users/solidsnack/sandbox/RustNDK/instaconst/target/i686-linux-android/debug/deps/instaconst.0.o --retain-symbols-file=/var/folders/0r/d4jxxrk51wsg1plg1ltj3fg00000gn/T/rustc.GpAxKXglMnqo/list --gc-sections -Bstatic -Bdynamic /Users/solidsnack/sandbox/RustNDK/instaconst/target/i686-linux-android/debug/deps/libjni_sys-4216f697fadf9126.rlib /Users/solidsnack/sandbox/RustNDK/instaconst/target/i686-linux-android/debug/deps/liblibc-1bd8847afb79f283.rlib /Users/solidsnack/.multirust/toolchains/nightly-x86_64-apple-darwin/lib/rustlib/i686-linux-android/lib/libstd-411f48d3.rlib /Users/solidsnack/.multirust/toolchains/nightly-x86_64-apple-darwin/lib/rustlib/i686-linux-android/lib/libpanic_unwind-411f48d3.rlib /Users/solidsnack/.multirust/toolchains/nightly-x86_64-apple-darwin/lib/rustlib/i686-linux-android/lib/libunwind-411f48d3.rlib /Users/solidsnack/.multirust/toolchains/nightly-x86_64-apple-darwin/lib/rustlib/i686-linux-android/lib/librand-411f48d3.rlib /Users/solidsnack/.multirust/toolchains/nightly-x86_64-apple-darwin/lib/rustlib/i686-linux-android/lib/libcollections-411f48d3.rlib /Users/solidsnack/.multirust/toolchains/nightly-x86_64-apple-darwin/lib/rustlib/i686-linux-android/lib/librustc_unicode-411f48d3.rlib /Users/solidsnack/.multirust/toolchains/nightly-x86_64-apple-darwin/lib/rustlib/i686-linux-android/lib/liballoc-411f48d3.rlib /Users/solidsnack/.multirust/toolchains/nightly-x86_64-apple-darwin/lib/rustlib/i686-linux-android/lib/liballoc_system-411f48d3.rlib /Users/solidsnack/.multirust/toolchains/nightly-x86_64-apple-darwin/lib/rustlib/i686-linux-android/lib/liblibc-411f48d3.rlib /Users/solidsnack/.multirust/toolchains/nightly-x86_64-apple-darwin/lib/rustlib/i686-linux-android/lib/libcore-411f48d3.rlib -ldl -llog -lgcc -lgcc -lc -lm -lcompiler-rt /Users/solidsnack/sandbox/RustNDK/instaconst/tmp/ndk.x86/bin/../sysroot/usr/lib/crtend_so.o
               └─── 64104 solidsnack /Users/solidsnack/sandbox/RustNDK/instaconst/tmp/ndk.x86/bin/../lib/gcc/i686-linux-android/4.9.x/../../../../i686-linux-android/bin/ld -plugin /Users/solidsnack/sandbox/RustNDK/instaconst/tmp/ndk.x86/bin/../libexec/gcc/i686-linux-android/4.9.x/liblto_plugin.so -plugin-opt=/Users/solidsnack/sandbox/RustNDK/instaconst/tmp/ndk.x86/bin/../libexec/gcc/i686-linux-android/4.9.x/lto-wrapper -plugin-opt=-fresolution=/var/folders/0r/d4jxxrk51wsg1plg1ltj3fg00000gn/T//cc3vVDUr.res --sysroot=/Users/solidsnack/sandbox/RustNDK/instaconst/tmp/ndk.x86/bin/../sysroot --eh-frame-hdr -m elf_i386 -shared -Bsymbolic -z noexecstack -z relro -z now -o /Users/solidsnack/sandbox/RustNDK/instaconst/target/i686-linux-android/debug/deps/libinstaconst.so /Users/solidsnack/sandbox/RustNDK/instaconst/tmp/ndk.x86/bin/../sysroot/usr/lib/crtbegin_so.o -L/Users/solidsnack/.multirust/toolchains/nightly-x86_64-apple-darwin/lib/rustlib/i686-linux-android/lib -L/Users/solidsnack/sandbox/RustNDK/instaconst/target/i686-linux-android/debug/deps -L/Users/solidsnack/.multirust/toolchains/nightly-x86_64-apple-darwin/lib/rustlib/i686-linux-android/lib -L/Users/solidsnack/sandbox/RustNDK/instaconst/tmp/ndk.x86/bin/../lib/gcc/i686-linux-android/4.9.x -L/Users/solidsnack/sandbox/RustNDK/instaconst/tmp/ndk.x86/bin/../lib/gcc -L/Users/solidsnack/sandbox/RustNDK/instaconst/tmp/ndk.x86/bin/../lib/gcc/i686-linux-android/4.9.x/../../../../i686-linux-android/lib -L/Users/solidsnack/sandbox/RustNDK/instaconst/tmp/ndk.x86/bin/../sysroot/usr/lib --as-needed -z noexecstack --allow-multiple-definition /Users/solidsnack/sandbox/RustNDK/instaconst/target/i686-linux-android/debug/deps/instaconst.0.o --retain-symbols-file=/var/folders/0r/d4jxxrk51wsg1plg1ltj3fg00000gn/T/rustc.GpAxKXglMnqo/list --gc-sections -Bstatic -Bdynamic /Users/solidsnack/sandbox/RustNDK/instaconst/target/i686-linux-android/debug/deps/libjni_sys-4216f697fadf9126.rlib /Users/solidsnack/sandbox/RustNDK/instaconst/target/i686-linux-android/debug/deps/liblibc-1bd8847afb79f283.rlib /Users/solidsnack/.multirust/toolchains/nightly-x86_64-apple-darwin/lib/rustlib/i686-linux-android/lib/libstd-411f48d3.rlib /Users/solidsnack/.multirust/toolchains/nightly-x86_64-apple-darwin/lib/rustlib/i686-linux-android/lib/libpanic_unwind-411f48d3.rlib /Users/solidsnack/.multirust/toolchains/nightly-x86_64-apple-darwin/lib/rustlib/i686-linux-android/lib/libunwind-411f48d3.rlib /Users/solidsnack/.multirust/toolchains/nightly-x86_64-apple-darwin/lib/rustlib/i686-linux-android/lib/librand-411f48d3.rlib /Users/solidsnack/.multirust/toolchains/nightly-x86_64-apple-darwin/lib/rustlib/i686-linux-android/lib/libcollections-411f48d3.rlib /Users/solidsnack/.multirust/toolchains/nightly-x86_64-apple-darwin/lib/rustlib/i686-linux-android/lib/librustc_unicode-411f48d3.rlib /Users/solidsnack/.multirust/toolchains/nightly-x86_64-apple-darwin/lib/rustlib/i686-linux-android/lib/liballoc-411f48d3.rlib /Users/solidsnack/.multirust/toolchains/nightly-x86_64-apple-darwin/lib/rustlib/i686-linux-android/lib/liballoc_system-411f48d3.rlib /Users/solidsnack/.multirust/toolchains/nightly-x86_64-apple-darwin/lib/rustlib/i686-linux-android/lib/liblibc-411f48d3.rlib /Users/solidsnack/.multirust/toolchains/nightly-x86_64-apple-darwin/lib/rustlib/i686-linux-android/lib/libcore-411f48d3.rlib -ldl -llog -lgcc -lgcc -lc -lm -lcompiler-rt /Users/solidsnack/sandbox/RustNDK/instaconst/tmp/ndk.x86/bin/../sysroot/usr/lib/crtend_so.o

#11

How do I print the linker args during build?

I thought rustc prints them out whenever linking fails. But maybe cargo hides that? Try cargo build -vv. Also, there’s rustc ... -Zprint-link-args.

In any case, it looks like rutsc is trying to link libpanic_unwind into your binary, which should have defined the panic_fmt lang item. I don’t know why this isn’t working…


#12

Linking is succeeding on the Rust side, in the sense that the commands exit without error. What is odd is that rust_begin_unwind is undefined on the cross build (Android ARM or Android x86) but defined for the default build.

:;  nm -D target/i686-linux-android/debug/libinstaconst.so | fgrep rust_begin
         U rust_begin_unwind

:;  nm -D target/arm-linux-androideabi/debug/libinstaconst.so | fgrep rust_begin
         U rust_begin_unwind

:;  nm target/debug/libinstaconst.dylib | fgrep rust_begin
0000000000004ea0 t _rust_begin_unwind

#13

Fixed it by implementing and exporting rust_begin_unwind as a loop:

#[allow(unused_variables)]
#[no_mangle]
pub extern
fn rust_begin_unwind(fmt: fmt::Arguments, file: &'static str, line: u32) -> ! {
    loop {}
}

#14

How i can integrate it in app like https://mobilerecorder24.com/ mobile recorder on Android?


#15

Integrate what, rust or rust_begin_unwind patch?