如何手动提供core::panicking::panic*给lld?

How to manually provide core::panicking::panic* to lld?

我正在将 rlib 的 Rust 代码编译为 LLVM IR,然后使用 Clang 编译 & link 它与 C 程序。这一直有效,直到我的代码包含恐慌,此时我得到 linker 错误:

ld.lld: error: undefined symbol: core::panicking::panic_bounds_check::hc3a71010bf41c72d
>>> referenced by ld-temp.o
>>>               lto.tmp:(run)
>>> referenced by ld-temp.o
>>>               lto.tmp:(run)
>>> referenced by ld-temp.o
>>>               lto.tmp:(run)
>>> referenced 11 more times

ld.lld: error: undefined symbol: core::panicking::panic::hd695e3b1d0dd4ef4
>>> referenced by ld-temp.o
>>>               lto.tmp:(run)
clang: error: ld.lld command failed with exit code 1 (use -v to see invocation)

我尝试了两种方法来缓解这种情况:

  1. 我已将 panic_handler 添加到我的图书馆:

    use core::panic::PanicInfo;
    
    #[panic_handler]
    pub extern fn panic(_: &PanicInfo<'_>) -> ! {
        loop{}
    }
    
  2. 我在 Cargo.toml:

    中将 panic 模式设置为 abort
    [profile.release]
    panic = "abort"
    

单独或组合都不能解决问题。

更多详情

在评论中,@Solomon Ucko 要求提供有关整个编译管道的更多详细信息。正如我在标签中所写,这是 no_std;另外,编译目标是MOS 6502。这是要编译和(尝试)link:

的完整命令列表
llvm-mos/bin/clang --config llvm-mos-sdk/build/commodore/64.cfg \
    -O2 -c \
    -o _build/main.c.o \
    src/main.c
cargo rustc --release -- \
    -C debuginfo=0 -C opt-level=1 --emit=llvm-ir
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

基于 ,我通过将 -Z build-std 传递给 Cargo 来解决这个问题,从而从 Rust 的 core 库中获取 LLVM IR,并将其链接进去。

但后来我意识到我可以做得更好,并避免 -Z std 强加的长时间编译,只需采用以下定义 core::panicking::panic_bounds_checkcore::panicking::panic 来自这些 IR 文件,简化了它们的主体,并将它们添加到手写的 panic.ll 文件中:

%"panic::location::Location" = type { { [0 x i8]*, i64 }, i32, i32 }

; core::panicking::panic
; Function Attrs: cold noinline noreturn nounwind nonlazybind
define void @_ZN4core9panicking5panic17hd695e3b1d0dd4ef4E([0 x i8]* noalias nonnull readonly align 1 %expr.0, i64 %expr.1, %"panic::location::Location"* noalias readonly align 8 dereferenceable(24) %0) unnamed_addr #22 {
start:
  unreachable
}

; core::panicking::panic_bounds_check
; Function Attrs: cold noinline noreturn nounwind nonlazybind
define void @_ZN4core9panicking18panic_bounds_check17hc3a71010bf41c72dE(i64 %0, i64 %1, %"panic::location::Location"* noalias readonly align 8 dereferenceable(24) %2) unnamed_addr #22 {
start:
  unreachable
}

TBH 我不确定它有多健壮(也许他们应该在“无法访问”之前通过分支循环到 start?),但至少它让我得到了一个完全链接和可运行的程序。