Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

C/C++ code linked to Rust code can't use some clang builtins #109717

Open
glandium opened this issue Mar 29, 2023 · 3 comments
Open

C/C++ code linked to Rust code can't use some clang builtins #109717

glandium opened this issue Mar 29, 2023 · 3 comments
Labels
A-FFI Area: Foreign function interface (FFI) A-linkage Area: linking into static, shared libraries and binaries C-bug Category: This is a bug. E-hard Call for participation: Hard difficulty. Experience needed to fix: A lot. E-mentor Call for participation: This issue has a mentor. Use #t-compiler/help on Zulip for discussion. O-android Operating system: Android T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.

Comments

@glandium
Copy link
Contributor

This is theoretically a problem that applies to all platforms, but in practice, at least on Linux, the rust compiler is saved by the forced linkage of libgcc_s (which, incidentally, is not really desirable when using clang's --rtlib argument, but that's another story). It is a problem on x86_64 Android.

Here are steps to reproduce the problem:

Download and unpack Android NDK r25c:

$ wget https://dl.google.com/android/repository/android-ndk-r25c-linux.zip
$ unzip android-ndk-r25c-linux.zip

Create a test crate:

$ cargo new --bin testcase
$ cd testcase
$ cat <<EOF >> Cargo.toml
[build-dependencies]
cc = "1.0"
EOF
$ cat <<EOF > build.rs
fn main() {
    cc::Build::new().file("foo.cpp").compile("foo");
}
EOF
$ cat <<EOF > src/main.rs
#[link(name="foo")]
extern {
    fn foo(d: f64);
}

fn main() {
    unsafe {
        foo(42.0);
    }
}
EOF
$ cat <<EOF > foo.cpp
extern "C" __float128 foo(double d) {
    return d;
}
EOF

Compile the crate (with some manual work that presumable cargo-apk would do):

$ export RUSTFLAGS="-Clinker=$PWD/../android-ndk-r25c/toolchains/llvm/prebuilt/linux-x86_64/bin/clang -Clink-arg=--target=x86_64-linux-android31 -Clink-arg=--sysroot=/tmp/android-ndk-r25c/toolchains/llvm/prebuilt/linux-x86_64/sysroot"
$ export CC=$PWD/../android-ndk-r25c/toolchains/llvm/prebuilt/linux-x86_64/bin/clang
$ export AR=$PWD/../android-ndk-r25c/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-ar
$ cargo build --target=x86_64-linux-android

This fails to link with, eventually:

  = note: ld: error: undefined symbol: __extenddftf2
          >>> referenced by foo.cpp:2
          >>>               foo.o:(foo) in archive /tmp/testcase/target/x86_64-linux-android/debug/build/testcase-7b8046ba34d79ef2/out/libfoo.a
          clang-14: error: linker command failed with exit code 1 (use -v to see invocation)

The __extenddftft2 symbol comes from the compilation of the function foo, for the extension of the 64-bits double to a 128-bits double. It is part of libclang_rt that comes with clang. But because rustc calls the linker (clang) with -nodefaultlibs, the clang runtime is not compiled in. And because the equivalent compiler-builtins from rustc doesn't contain all the clang builtins, this fails to link.

