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