Repository navigation
It's impossible to write a panic crate for no_std #48661
Description
(Originally filed as rust-lang/cargo#5106, but I think it's actually a rustc issue)
I've created a workspace and have multiple crates, all of which are no_std and need a panic_fmt implementation, so I created a separate crate that can be shared for that. Then I built a cdylib which built and linked fine, but failed at runtime with "undefined symbol: rust_begin_unwind".
Here's how to reproduce (on Linux, but I expect this should fail the same on all platforms):
$ cargo new --lib bar
$ cd bar
$ cargo new --lib panic
$ cat > panic/src/lib.rs <<EOF
#![no_std]
#![feature(lang_items)]
#[cfg(not(test))]
#[lang = "panic_fmt"]
#[no_mangle]
pub extern "C" fn panic_fmt(_: core::fmt::Arguments, _: &'static str, _: u32, _: u32) -> ! {
loop {}
}
EOF
$ cat >> Cargo.toml <<EOF
panic = { path = "panic" }
[profile.dev]
panic = "abort"
[profile.release]
panic = "abort"
[lib]
crate-type = ["cdylib"]
EOF
$ cat > src/lib.rs <<EOF
#![no_std]
extern crate panic;
#[no_mangle]
pub fn foo() -> ! {
panic!("");
}
EOF
$ cargo +nightly build --release
Compiling bar v0.1.0 (file:///tmp/bar)
Finished release [optimized] target(s) in 0.11 secs
Note how this all compiled and linked fine. But:
$ objdump -T target/release/libbar.so
target/release/libbar.so: file format elf64-x86-64
DYNAMIC SYMBOL TABLE:
0000000000000000 w D *UND* 0000000000000000 __cxa_finalize
0000000000000000 w D *UND* 0000000000000000 _ITM_registerTMCloneTable
0000000000000000 D *UND* 0000000000000000 rust_begin_unwind
0000000000000000 w D *UND* 0000000000000000 _ITM_deregisterTMCloneTable
0000000000000000 w D *UND* 0000000000000000 __gmon_start__
0000000000000550 g DF .text 000000000000000f foo
rust_begin_unwind is undefined.
The reason this is happening is because nothing is using the symbol in any library that appears before libpanic on the linker command line, and the only thing that does use the symbol is libcore, which comes after. So the linker happily removes it.
If I force libpanic to be added last on the linker command line, it works:
$ RUSTFLAGS="-C link-arg=target/release/deps/libpanic-3af7779d45985ae9.rlib" cargo +nightly build --release
Compiling bar v0.1.0 (file:///tmp/bar)
Finished release [optimized] target(s) in 0.11 secs
$ objdump -T target/release/libbar.so
target/release/libbar.so: file format elf64-x86-64
DYNAMIC SYMBOL TABLE:
0000000000000000 w D *UND* 0000000000000000 __cxa_finalize
0000000000000000 w D *UND* 0000000000000000 _ITM_registerTMCloneTable
0000000000000000 w D *UND* 0000000000000000 _ITM_deregisterTMCloneTable
0000000000000000 w D *UND* 0000000000000000 __gmon_start__
0000000000000620 g DF .text 0000000000000002 rust_begin_unwind
0000000000000550 g DF .text 000000000000000f foo
Relatedly, this makes me think cargo should probably add -Wl,-z,defs:
$ RUSTFLAGS="-C link-arg=-Wl,-z,defs" cargo +nightly build --release
Compiling bar v0.1.0 (file:///tmp/bar)
error: linking with `cc` failed: exit code: 1
|
= note: "cc" "-Wl,--as-needed" "-Wl,-z,noexecstack" "-m64" "-L" "/home/glandium/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib" "/tmp/bar/target/release/deps/bar.bar0-b17b6035155785f4e639ba83018b4206.rs.rcgu.o" "-o" "/tmp/bar/target/release/deps/libbar.so" "-Wl,--version-script=/tmp/rustc.vWTWjhp8JGrI/list" "-Wl,--gc-sections" "-Wl,-z,relro,-z,now" "-Wl,-O1" "-nodefaultlibs" "-L" "/tmp/bar/target/release/deps" "-L" "/home/glandium/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib" "-Wl,-Bstatic" "/tmp/bar/target/release/deps/libpanic-3af7779d45985ae9.rlib" "/home/glandium/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libcore-80b45058e2fc80f9.rlib" "-shared" "-Wl,-z,defs" "-Wl,-Bdynamic"
= note: /home/glandium/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libcore-80b45058e2fc80f9.rlib(core-80b45058e2fc80f9.core0.rcgu.o): In function `core::panicking::panic_fmt':
/checkout/src/libcore/num/bignum.rs:263: undefined reference to `rust_begin_unwind'
collect2: error: ld returned 1 exit status
Activity
glandium commentedon Mar 2, 2018
FWIW, LTO works around the issue.
glandium commentedon Mar 2, 2018
Another work around: using the dylib crate-type instead of cdylib, because of:
rust/src/librustc_trans/back/link.rs
Lines 1393 to 1395 in 5db73fc
But this doesn't help for the bin crate-type, which actually fails to link because of the missing
rust_begin_unwindsymbol.All in all, I just wish there was a way for me to make that library appear after libcore on the linker command.
glandium commentedon Mar 2, 2018
Another workaround: building libpanic as both a rlib and a staticlib, and add:
in the same file that contains
extern crate panic, and add-L target/releaseto the linker flags, which I guess is only possible with a build script...glandium commentedon Mar 2, 2018
This
build.rsallows me to build as a workaround:The triple
parent()is kind of awful, I wish cargo exposed its base target directory instead.japaric commentedon Mar 15, 2018
I don't remember the differences between cdylbs and plain executables but this sounds like #47074 / #18807, which has a proposed rustc fix in #47074 (comment). @glandium could you try wrapping the linker arguments in --start-group / --end-group?
glandium commentedon Mar 15, 2018
It works, but only if libcore and libpanic are between the same --start-group/--end-group. That doesn't help with the second half of #44489 (comment) though.
japaric commentedon Mar 15, 2018
Yes, that's what #47074 (comment) proposes to do.
FWIW, you may be able to avoid the linking errors if you disable both incr comp and parallel codegen in your dev profile (IDK if you also get the error using the release profile). We have run into this problem in Cortex-M land because the cortex-m-rt provides a panic implementation (the panic_fmt lang item) and both disabling incr comp and parallel codegen fixes the linking issue in must, but not all, cases.
glandium commentedon Mar 31, 2018
@alexcrichton Sadly, #49316 didn't fix this :(
Fix another circulare deps link args issue
alexcrichton commentedon Apr 4, 2018
I believe this should be fixed by #49672
Auto merge of #49672 - alexcrichton:fix-another-std-core-cycle, r=mic…
glandium commentedon Apr 8, 2018
I can confirm this is fixed.