When linking dynamic libraries, the link actually goes through without an error, but yields an error when the library is loaded at runtime because of the missing __extenddftft2 symbol. You'll find multiple people running into this problem over the years, but somehow I didn't find it reported against the rust compiler (example: mozilla/application-services#5436).

Because the __extenddftft2 symbol exists in rustc's compiler-builtins for aarch64 android, it's not a problem on that platform.

@glandium glandium added the C-bug Category: This is a bug. label Mar 29, 2023
@jyn514 jyn514 added A-linkage Area: linking into static, shared libraries and binaries O-android Operating system: Android A-FFI Area: Foreign function interface (FFI) T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. labels Apr 3, 2023
@jyn514
Copy link
Member

jyn514 commented Apr 3, 2023

But because rustc calls the linker (clang) with -nodefaultlibs, the clang runtime is not compiled in.

The first step in investigating this issue would be to find out why rustc currently passes -nodefaultlibs. It sounds like if we removed that flag, it would fix this bug?

@jyn514 jyn514 added E-hard Call for participation: Hard difficulty. Experience needed to fix: A lot. E-mentor Call for participation: This issue has a mentor. Use #t-compiler/help on Zulip for discussion. labels Apr 3, 2023
@glandium
Copy link
Contributor Author

glandium commented Apr 3, 2023

See 28fa81a.

@complexspaces
Copy link

Has anyone else had a chance to look at this issue more? With Rust's standard library only targeting NDK 25 in recent versions, I think that this issue has become more problematic for projects using the same NDK.

AFAICT, the symbol has to exist somewhere in clang's compiler-rt library if manually linking to it (as per the workaround everyone is using) fixes the issue. LLVM also has a codegen test for x86_64-android-linux with the symbol, so it seems to be expected. Optimistically, maybe Rust's compiler-builtins just needs to include something else or change a flag?

Niels-Be added a commit to Niels-Be/rusqlite that referenced this issue Nov 4, 2024
Adds a temporary workaround for [an issue] with the Rust compiler and Android when
compiling for x86_64 devices.

The Android NDK used to include `libgcc` for unwind support (which is required by Rust
among others). From NDK r23, `libgcc` is removed, replaced by LLVM's `libunwind`.
However, `libgcc` was ambiently providing other compiler builtins, one of which we
require: `__extenddftf2` for software floating-point emulation. This is used by SQLite
(via the `rusqlite` crate), which defines a `LONGDOUBLE_TYPE` type as `long double`.

Rust uses a `compiler-builtins` crate that does not provide `__extenddftf2` because
[it involves floating-point types that are not supported by Rust][unsupported]. For
some reason, they _do_ export this symbol for `aarch64-linux-android`, but they do not
for `x86_64-linux-android`. Thus we run into a problem when trying to compile and run
the SDK on an x86_64 emulator.

The workaround comes from [this Mozilla PR]: we tell Cargo to statically link the
builtins from the Clang runtime provided inside the NDK, to provide this symbol.

[an issue]: rust-lang/rust#109717
[this Mozilla PR]:mozilla/application-services#5442
[unsupported]: https://github.com/rust-lang/compiler-builtins#unimplemented-functions

This fix was copied from: https://github.com/nerdcash/Nerdbank.Cryptocurrencies/pull/262/files#diff-7cc5f1ef7cbfce3114fe631861f19de2c050c13ff71e987100669131bb9ffa25

Fixes rusqlite#1380
Niels-Be added a commit to Niels-Be/rusqlite that referenced this issue Nov 26, 2024
Adds a temporary workaround for [an issue] with the Rust compiler and Android when
compiling for x86_64 devices.

The Android NDK used to include `libgcc` for unwind support (which is required by Rust
among others). From NDK r23, `libgcc` is removed, replaced by LLVM's `libunwind`.
However, `libgcc` was ambiently providing other compiler builtins, one of which we
require: `__extenddftf2` for software floating-point emulation. This is used by SQLite
(via the `rusqlite` crate), which defines a `LONGDOUBLE_TYPE` type as `long double`.

Rust uses a `compiler-builtins` crate that does not provide `__extenddftf2` because
[it involves floating-point types that are not supported by Rust][unsupported]. For
some reason, they _do_ export this symbol for `aarch64-linux-android`, but they do not
for `x86_64-linux-android`. Thus we run into a problem when trying to compile and run
the SDK on an x86_64 emulator.

The workaround comes from [this Mozilla PR]: we tell Cargo to statically link the
builtins from the Clang runtime provided inside the NDK, to provide this symbol.

[an issue]: rust-lang/rust#109717
[this Mozilla PR]:mozilla/application-services#5442
[unsupported]: https://github.com/rust-lang/compiler-builtins#unimplemented-functions

This fix was copied from: Electric-Coin-Company/zcash-android-wallet-sdk@1bf2f84

Fixes rusqlite#1380

Co-authored-by: Jack Grigg <jack@electriccoin.co>
richvdh added a commit to matrix-org/matrix-rust-sdk that referenced this issue Dec 11, 2024
Update the workaround for rust-lang/rust#109717 to
avoid hardcoding the clang version; instead, run `clang -dumpversion` to figure
it out.

While we're there, use the `CC_x86_64-linux-android` env var, which should
point to clang, rather than relying on `ANDROID_NDK_HOME` to be set.
richvdh added a commit to matrix-org/matrix-rust-sdk that referenced this issue Dec 12, 2024
Update the workaround for rust-lang/rust#109717 to
avoid hardcoding the clang version; instead, run `clang -dumpversion` to figure
it out.

While we're there, use the `CC_x86_64-linux-android` env var, which should
point to clang, rather than relying on `ANDROID_NDK_HOME` to be set.
richvdh added a commit to matrix-org/matrix-rust-sdk that referenced this issue Dec 12, 2024
Update the workaround for rust-lang/rust#109717 to
avoid hardcoding the clang version; instead, run `clang -dumpversion` to figure
it out.

While we're there, use the `CC_x86_64-linux-android` env var, which should
point to clang, rather than relying on `ANDROID_NDK_HOME` to be set.
andybalaam pushed a commit to matrix-org/matrix-rust-sdk that referenced this issue Dec 18, 2024
Update the workaround for rust-lang/rust#109717 to
avoid hardcoding the clang version; instead, run `clang -dumpversion` to figure
it out.

While we're there, use the `CC_x86_64-linux-android` env var, which should
point to clang, rather than relying on `ANDROID_NDK_HOME` to be set.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-FFI Area: Foreign function interface (FFI) A-linkage Area: linking into static, shared libraries and binaries C-bug Category: This is a bug. E-hard Call for participation: Hard difficulty. Experience needed to fix: A lot. E-mentor Call for participation: This issue has a mentor. Use #t-compiler/help on Zulip for discussion. O-android Operating system: Android T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.
Projects
None yet
Development

No branches or pull requests

3 participants