Rust: `rust_begin_unwind` required for panic=abort

Created on 10 Dec 2016  路  20Comments  路  Source: rust-lang/rust

Since a few nightlies, the compiler requires a rust_begin_unwind symbol again even though my no_std crate uses panic=abort:

In function `core::panicking::panic_fmt::hb1bd46c16a8d9cdb':
core.cgu-0.rs:(.text._ZN4core9panicking9panic_fmt17hb1bd46c16a8d9cdbE+0x38): undefined reference to `rust_begin_unwind'

The big problem is that defining a rust_begin_unwind function in Rust gives an error, too:

error: symbol `rust_begin_unwind` is already defined

I only works if I add a rust_begin_unwind function to a C file that is linked with the Rust crate.

A-linkage C-bug

Most helpful comment

Oh, that's because this already has some special handling in the compiler. As far as I can tell, no matter what actual name the function has, if it is marked with #[lang = "panic_fmt"] then it will be assigned "rust_begin_unwind" as symbol name. It's a bit strange.

All 20 comments

STR

$ cargo new --bin app && cd $_

$ edit Cargo.toml && tail -n2 $_
[profile.dev]
panic = "abort"

$ edit src/main.rs && cat $_
#![feature(lang_items)]
#![no_main]
#![no_std]

#[no_mangle]
pub fn _start() -> ! {
    panic!()
}

#[lang = "panic_fmt"]
extern "C" fn panic_fmt() -> ! {
    loop {}
}

$ cargo rustc -- -C link-arg=-nostartfiles
error: linking with `cc` failed: exit code: 1
  |
  = note: "cc" "-Wl,--as-needed" "-Wl,-z,noexecstack" "-m64" "-L" "/home/japaric/.multirust/toolchains/nightly-2016-12-06-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib" "/home/japaric/tmp/app/target/debug/deps/app-55df21ded2024f97.0.o" "-o" "/home/japaric/tmp/app/target/debug/deps/app-55df21ded2024f97" "-Wl,--gc-sections" "-pie" "-nodefaultlibs" "-L" "/home/japaric/tmp/app/target/debug/deps" "-L" "/home/japaric/.multirust/toolchains/nightly-2016-12-06-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib" "-Wl,-Bstatic" "-Wl,-Bdynamic" "/home/japaric/.multirust/toolchains/nightly-2016-12-06-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libcore-1357b93f.rlib" "-nostartfiles"
  = note: /home/japaric/.multirust/toolchains/nightly-2016-12-06-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libcore-1357b93f.rlib(core-1357b93f.0.o): In function `core::panicking::panic_fmt':
/buildslave/rust-buildbot/slave/nightly-dist-rustc-linux/build/obj/../src/libcore/num/bignum.rs:489: undefined reference to `rust_begin_unwind'
collect2: error: ld returned 1 exit status


error: aborting due to previous error

error: Could not compile `app`.

$ nm -C target/debug/deps/app*.0.o
0000000000000000 t rust_begin_unwind
0000000000000000 N __rustc_debug_gdb_scripts_section__
0000000000000000 T _start
0000000000000000 r str.0
0000000000000000 r str.1
0000000000000000 d app::_start::_MSG_FILE_LINE::h21fcbd8366a7e1b6
                 U core::panicking::panic::h194ce5d68a8f28a1
0000000000000000 t drop::h8b70c8901008835d

Bisecting:

BAD: rustc 1.15.0-nightly (daf8c1dfc 2016-12-05)

GOOD: rustc 1.15.0-nightly (ebeee0e27 2016-12-04)

AFAICT, the difference is that rust_begin_unwind is never a extern/global
symbol in recent nightlies like it used to be:

# with GOOD rustc
$ cargo rustc -- --emit=obj

$ nm -C ./target/debug/deps/app-*.o
0000000000000000 T rust_begin_unwind
0000000000000000 N __rustc_debug_gdb_scripts_section__
0000000000000000 T _start
0000000000000000 r str.0
0000000000000000 r str.1
0000000000000000 d app::_start::_MSG_FILE_LINE::h0939c9c7dafe8539
                 U core::panicking::panic::h194ce5d68a8f28a1
