Unexpected `undefined reference to rust_eh_personality` when compiling with `-C panic=abort` for `no_std` library

Description:

I encountered an issue where I tried to compile a Rust static library with #![no_std] and -C panic=abort. However, when linking the resulting library with a C program, I received the following error:

/usr/bin/ld: libadd-withoutopt.a(core-d453bab70303062c.core.51655a4ef8d536d2-cgu.0.rcgu.o):(.data.DW.ref.rust_eh_personality[DW.ref.rust_eh_personality]+0x0): undefined reference to `rust_eh_personality'
collect2: error: ld returned 1 exit status

Steps to Reproduce

  1. Rust source (add.rs):

    #![no_std]
    
    use core::panic::PanicInfo;
    
    #[panic_handler]
    fn panic(_info: &PanicInfo) -> ! {
        loop {} 
    }
    
    #[no_mangle]
    pub fn add(a: i32, b: i32) -> i32 {
        a + b
    }
    
  2. C code (test.c):

    #include <stdio.h>
    
    extern int add(int a, int b);
    
    int main() {
        int result = add(1, 2);
        printf("The result is: %d\n", result);
        return 0;
    }
    
  3. Compilation commands:

    $ rustc -C panic=abort --crate-type staticlib add.rs -o libadd-withoutopt.a
    $ gcc test.c libadd-withoutopt.a -o main
    

    This results in the error:

     /usr/bin/ld: libadd-withoutopt.a(core-d453bab70303062c.core.51655a4ef8d536d2-cgu.0.rcgu.o):(.data.DW.ref.rust_eh_personality[DW.ref.rust_eh_personality]+0x0): undefined reference to `rust_eh_personality'
     collect2: error: ld returned 1 exit status
    
  4. However, if I add -C opt-level=3, the linking succeeds:

    $ rustc -C panic=abort -C opt-level=3 --crate-type staticlib add.rs -o libadd-withopt.a
    $ gcc test.c libadd-withopt.a -o main
    $ ./main
    The result is: 3
    

Questions:

  1. Why does using -C panic=abort without optimization still lead to an undefined reference to rust_eh_personality? My understanding was that this setting should prevent any references to Rust's panic machinery.

  2. Does setting -C opt-level=3 optimize out the unused rust_eh_personality symbol and make gcc runs fine, or is there another mechanism at play here?

Toolchain Information:

rustc 1.84.0-nightly (86d69c705 2024-10-22)
binary: rustc
commit-hash: 86d69c705a552236a622eee3fdea94bf13c5f102
commit-date: 2024-10-22
host: x86_64-unknown-linux-gnu
release: 1.84.0-nightly
LLVM version: 19.1.1

Any insights into this behavior would be greatly appreciated, thank you!! :smiling_face_with_three_hearts:

1 Like

If you are compiling for a target which by default uses panic=unwind, the precompiled standard library is compiled with panic=unwind and thus references rust_eh_personality even when your own code uses panic=abort. If you compile for a target which is always panic=abort you won't have this issue. And if you use the unstable -Zbuild-std flag of cargo, the standard library will be compiled with panic=abort and thus doesn'5 have the issue either.

2 Likes

Hello bjorn3, Thank you for the detailed explanation!

Following your advice, I recompiled the add library with -Zbuild-std and set panic=abort to avoid linking against the unwind features in the standard library.

Here's what I did:

  1. I created a new Cargo library project with the same code:

    cargo new --lib add
    

    and replaced the content of src/lib.rs with:

    #![no_std]
    
    use core::panic::PanicInfo;
    
    #[panic_handler]
    fn panic(_info: &PanicInfo) -> ! {
        loop {} 
    }
    
    #[no_mangle]
    pub fn add(a: i32, b: i32) -> i32 {
        a + b
    }
    
  2. I then compiled it using:

    cargo rustc --crate-type=staticlib -Zbuild-std --target x86_64-unknown-linux-gnu -- -C panic=abort
    
  3. I attempted to link the resulting libadd.a with test.c:

    gcc ../test.c target/x86_64-unknown-linux-gnu/debug/libadd.a -o main
    

However, I still encountered the following error:

/usr/bin/ld: target/x86_64-unknown-linux-gnu/debug/libadd.a(core-69a355373b02aaef.core.b9105654efbf3ff8-cgu.04.rcgu.o):(.data.DW.ref.rust_eh_personality[DW.ref.rust_eh_personality]+0x0): undefined reference to `rust_eh_personality'
collect2: error: ld returned 1 exit status

From your previous message, recompiling core with panic=abort should avoid pulling in unwind dependencies, but why it still give a undefined reference :thinking:

Thank you once again for your guidance!

If you do cargo rustc -- -Cpanic=abort only your own crate will use panic=abort, not any of your dependencies (including the standard library) You need to use CARGO_PROFILE_DEV_PANIC=abort (or CARGO_PROFILE_RELEASE_PANIC=abort if doing a release build) instead.

1 Like

Hello bjorn3, thanks again! Using CARGO_PROFILE_DEV_PANIC=abort with cargo rustc as you suggested worked perfectly. I was able to link test.c successfully, and the custom panic handler (infinite loop) was invoked as expected when adding 2147483647(2^31 - 1) and 1, resulting in a panic condition.

I do have an additional question:

When I compile the library with cargo rustc --release --crate-type=staticlib -- -C panic=abort (without recompiling core to get rid of unwind but with --release, which seems to strip out unused symbols), the linking with test.c is also successful. However, when running the output, the behavior deviates from the custom panic handler I defined. Instead of the expected infinite loop, it appears to use wrapping_add and outputs -2147483648.

Is this behavior expected? Since it bypasses my custom panic handler, would this be considered undefined behavior (UB)? Would this be something worth opening an issue for?

I also tried (CARGO_PROFILE_DEV_PANIC=abort + release ver):

CARGO_PROFILE_DEV_PANIC=abort cargo rustc --release --crate-type=staticlib -Zbuild-std --target x86_64-unknown-linux-gnu -- -C panic=abort`

It doesnt give expected panic handling too..

By default overflow checks are disabled in release builds, and the behaviour is defined to be wrapping for both signed and unsigned (so no risk of UB, unlike C). You can change this in your profile in your Cargo.toml. Or via environment variables as well probably.

1 Like

Thank you for clarifying, Vorpal! Now I fully understand ; )

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.