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

linker-plugin-lto stopped working in Rust 1.45.0 #74657

Closed
heftig opened this issue Jul 22, 2020 · 30 comments
Closed

linker-plugin-lto stopped working in Rust 1.45.0 #74657

heftig opened this issue Jul 22, 2020 · 30 comments
Assignees
Labels
A-linkage Area: linking into static, shared libraries and binaries A-LLVM Area: Code generation parts specific to LLVM. Both correctness bugs and optimization-related issues. C-bug Category: This is a bug. E-needs-mcve Call for participation: This issue has a repro, but needs a Minimal Complete and Verifiable Example ICEBreaker-Cleanup-Crew Helping to "clean up" bugs with minimal examples and bisections P-high High priority regression-from-stable-to-stable Performance or correctness regression from one stable version to another. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.

Comments

@heftig
Copy link

heftig commented Jul 22, 2020

After upgrading from Rust 1.44.1 to Rust 1.45.0, Firefox's LTO build failed to link a crate build script with undefined reference to '__rust_probestack'.

The system is Arch Linux, which has binutils 2.34, GCC 10.1.0, LLVM 10.0.0, Clang 10.0.0.

Originally posted at https://bugzilla.mozilla.org/show_bug.cgi?id=1640982#c30:

I can replicate the error with rustup and the rusqlite crate (https://github.com/rusqlite/rusqlite) like this:

rusqlite> CARGO_PROFILE_RELEASE_LTO=true RUSTFLAGS="-Clinker-plugin-lto=LLVMgold.so" cargo +stable build --release                
    Updating crates.io index
   Compiling pkg-config v0.3.18
   Compiling libc v0.2.73
   Compiling bitflags v1.2.1
   Compiling memchr v2.3.3
   Compiling linked-hash-map v0.5.3
   Compiling fallible-streaming-iterator v0.1.9
   Compiling smallvec v1.4.1
   Compiling fallible-iterator v0.2.0
   Compiling lru-cache v0.1.2
   Compiling libsqlite3-sys v0.19.0 (/home/jan/vc/rusqlite/libsqlite3-sys)
   Compiling time v0.1.43
error: linking with `cc` failed: exit code: 1
  |
  = note: "cc" "-Wl,--as-needed" "-Wl,-z,noexecstack" "-m64" "-Wl,-plugin=LLVMgold.so" "-Wl,-plugin-opt=O3" "-Wl,-plugin-opt=mcpu=x86-64" "-L" "/home/jan/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib" "/home/jan/vc/rusqlite/target/release/build/libsqlite3-sys-f447ce3cb2731b7a/build_script_build-f447ce3cb2731b7a.build_script_build.7mwl8gcz-cgu.0.rcgu.o" "/home/jan/vc/rusqlite/target/release/build/libsqlite3-sys-f447ce3cb2731b7a/build_script_build-f447ce3cb2731b7a.build_script_build.7mwl8gcz-cgu.1.rcgu.o" "/home/jan/vc/rusqlite/target/release/build/libsqlite3-sys-f447ce3cb2731b7a/build_script_build-f447ce3cb2731b7a.build_script_build.7mwl8gcz-cgu.10.rcgu.o" "/home/jan/vc/rusqlite/target/release/build/libsqlite3-sys-f447ce3cb2731b7a/build_script_build-f447ce3cb2731b7a.build_script_build.7mwl8gcz-cgu.11.rcgu.o" "/home/jan/vc/rusqlite/target/release/build/libsqlite3-sys-f447ce3cb2731b7a/build_script_build-f447ce3cb2731b7a.build_script_build.7mwl8gcz-cgu.12.rcgu.o" "/home/jan/vc/rusqlite/target/release/build/libsqlite3-sys-f447ce3cb2731b7a/build_script_build-f447ce3cb2731b7a.build_script_build.7mwl8gcz-cgu.13.rcgu.o" "/home/jan/vc/rusqlite/target/release/build/libsqlite3-sys-f447ce3cb2731b7a/build_script_build-f447ce3cb2731b7a.build_script_build.7mwl8gcz-cgu.14.rcgu.o" "/home/jan/vc/rusqlite/target/release/build/libsqlite3-sys-f447ce3cb2731b7a/build_script_build-f447ce3cb2731b7a.build_script_build.7mwl8gcz-cgu.15.rcgu.o" "/home/jan/vc/rusqlite/target/release/build/libsqlite3-sys-f447ce3cb2731b7a/build_script_build-f447ce3cb2731b7a.build_script_build.7mwl8gcz-cgu.2.rcgu.o" "/home/jan/vc/rusqlite/target/release/build/libsqlite3-sys-f447ce3cb2731b7a/build_script_build-f447ce3cb2731b7a.build_script_build.7mwl8gcz-cgu.3.rcgu.o" "/home/jan/vc/rusqlite/target/release/build/libsqlite3-sys-f447ce3cb2731b7a/build_script_build-f447ce3cb2731b7a.build_script_build.7mwl8gcz-cgu.4.rcgu.o" "/home/jan/vc/rusqlite/target/release/build/libsqlite3-sys-f447ce3cb2731b7a/build_script_build-f447ce3cb2731b7a.build_script_build.7mwl8gcz-cgu.5.rcgu.o" "/home/jan/vc/rusqlite/target/release/build/libsqlite3-sys-f447ce3cb2731b7a/build_script_build-f447ce3cb2731b7a.build_script_build.7mwl8gcz-cgu.6.rcgu.o" "/home/jan/vc/rusqlite/target/release/build/libsqlite3-sys-f447ce3cb2731b7a/build_script_build-f447ce3cb2731b7a.build_script_build.7mwl8gcz-cgu.7.rcgu.o" "/home/jan/vc/rusqlite/target/release/build/libsqlite3-sys-f447ce3cb2731b7a/build_script_build-f447ce3cb2731b7a.build_script_build.7mwl8gcz-cgu.8.rcgu.o" "/home/jan/vc/rusqlite/target/release/build/libsqlite3-sys-f447ce3cb2731b7a/build_script_build-f447ce3cb2731b7a.build_script_build.7mwl8gcz-cgu.9.rcgu.o" "-o" "/home/jan/vc/rusqlite/target/release/build/libsqlite3-sys-f447ce3cb2731b7a/build_script_build-f447ce3cb2731b7a" "/home/jan/vc/rusqlite/target/release/build/libsqlite3-sys-f447ce3cb2731b7a/build_script_build-f447ce3cb2731b7a.497gn0w79xbcp3uz.rcgu.o" "-Wl,--gc-sections" "-pie" "-Wl,-zrelro" "-Wl,-znow" "-Wl,-O1" "-nodefaultlibs" "-L" "/home/jan/vc/rusqlite/target/release/deps" "-L" "/home/jan/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib" "-Wl,-Bstatic" "/home/jan/vc/rusqlite/target/release/deps/libpkg_config-800dea52ae78bc9e.rlib" "-Wl,--start-group" "/home/jan/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libstd-c147cd9c030850ef.rlib" "/home/jan/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libpanic_unwind-7e62a3a07bb85bc1.rlib" "/home/jan/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libhashbrown-000f77165d4d2d36.rlib" "/home/jan/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/librustc_std_workspace_alloc-7dc0cb59ed386ac6.rlib" "/home/jan/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libbacktrace-9248bfbd7273ac3d.rlib" "/home/jan/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libbacktrace_sys-b75363fb938de39d.rlib" "/home/jan/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/librustc_demangle-7bbe96f555da4ad6.rlib" "/home/jan/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libunwind-a145493c64eeb044.rlib" "/home/jan/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libcfg_if-9577436fc6fce6bc.rlib" "/home/jan/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/liblibc-b3376c0a2b35415c.rlib" "/home/jan/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/liballoc-5708f6b2b59b6e0f.rlib" "/home/jan/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/librustc_std_workspace_core-e9fd09201d99d6f4.rlib" "/home/jan/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libcore-914c6ef6f5cf354a.rlib" "-Wl,--end-group" "/home/jan/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libcompiler_builtins-1445b6c7903692a2.rlib" "-Wl,-Bdynamic" "-ldl" "-lrt" "-lpthread" "-lgcc_s" "-lc" "-lm" "-lrt" "-lpthread" "-lutil" "-ldl" "-lutil"
  = note: /usr/bin/ld: /tmp/lto-llvm-7519f5.o: in function `std::sys::unix::fs::copy':
          /rustc/5c1f21c3b82297671ad3ae1e8c942d2ca92e84f2//src/libstd/sys/unix/fs.rs:1172: undefined reference to `__rust_probestack'
          collect2: error: ld returned 1 exit status
          

error: aborting due to previous error

error: could not compile `libsqlite3-sys`.

To learn more, run the command again with --verbose.
warning: build failed, waiting for other jobs to finish...
error: build failed

This works with 1.44.1:

rusqlite> CARGO_PROFILE_RELEASE_LTO=true RUSTFLAGS="-Clinker-plugin-lto=LLVMgold.so" cargo +1.44.1 build --release
   Compiling libc v0.2.73
   Compiling pkg-config v0.3.18
   Compiling memchr v2.3.3
   Compiling bitflags v1.2.1
   Compiling linked-hash-map v0.5.3
   Compiling smallvec v1.4.1
   Compiling fallible-streaming-iterator v0.1.9
   Compiling fallible-iterator v0.2.0
   Compiling lru-cache v0.1.2
   Compiling libsqlite3-sys v0.19.0 (/home/jan/vc/rusqlite/libsqlite3-sys)
   Compiling time v0.1.43
   Compiling rusqlite v0.23.1 (/home/jan/vc/rusqlite)
    Finished release [optimized] target(s) in 3.56s

Using clang -flto as the linker instead of GCC with explicit LLVMgold.so behaves analogously:

fails:    CARGO_PROFILE_RELEASE_LTO=true CARGO_TARGET_X86_64_UNKNOWN_LINUX_GNU_LINKER=clang RUSTFLAGS="-Clinker-plugin-lto -Clink-arg=-flto" cargo +stable build --release
succeeds: CARGO_PROFILE_RELEASE_LTO=true CARGO_TARGET_X86_64_UNKNOWN_LINUX_GNU_LINKER=clang RUSTFLAGS="-Clinker-plugin-lto -Clink-arg=-flto" cargo +1.44.1 build --release

Using LLD or gold instead of the BFD linker also makes it work:

CARGO_PROFILE_RELEASE_LTO=true RUSTFLAGS="-Clinker-plugin-lto=LLVMgold.so -Clink-arg=-fuse-ld=gold" cargo +stable build --release
CARGO_PROFILE_RELEASE_LTO=true RUSTFLAGS="-Clinker-plugin-lto=LLVMgold.so -Clink-arg=-fuse-ld=lld" cargo +stable build --release
CARGO_PROFILE_RELEASE_LTO=true CARGO_TARGET_X86_64_UNKNOWN_LINUX_GNU_LINKER=clang RUSTFLAGS="-Clinker-plugin-lto -Clink-arg=-flto -Clink-arg=-fuse-ld=gold" cargo +stable build --release
CARGO_PROFILE_RELEASE_LTO=true CARGO_TARGET_X86_64_UNKNOWN_LINUX_GNU_LINKER=clang RUSTFLAGS="-Clinker-plugin-lto -Clink-arg=-flto -Clink-arg=-fuse-ld=lld" cargo +stable build --release
@heftig heftig added the C-bug Category: This is a bug. label Jul 22, 2020
@jonas-schievink jonas-schievink added A-linkage Area: linking into static, shared libraries and binaries regression-from-stable-to-stable Performance or correctness regression from one stable version to another. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. labels Jul 22, 2020
@rustbot rustbot added the I-prioritize Issue: Indicates that prioritization has been requested for this issue. label Jul 22, 2020
@heftig
Copy link
Author

heftig commented Jul 27, 2020

In https://bugzilla.mozilla.org/show_bug.cgi?id=1654465, Mozilla is switching from setting CARGO_PROFILE_RELEASE_LTO=true to -Cembed-bitcode=yes (for Rust 1.45+ only), but this does not seem to affect this issue.

fails   : RUSTFLAGS="-Clinker-plugin-lto=LLVMgold.so" cargo +stable build --release
succeeds: RUSTFLAGS="-Clinker-plugin-lto=LLVMgold.so" cargo +1.44.1 build --release
fails   : RUSTFLAGS="-Clinker-plugin-lto=LLVMgold.so -Cembed-bitcode=yes" cargo +stable build --release

fails   : CARGO_TARGET_X86_64_UNKNOWN_LINUX_GNU_LINKER=clang RUSTFLAGS="-Clinker-plugin-lto -Clink-arg=-flto" cargo +stable build --release
succeeds: CARGO_TARGET_X86_64_UNKNOWN_LINUX_GNU_LINKER=clang RUSTFLAGS="-Clinker-plugin-lto -Clink-arg=-flto" cargo +1.44.1 build --release
fails   : CARGO_TARGET_X86_64_UNKNOWN_LINUX_GNU_LINKER=clang RUSTFLAGS="-Clinker-plugin-lto -Cembed-bitcode=yes -Clink-arg=-flto" cargo +stable build --release

succeeds: RUSTFLAGS="-Clinker-plugin-lto=LLVMgold.so -Clink-arg=-fuse-ld=gold" cargo +stable build --release
succeeds: RUSTFLAGS="-Clinker-plugin-lto=LLVMgold.so -Clink-arg=-fuse-ld=lld" cargo +stable build --release
succeeds: RUSTFLAGS="-Clinker-plugin-lto=LLVMgold.so -Cembed-bitcode=yes -Clink-arg=-fuse-ld=gold" cargo +stable build --release
succeeds: RUSTFLAGS="-Clinker-plugin-lto=LLVMgold.so -Cembed-bitcode=yes -Clink-arg=-fuse-ld=lld" cargo +stable build --release

succeeds: CARGO_TARGET_X86_64_UNKNOWN_LINUX_GNU_LINKER=clang RUSTFLAGS="-Clinker-plugin-lto -Clink-arg=-flto -Clink-arg=-fuse-ld=gold" cargo +stable build --release
succeeds: CARGO_TARGET_X86_64_UNKNOWN_LINUX_GNU_LINKER=clang RUSTFLAGS="-Clinker-plugin-lto -Clink-arg=-flto -Clink-arg=-fuse-ld=lld" cargo +stable build --release
succeeds: CARGO_TARGET_X86_64_UNKNOWN_LINUX_GNU_LINKER=clang RUSTFLAGS="-Clinker-plugin-lto -Cembed-bitcode=yes -Clink-arg=-flto -Clink-arg=-fuse-ld=gold" cargo +stable build --release
succeeds: CARGO_TARGET_X86_64_UNKNOWN_LINUX_GNU_LINKER=clang RUSTFLAGS="-Clinker-plugin-lto -Cembed-bitcode=yes -Clink-arg=-flto -Clink-arg=-fuse-ld=lld" cargo +stable build --release

archlinux-github pushed a commit to archlinux/svntogit-packages that referenced this issue Jul 27, 2020
Add a patch for https://bugzilla.mozilla.org/show_bug.cgi?id=1654465

Switch from ld.bfd to ld.lld to work around rust-lang/rust#74657

git-svn-id: file:///srv/repos/svn-packages/svn@392595 eb2447ed-0c53-47e4-bac8-5bc4a241df78
archlinux-github pushed a commit to archlinux/svntogit-packages that referenced this issue Jul 27, 2020
Add a patch for https://bugzilla.mozilla.org/show_bug.cgi?id=1654465

Switch from ld.bfd to ld.lld to work around rust-lang/rust#74657

git-svn-id: file:///srv/repos/svn-packages/svn@392595 eb2447ed-0c53-47e4-bac8-5bc4a241df78
@foutrelis
Copy link

The issue is also reproducible on Ubuntu 20.04 with rust 1.45.0 installed using rustup.rs. Bisecting points to 1357af3 which sounds relevant.

For the bisect, I used cargo-bisect-rustc to test if rusqlite builds with RUSTFLAGS="-Clinker-plugin-lto=LLVMgold.so" cargo build --release.

@spastorino
Copy link
Member

@rustbot ping cleanup

To see if we can minimize this issue.

@rustbot rustbot added the ICEBreaker-Cleanup-Crew Helping to "clean up" bugs with minimal examples and bisections label Jul 29, 2020
@rustbot
Copy link
Collaborator

rustbot commented Jul 29, 2020

Hey Cleanup Crew ICE-breakers! This bug has been identified as a good
"Cleanup ICE-breaking candidate". In case it's useful, here are some
instructions for tackling these sorts of bugs. Maybe take a look?
Thanks! <3

cc @AminArria @camelid @chrissimpkins @contrun @DutchGhost @elshize @ethanboxx @h-michael @HallerPatrick @hdhoang @hellow554 @imtsuki @kanru @KarlK90 @LeSeulArtichaut @MAdrianMattocks @matheus-consoli @mental32 @nmccarty @Noah-Kennedy @pard68 @PeytonT @pierreN @Redblueflame @RobbieClarken @RobertoSnap @robjtede @SarthakSingh31 @senden9 @shekohex @sinato @spastorino @turboladen @woshilapin @yerke

@spastorino
Copy link
Member

spastorino commented Jul 29, 2020

Assigning P-highmeanwhile we figure out more information about this issue, as discussed as part of the Prioritization Working Group procedure and removing I-prioritize.

@spastorino spastorino added P-high High priority and removed I-prioritize Issue: Indicates that prioritization has been requested for this issue. labels Jul 29, 2020
@LeSeulArtichaut LeSeulArtichaut added the E-needs-mcve Call for participation: This issue has a repro, but needs a Minimal Complete and Verifiable Example label Jul 29, 2020
@LeSeulArtichaut
Copy link
Contributor

Bisecting points to 1357af3 which sounds relevant.

cc @alexcrichton

@heftig
Copy link
Author

heftig commented Jul 29, 2020

From Zulip:

so most firefox targets still work here

To clarify, the reason I believe this isn't hitting anyone else but Arch Linux yet is that we're the only ones building Firefox with cross-language LTO and Rust 1.45.

Mozilla's official builds use an older Rust version, which isn't affected. Developer builds don't do LTO or use LLD if it's available, which isn't affected.

I guess this was fixed on Firefox’s side, see the linkrf bugzilla issue

Not this undefined reference issue.

Arch Linux applies two fixes to its Firefox build:

archlinux-github pushed a commit to archlinux/svntogit-community that referenced this issue Jul 29, 2020
Add a patch for https://bugzilla.mozilla.org/show_bug.cgi?id=1654465

Switch from ld.bfd to ld.lld to work around rust-lang/rust#74657

git-svn-id: file:///srv/repos/svn-community/svn@665789 9fca08f4-af9d-4005-b8df-a31f2cc04f65
archlinux-github pushed a commit to archlinux/svntogit-community that referenced this issue Jul 29, 2020
Add a patch for https://bugzilla.mozilla.org/show_bug.cgi?id=1654465

Switch from ld.bfd to ld.lld to work around rust-lang/rust#74657


git-svn-id: file:///srv/repos/svn-community/svn@665789 9fca08f4-af9d-4005-b8df-a31f2cc04f65
@glandium
Copy link
Contributor

Actually, older versions of rust are affected if you switch -Clto for -Clto=thin, but not on all platforms.

@alexcrichton
Copy link
Member

Is there perhaps a small/simple docker container to reproduce this? I unfortunately can't reproduce this locally at this time.

@foutrelis
Copy link

foutrelis commented Jul 31, 2020

This Dockerfile reproduces the issue with docker build -t rust-issue-74657 .; docker run -it --rm rust-issue-74657

FROM ubuntu:20.04
WORKDIR /root
RUN apt-get update && apt-get install -y curl git llvm-dev build-essential \
    && curl https://sh.rustup.rs | sh -s -- -y --default-toolchain 1.45.0 \
    && git clone --depth=1 https://github.com/rusqlite/rusqlite
WORKDIR rusqlite
RUN ../.cargo/bin/cargo fetch
CMD . /root/.cargo/env; RUSTFLAGS="-Clinker-plugin-lto=LLVMgold.so" cargo build --release

@alexcrichton
Copy link
Member

It looks like I've configured my system for ld to be ld.gold, which is why I was unable to reproduce. I'm able to reproduce this on Ubuntu 20.04 with your above Dockerfile, but it can also be minimized to:

$ echo 'fn main() { let a = [0u64; 1024]; println!("{:?}", &a[..]); }' > foo.rs
$ rustc foo.rs -Clinker-plugin-lto=LLVMgold.so -C link-arg=-fuse-ld=bfd

Is this an issue with LLVMgold.so not being compatible with ld.bfd? Given that this is so specific to the linker and the reduction is so small, this seems like a linker bug. In the failing cases compiler-builtins is linked last and defined __rust_probestack. It seems like, if anything, ld.bfd is deciding to not look at libraries until after they're codegen'd, since the reference to __rust_probestack doesn't happen until after codegen happens.

@glandium
Copy link
Contributor

glandium commented Oct 9, 2020

In the Firefox case, rustc is not invoking ld: it generates a staticlib that then is linked into libxul.

@glandium
Copy link
Contributor

At this point of my investigation, I'm not sure if it's a BFD ld bug or a LLVM gold plugin bug yet, but I have a smaller reproducer that is independent of rust (but emulates the problem): https://gist.github.com/glandium/98f8d5dd2e075860a731ed374dd284a1

Both make main and make main2 fail. The reason why it fails is that in the first case, the bitcode for probestack is built too late and in the latter it's not built at all.

The reason why it doesn't fail with gold or lld is that they don't even try to use the bitcode, they just use the code in .text.

The same failure happens on x86 for things like __muloti4, for similar-ish reasons, which is related to how the symbols are defined in the bitcode. For instance, adding a probestack() call in main() makes the testcase pass for for both main and main2.

One way this could be worked around in rust (because even if the bug, wherever it is, is fixed, it will take a while for the fix to make its way everywhere) would be to avoid embedding bitcode for the object files containing these special symbols. Essentially, all of libcompiler_builtins... And considering only BFD ld uses the bitcode anyways...

@glandium
Copy link
Contributor

Unfortunately, there's no way that I can see to opt-out of

cargo.rustflag("-Cembed-bitcode=yes");
for compiler_builtins only.

@glandium
Copy link
Contributor

I'm leaning towards a problem on LLVM's end, so I filed https://bugs.llvm.org/show_bug.cgi?id=47872

@jyn514 jyn514 added the A-LLVM Area: Code generation parts specific to LLVM. Both correctness bugs and optimization-related issues. label Feb 11, 2021
thotypous added a commit to chaotic-aur/pkgbuild-firefox-wayland-hg that referenced this issue Nov 8, 2021
@tstellar
Copy link

tstellar commented Dec 8, 2021

At this point of my investigation, I'm not sure if it's a BFD ld bug or a LLVM gold plugin bug yet, but I have a smaller reproducer that is independent of rust (but emulates the problem): https://gist.github.com/glandium/98f8d5dd2e075860a731ed374dd284a1

Both make main and make main2 fail. The reason why it fails is that in the first case, the bitcode for probestack is built too late and in the latter it's not built at all.

The reason why it doesn't fail with gold or lld is that they don't even try to use the bitcode, they just use the code in .text.

The same failure happens on x86 for things like __muloti4, for similar-ish reasons, which is related to how the symbols are defined in the bitcode. For instance, adding a probestack() call in main() makes the testcase pass for for both main and main2.

One way this could be worked around in rust (because even if the bug, wherever it is, is fixed, it will take a while for the fix to make its way everywhere) would be to avoid embedding bitcode for the object files containing these special symbols. Essentially, all of libcompiler_builtins... And considering only BFD ld uses the bitcode anyways...

Are you sure that BFD ld is using the bitcode? How does it know that there is bitcode embeded in probestack.o?

@tstellar
Copy link

tstellar commented Dec 8, 2021

Are you sure that BFD ld is using the bitcode? How does it know that there is bitcode embeded in probestack.o?

Answering my own question, I can get it to work if I strip out the the .llvmbc section:

make
strip -K probestack -R .llvmbc probestack.o
make

The other question I have is if gold and lld ignore the embedded bitcode, then does that mean they aren't actually doing LTO?

@tstellar
Copy link

I spent some time debugging this and what I found is that bfd passes libprobestack.a to the LLVMgold plugin, but the plugin refuses to claim it, because it does not support reading archives. Therefore, the bitcode from libprobestack.o is never considered during LTO.

Then after LTO is done, bfd passes the libprobestack.o member of libprobestack.a to the plugin. The pugin sees the embedded bitcode in libprobestack.o and claims this file. However, at this point it is too late for bfd to add new IR symbols to the link, so the file gets dropped. My guess is that also because the plugin claimed the file, then bfd does not include any of the ELF symbols from the file in the link. I confirmed this by telling the plugin not to claim the libprobestack.o member and this makes the example link.

The reason adding probestack() to main.c works, is because when you do this, bfd passes the libprobestack.o member of lbprobestack.a to the plugin before LTO is run, so the bitcode and symbols from libprobestack.o participate in LTO.

gold on the other hand does not even attempt to pass the libprobestack.a archive or its probestack.o member to the plugin, and I think it ends up getting the ELF symbols from those files.

It's possible there is a bug in bfd here, I'm not sure, but it looks like we could fix the LLVMgold plugin in two different ways:

  1. Add support for reading archive files.
  2. Don't claim mixed binaries with both bitcode and ELF symbols after running LTO.

@nickclifton
Copy link

It's possible there is a bug in bfd here,

Personally I would say that this is an LLVMgold plugin bug, since it is that plugin's responsibility to handle LLVM bitcode files. But I could be persuaded otherwise. If you do think that the BFD library should be doing something differently, please could you file a bug report here:
https://sourceware.org/bugzilla/enter_bug.cgi?product=binutils

I'm not sure, but it looks like we could fix the LLVMgold plugin in two different ways:
1. Add support for reading archive files.

I think that this would be bad, because the plugin will not know which members of the archive are going to be needed to complete the link. Unless it is possible to compile each of the members in isolation and then build a new archive containing these processed object files and return that to the linker.

2. Don't claim mixed binaries with both bitcode and ELF symbols after running LTO.  

This sounds like a good idea. Even if the bug really is with the BFD library, I think that the LLVM plugin would benefit from this check.

@glandium
Copy link
Contributor

I'm leaning towards a problem on LLVM's end, so I filed https://bugs.llvm.org/show_bug.cgi?id=47872

For the record, that bug is now llvm/llvm-project#47216

@tstellar
Copy link

tstellar commented Jan 4, 2022

@alexcrichton Is the intention with 1357af3 that linkers will always ignore the .llvmbc section? If so, then whatever mechanism was added to cause linkers to ignore the section is not working with bfd and the gold plugin.

I also wonder if this is fixed by #90326.

@alexcrichton
Copy link
Member

Yes that was the original intention. We could probably rename the section to something like .rustc_llvmbc if LLVM linker plugins are picking up .llvmbc and doing things with it. (I'm not following this issue though so there may also be something we can do such that LLVM-linker-plugin-using-things can sitll work, not sure)

@tstellar
Copy link

tstellar commented Jan 4, 2022

@alexcrichton I think renaming the section to .rustc_llvmbc is going to be the safest solution for rust if you want to guarantee that the section gets ignored. The .llvmbc has special meaning in LLVM, so even if we were to update the gold plugin to ignore it (which may be possible), there could be other problems that pop up in the future as new features are added to LLVM.

Renaming the section is also going to be the only way to ensure this bug is fixed for LLVM <=13, since those versions are no longer getting fixes upstream.

@alexcrichton
Copy link
Member

IIRC we also rely on LLVM-internal functions to find the bytecode within an object, and I think those functions require the section to be named .llvmbc or similar. If we were to rename the section we would also need to reimplement those functions in Rust. I don't think that would be hard, but it's something to do. (I won't personally have time to do this).

@pnkfelix
Copy link
Member

pnkfelix commented Dec 9, 2022

Visiting for P-high review

From what @alexcrichton has written above, it sound like there are clear ideas for a straight-forward fix here; and the issue is just figuring out the all the internal plumbing for making this change.

I'm going to self-assign with the hopes of using it as the basis for some instructional videos on how to hack on rustc.

@rustbot claim

@pnkfelix
Copy link
Member

pnkfelix commented Dec 13, 2022

Actually this might now be fixed upstream in LLVM, based on https://reviews.llvm.org/rG4b1e3d19370694dd2b2c04a5945f3f9e43917456 (committed back on 2022-07-14, which is in LLVM 15, which we started using in x86 CI dist builds back in #101527)

So maybe this is fixed now? Seems worth checking.

(But even if it is fixed, the earlier comment implies that there might still be value in renaming the relevant section here to .rustc_llvmbc, for the sake of future-proofing against similar problems in the future.)

@pnkfelix
Copy link
Member

@heftig can you confirm whether or not this has been resolved for you by a more recent Rust release that is using LLVM 15 (and thus has the fix here)?

(I spent a little while trying do such confirmation on my own, but I'm not well versed in how to adjust Rust's LLVM build settings to get access to the LLVMgold.so plugin.)

@heftig
Copy link
Author

heftig commented Dec 13, 2022

I currently get another error trying to reproduce this:

error: linking with `cc` failed: exit status: 1
  |
  = note: "cc" "-m64" "/tmp/rustcQXcC2a/symbols.o" "/home/jan/vc/rusqlite/target/release/build/libc-ab845801ca034d0f/build_script_build-ab845801ca034d0f.build_script_build.45a96ece-cgu.0.rcgu.o" "/home/jan/vc/rusqlite/target/release/build/libc-ab845801ca034d0f/build_script_build-ab845801ca034d0f.build_script_build.45a96ece-cgu.1.rcgu.o" "/home/jan/vc/rusqlite/target/release/build/libc-ab845801ca034d0f/build_script_build-ab845801ca034d0f.build_script_build.45a96ece-cgu.10.rcgu.o" "/home/jan/vc/rusqlite/target/release/build/libc-ab845801ca034d0f/build_script_build-ab845801ca034d0f.build_script_build.45a96ece-cgu.11.rcgu.o" "/home/jan/vc/rusqlite/target/release/build/libc-ab845801ca034d0f/build_script_build-ab845801ca034d0f.build_script_build.45a96ece-cgu.12.rcgu.o" "/home/jan/vc/rusqlite/target/release/build/libc-ab845801ca034d0f/build_script_build-ab845801ca034d0f.build_script_build.45a96ece-cgu.13.rcgu.o" "/home/jan/vc/rusqlite/target/release/build/libc-ab845801ca034d0f/build_script_build-ab845801ca034d0f.build_script_build.45a96ece-cgu.14.rcgu.o" "/home/jan/vc/rusqlite/target/release/build/libc-ab845801ca034d0f/build_script_build-ab845801ca034d0f.build_script_build.45a96ece-cgu.15.rcgu.o" "/home/jan/vc/rusqlite/target/release/build/libc-ab845801ca034d0f/build_script_build-ab845801ca034d0f.build_script_build.45a96ece-cgu.2.rcgu.o" "/home/jan/vc/rusqlite/target/release/build/libc-ab845801ca034d0f/build_script_build-ab845801ca034d0f.build_script_build.45a96ece-cgu.3.rcgu.o" "/home/jan/vc/rusqlite/target/release/build/libc-ab845801ca034d0f/build_script_build-ab845801ca034d0f.build_script_build.45a96ece-cgu.4.rcgu.o" "/home/jan/vc/rusqlite/target/release/build/libc-ab845801ca034d0f/build_script_build-ab845801ca034d0f.build_script_build.45a96ece-cgu.5.rcgu.o" "/home/jan/vc/rusqlite/target/release/build/libc-ab845801ca034d0f/build_script_build-ab845801ca034d0f.build_script_build.45a96ece-cgu.6.rcgu.o" "/home/jan/vc/rusqlite/target/release/build/libc-ab845801ca034d0f/build_script_build-ab845801ca034d0f.build_script_build.45a96ece-cgu.7.rcgu.o" "/home/jan/vc/rusqlite/target/release/build/libc-ab845801ca034d0f/build_script_build-ab845801ca034d0f.build_script_build.45a96ece-cgu.8.rcgu.o" "/home/jan/vc/rusqlite/target/release/build/libc-ab845801ca034d0f/build_script_build-ab845801ca034d0f.build_script_build.45a96ece-cgu.9.rcgu.o" "/home/jan/vc/rusqlite/target/release/build/libc-ab845801ca034d0f/build_script_build-ab845801ca034d0f.56jexca5gqa9z4t5.rcgu.o" "-Wl,--as-needed" "-L" "/home/jan/vc/rusqlite/target/release/deps" "-L" "/home/jan/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib" "-Wl,-Bstatic" "/home/jan/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libstd-05737cf45bd30456.rlib" "/home/jan/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libpanic_unwind-9f873b61fdec9b03.rlib" "/home/jan/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libobject-7f13930fcac1846f.rlib" "/home/jan/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libmemchr-098633b847612f3b.rlib" "/home/jan/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libaddr2line-f14b73d282b0245e.rlib" "/home/jan/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libgimli-2c5b4433ebc1d822.rlib" "/home/jan/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/librustc_demangle-59591a7b405fe395.rlib" "/home/jan/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libstd_detect-384947c6d5f697ff.rlib" "/home/jan/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libhashbrown-b08a86c6880b47a8.rlib" "/home/jan/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libminiz_oxide-58adeee671f9ba8e.rlib" "/home/jan/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libadler-f156b880fc73e7f0.rlib" "/home/jan/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/librustc_std_workspace_alloc-4458c5022988e1ab.rlib" "/home/jan/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libunwind-02e61e5ec4aa9e8b.rlib" "/home/jan/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libcfg_if-a0d9b33b5161957b.rlib" "/home/jan/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/liblibc-04cec55a79224c36.rlib" "/home/jan/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/liballoc-3fb6d8496dc7d6a6.rlib" "/home/jan/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/librustc_std_workspace_core-7d46c016841a97d4.rlib" "/home/jan/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libcore-a1f7b8b60464cc57.rlib" "/home/jan/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libcompiler_builtins-272ca28f0b8538d5.rlib" "-Wl,-Bdynamic" "-lgcc_s" "-lutil" "-lrt" "-lpthread" "-lm" "-ldl" "-lc" "-Wl,--eh-frame-hdr" "-Wl,-znoexecstack" "-Wl,-plugin=LLVMgold.so" "-Wl,-plugin-opt=O0,-plugin-opt=mcpu=x86-64" "-L" "/home/jan/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib" "-o" "/home/jan/vc/rusqlite/target/release/build/libc-ab845801ca034d0f/build_script_build-ab845801ca034d0f" "-Wl,--gc-sections" "-pie" "-Wl,-zrelro,-znow" "-nodefaultlibs"
  = note: /usr/bin/ld: error: LLVM gold plugin has failed to create LTO module: Opaque pointers are only supported in -opaque-pointers mode (Producer: 'LLVM15.0.0-rust-1.65.0-stable' Reader: 'LLVM 14.0.6')
          collect2: error: ld returned 1 exit status

@nikic
Copy link
Contributor

nikic commented Dec 13, 2022

You are using a gold plugin from LLVM 14 to read bitcode produced by LLVM 15, which is not possible.

@heftig
Copy link
Author

heftig commented Nov 15, 2023

This has been resolved.

@heftig heftig closed this as completed Nov 15, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-linkage Area: linking into static, shared libraries and binaries A-LLVM Area: Code generation parts specific to LLVM. Both correctness bugs and optimization-related issues. C-bug Category: This is a bug. E-needs-mcve Call for participation: This issue has a repro, but needs a Minimal Complete and Verifiable Example ICEBreaker-Cleanup-Crew Helping to "clean up" bugs with minimal examples and bisections P-high High priority regression-from-stable-to-stable Performance or correctness regression from one stable version to another. 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