Linker error for cdylib with panic=abort (Undefined symbol "_rust_eh_personality_catch")
If I attempt to compile a crate as a cdylib with panic=abort, I get the following error:
error: linking with `cc` failed: exit code: 1
note: Undefined symbols for architecture x86_64:
"_rust_eh_personality_catch", referenced from:
-exported_symbol[s_list] command line option
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
I'm using rustc 1.11.0-nightly (ad7fe6521 2016-06-23) on OSX 10.11.5.
I can repro by compiling an empty lib.rs with rustc lib.rs --crate-type cdylib -C panic=abort or with a Cargo.toml like the following:
[package]
name = "foo"
version = "0.0.0"
[lib]
crate-type = ["cdylib"]
[profile.release]
panic = "abort"
cc @alexcrichton since you've worked on both cdylib (#33553) and panic=abort (#32900) 😊
Steven Sheldon at 2016-06-25 17:27:41
Oh dear sounds bad! Not sure how this got past the bots...
Looks like this isn't a problem on Linux (yay linker shenanigans!) but we're erroneously claiming that this symbol is exported from the cdylib when it's not even contained. I believe I see the error and I'll try to have a patch shortly.
Alex Crichton at 2016-06-27 23:29:07
Er, maybe I won't have a chance to get around to this soon :(. As an explanation of the problem, though:
- The linker error happens on OSX because the command line option we pass
-exported_symbols_listis a file that contains the symbolrust_eh_personality_catch. That is, we're indicating to the linker that this symbol should be exported. - That symbol does not exist, however, because it's only defined in
libpanic_unwind.rlibwhich is not being linked. The linker on OSX decides this is a fatal error, whereas the linker on Unix for example does not decide this is a fatal error. - That file is generated here coming from
cdylib_exportshere which in turn comes from thereachableargument which is created here. - Creation of this list in involves iterating over all crates and pulling in their exported/reachable symbols.
- Currently a "reachable symbol" is any
#[no_mangle], reachable, extern symbol, which lo and behold our symbol is indeed.
So the problem here is that the loop over crates is looping over all crates, not the crates that are linked. When dealing with panic runtimes and allocators we have crates in the crate store which aren't actually linked, because some output formats may have them linked but others may not.
The fix here will probably be just ensuring that when generating the set of reachable symbols for a particular output type we only consider those crates being linked for that output type, not all crates in the world. There's a bit of refactoring here that may need to happen because the reachable set of symbols is also used for LTO, but the principle of the solution should remain the same.
I certainly wouldn't mind helping out anyone fix this if I don't end up getting around to it.
Alex Crichton at 2016-07-01 16:42:15
- The linker error happens on OSX because the command line option we pass
From what I can tell, on macOS today,
rustc --crate-type=cdylib -Cpanic=abort test.rscompletes successfully. However, the file generated is only 4 KB in size compared to the 4 MB on Linux. I suspect this is because the file is practically empty (see below for objdump). Indeed, it seems that we now are in a worse situation -- we appear to have been successful, but in fact it seems that linking and/or compilation failed.$ objdump -s libtest.dylib libtest.dylib: file format Mach-O 64-bit x86-64 Contents of section __text: 0fb0 554889e5 5dc3 UH..]. Contents of section __unwind_info: 0fb8 01000000 1c000000 00000000 1c000000 ................ 0fc8 00000000 1c000000 02000000 b00f0000 ................ 0fd8 34000000 34000000 b70f0000 00000000 4...4........... 0fe8 34000000 03000000 0c000100 10000100 4............... 0ff8 00000000 00000000 ........Mark Rousskov at 2017-05-06 15:22:26
I think it is expected that an empty
test.rswith the cdylib crate type will result in an empty dylib. On Linux it doesn't contain any functions other than a couple of fixed libc/compiler internal ones. All of the size you are seeing on Linux is because of debuginfo. On macOS debuginfo is put in a separate.dSYMbundle and in addition I believe dsymutil which generates the.dSYMbundle is able to eliminate debuginfo for dead functions, unlike the linker on Linux.bjorn3 at 2022-05-15 14:58:02