0000000000000000 t drop::he2bf721309cf573a

Changing the extern "C" fn to public doesn't help:


 #[lang = "panic_fmt"]
-extern "C" fn panic_fmt() -> ! {
+pub extern "C" fn panic_fmt() -> ! {
     loop {}
 }
# with BAD rustc
$ nm -C ./target/debug/deps/app-*.0.o
0000000000000000 t rust_begin_unwind
0000000000000000 N __rustc_debug_gdb_scripts_section__
0000000000000000 T _start
0000000000000000 r str.0
0000000000000000 r str.1
0000000000000000 d app::_start::_MSG_FILE_LINE::hb927abaa970af5cf
                 U core::panicking::panic::h194ce5d68a8f28a1
0000000000000000 t drop::hc6005949ff734e37

cc @michaelwoerister this may have been caused by #38117

@japaric That analysis looks pretty correct to me. I suspect that adding #[no_mangle] in addition to pub would solve the problem. But I'll think about what a clean solution would be.

@brson, @alexcrichton: I guess lang-items should always have external linkage?

@michaelwoerister yeah unfortunately things like rust_begin_unwind have to be external, although ideally one day I'd like to fix that!

If it's not already #[no_mangle] and pub it likely should be though, I'd prefer to avoid special-casing these symbols too much.

@alexcrichton OK.

#[no_mangle] is slightly confusing because the actual symbol name can be different from the function name (as in @japaric's example).

Also, should these symbols be re-exported from (c)dylibs? Probably not, right?

Yeah ideally we wouldn't export rust_begin_unwind from cdylibs, and I don't think it'll be required to link correctly either.

Sorry to be annoyning but a few people that work with the thumbv*-none-eabi* targets have bumped into this and asked about it on the #rust-embedded IRC channel. Is this likely to be fixed soon?

@japaric Have you tried if adding #[no_mangle] helps?

@michaelwoerister
Adding #[no_mangle] to panic_fmt helped in my case. So how does this work?
It picks up default panic_fmt when it can't find the custom one?

The #[no_mangle] attribute just prevents the compiler from hiding the symbol. The compiler generally will try to hide as many symbols as possible because it can make for smaller and faster code and allows LLVM to do more optimizations. The algorithm that determines what to hide has become a little more aggressive recently, which is why this pops up now.

So there is a workaround (i.e. #[no_mangle]) but it's not quite ideal. I'd rather that the compiler knows about these special symbols (or that we require, with a lint for example, that this lang-item and maybe others, have the right name and annotations).

I know what #[no_mangle] does, what I don't know is why do we get 'rust_begin_unwind is missing' error instead of 'panic_fmt is missing' error.

Oh, that's because this already has some special handling in the compiler. As far as I can tell, no matter what actual name the function has, if it is marked with #[lang = "panic_fmt"] then it will be assigned "rust_begin_unwind" as symbol name. It's a bit strange.

@michaelwoerister
Oh, now it makes sense, thank you for explaining.
I was thinking there is some other version of panic_fmt that gets pulled in and makes calls to rust_begin_unwind 馃榾

@michaelwoerister

Have you tried if adding #[no_mangle] helps?

That works, thanks. Is that how this lang item is supposed to be used from now on? Or will the no no_mangle form work again in the future? Mainly want to know if I should go ahead and change all the references to panic_fmt in e.g. copper, f3, etc. right now or do nothing at all 馃槃.

@japaric I think that's pretty much up to the tools and compiler teams to decide. I personally don't mind giving lang-items special treatment, since that allows us to later not require #[no_mangle] or even that they are exported.

@alexcrichton @michaelwoerister Could someone clarify how to fix this for stable builds?
I haven't defined #![no_main]or #![no_std] for my crate (Cargo.toml), but linking fails on Windows using latest stable.

@urschrei you may be running into https://github.com/rust-lang/rust/issues/18807, can you test the workaround mentioned?

@alexcrichton Just adding a spare function still fails with the same error. I assume adding it to lib.rs instead of ffi.rs doesn't matter (Also I opened https://github.com/rust-lang/rust/issues/41609, but lmk if it's a duplicate and I'll close it)

Oops, turns out it does have to be in lib.rs. Link step passes now.

Ping from triage!

I attempted to update the code:

> cat .\src\main.rs
#![feature(panic_handler)]
#![no_main]
#![no_std]

#[no_mangle]
pub fn _start() -> ! {
    panic!()
}

use core::panic::PanicInfo;

#[panic_handler]
#[no_mangle]
pub fn panic(_info: &PanicInfo) -> ! {
    loop { }
}

but I got a different error, possibly because I'm on windows

>  cargo rustc -- -C link-arg=-nostartfiles
   Compiling app v0.1.0 (file:///C:/Users/steve/tmp/app)
error: linking with `link.exe` failed: exit code: 1561
  |
  = note: "C:\\Program Files (x86)\\Microsoft Visual Studio\\2017\\Community\\VC\\Tools\\MSVC\\14.15.26726\\bin\\HostX64\\x64\\link.exe" "/NOLOGO" "/NXCOMPAT" "/LIBPATH:C:\\Users\\steve\\.rustup\\toolchains\\nightly-x86_64-pc-windows-msvc\\lib\\rustlib\\x86_64-pc-windows-msvc\\lib" "C:\\Users\\steve\\tmp\\app\\target\\debug\\deps\\app-3187309a36d3b090.1aq5w1s18bk2pb4a.rcgu.o" "/OUT:C:\\Users\\steve\\tmp\\app\\target\\debug\\deps\\app-3187309a36d3b090.exe" "/OPT:REF,NOICF" "/DEBUG" "/NATVIS:C:\\Users\\steve\\.rustup\\toolchains\\nightly-x86_64-pc-windows-msvc\\lib\\rustlib\\etc\\intrinsic.natvis" "/NATVIS:C:\\Users\\steve\\.rustup\\toolchains\\nightly-x86_64-pc-windows-msvc\\lib\\rustlib\\etc\\liballoc.natvis" "/NATVIS:C:\\Users\\steve\\.rustup\\toolchains\\nightly-x86_64-pc-windows-msvc\\lib\\rustlib\\etc\\libcore.natvis" "/LIBPATH:C:\\Users\\steve\\tmp\\app\\target\\debug\\deps" "/LIBPATH:C:\\Users\\steve\\.rustup\\toolchains\\nightly-x86_64-pc-windows-msvc\\lib\\rustlib\\x86_64-pc-windows-msvc\\lib" "C:\\Users\\steve\\.rustup\\toolchains\\nightly-x86_64-pc-windows-msvc\\lib\\rustlib\\x86_64-pc-windows-msvc\\lib\\libcore-68de561760a7c421.rlib" "C:\\Users\\steve\\.rustup\\toolchains\\nightly-x86_64-pc-windows-msvc\\lib\\rustlib\\x86_64-pc-windows-msvc\\lib\\libcompiler_builtins-a0d3327a110151c3.rlib" "-nostartfiles"
  = note: LINK : warning LNK4044: unrecognized option '/nostartfiles'; ignored
          LINK : fatal error LNK1561: entry point must be defined


error: aborting due to previous error

error: Could not compile `app`.

I tried to figure out the equivalent msvc option, but it wasn't clear...

Instead of defining a lang item, the panic_implementation attribute was implemented, which was later stabilized as panic_handler. For some time, the rust_begin_unwind issue still existed with the panic_implementation attribute, but it was fixed before stabilizing.

So this issue was superseded by https://github.com/rust-lang/rust/issues/51342, which was fixed. Therefore I'm going to close this issue.

Was this page helpful?
0 / 5 - 0 ratings