如何手动向lld提供core::panicking::panic*符号解决Rust C混编链接错误
问题根因
你遇到的链接错误是因为编译Rust代码时仅导出了自身代码的LLVM IR,没有把core库中core::panicking相关的依赖实现一同带入链接流程,哪怕你已经定义了panic_handler,core库内部的panic入口包装函数仍然是缺失状态。
解决方法
方法1:补全Rust侧编译流程,携带core依赖
你的cargo rustc命令缺少目标架构指定,且仅导出自身代码IR,没有包含core库的编译产物:
- 首先准备好MOS 6502对应的Rust目标描述JSON文件,编译时指定目标:
cargo rustc --release --target=mos-6502.json -- -C debuginfo=0 -C opt-level=1 --emit=obj
不要用--emit=llvm-ir,直接编译为.o目标文件,rustc会自动将你定义的panic_handler与core库的panic入口做关联,不会再产生外部符号依赖。
2. 把编译生成的目标文件(路径为target/mos-6502/release/deps/chip8_c64-xxxxxx.o)替换原来的.ll文件传给clang链接即可。
方法2:手动指定符号别名(快速兜底)
如果你不想修改现有编译流程,可以直接在最后一步clang链接时通过链接器参数将缺失的符号指向你已经实现的panic处理函数:
llvm-mos/bin/clang --config llvm-mos-sdk/build/commodore/64.cfg \ -O2 \ -o _build/charset.prg \ _build/main.c.o \ target/release/deps/chip8_c64-e21ff59526dd729a.ll \ -Wl,--defsym=core::panicking::panic_bounds_check::hc3a71010bf41c72d=panic,--defsym=core::panicking::panic::hd695e3b1d0dd4ef4=panic
这里的panic就是你定义的panic_handler函数名,链接器会直接把缺失的符号指向该函数,不会再报未定义错误。
方法3:手动实现缺失符号
直接在你的Rust代码中用#[no_mangle]强制导出缺失的符号,指向你的panic逻辑:
use core::panic::PanicInfo; #[panic_handler] pub extern fn panic(_: &PanicInfo<'_>) -> ! { loop{} } #[no_mangle] #[allow(non_snake_case)] pub extern "Rust" fn core::panicking::panic_bounds_check::hc3a71010bf41c72d(_: usize, _: usize) -> ! { panic() } #[no_mangle] #[allow(non_snake_case)] pub extern "Rust" fn core::panicking::panic::hd695e3b1d0dd4ef4(_: &'static str, _: u32) -> ! { panic() }
注意函数参数要和core中对应panic函数的参数匹配,避免调用时栈出错。
额外注意
- 建议在
.cargo/config.toml中全局配置panic策略,确保跨目标生效:
[target.'cfg(all())'] panic = "abort"
- 尽量不要直接传递LLVM IR做跨语言链接,使用编译完成的目标文件可以避免很多符号关联问题。
内容的提问来源于stack exchange,提问作者Cactus
相关产品推荐
相关产品推荐

