4

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

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. 我已将panic模式设置abortCargo.toml

    [profile.release]
    panic = "abort"
    

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

更多细节

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

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
4

1 回答 1

0

Based on this answer, I worked around this by passing -Z build-std to Cargo, thereby getting the LLVM IR from Rust's core library, and linking it in.

But then I realized I can do one better, and avoid the long compilation time imposed by -Z std, by just taking the definitions of core::panicking::panic_bounds_check and core::panicking::panic from these IR files, simplifying their body, and adding them to a hand-written panic.ll file:

%"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 I'm not sure how robust that is (maybe they should loop by branchin to start before `unreachable?), but at least it got me to a fully linked and runnable program.

于 2021-09-05T02:55:16.933 回答