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

It's impossible to write a panic crate for no_std #5106

Closed
glandium opened this issue Mar 2, 2018 · 1 comment
Closed

It's impossible to write a panic crate for no_std #5106

glandium opened this issue Mar 2, 2018 · 1 comment

Comments

@glandium
Copy link
Contributor

glandium commented Mar 2, 2018

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
@glandium
Copy link
Contributor Author

glandium commented Mar 2, 2018

Refiled as rust-lang/rust#48661 because I think it's actually a rustc problem.

@glandium glandium closed this as completed Mar 2, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant