如何使用自定义llc编译Rust程序?

Hob*_*ski 7 llvm rust

我有一个自定义LLVM后端,并希望为该自定义(nostd)目标交叉编译Rust.我想分两步编译Rust程序:

  1. 使用rustc产生LLVM IR.
  2. 使用我自己的opt,llc并将LLVM IR转换为机器代码.

我试过用cargo rustc -- --emit=llvm-ir.我得到.ll文件,然后llc用来获取.o文件.然后我libcore以相同的方式交叉编译.当我尝试将所有对象链接在一起时,它告诉我一个未定义的引用.我用的是同犯的libcorerustc.这似乎是LLVM版本的一个问题,但我不确定.

小智 9

您应该注意以下几点。最重要的是,如果您从 rustup 或发行版包管理器获取 rustc 默认使用的 LLVM 版本,它/不是/实际的 LLVM 版本,并且实际上可能与特定的 llvm 版本不兼容位码。我们在我的项目中通过使用--llvm-root配置标志从源代码构建 Rust 来解决这个问题。然后,您可以将rustup toolchain link构建的 rustc 链接到自定义 rustup 工具链中。

其次,如果您至少使用 rustc 1.34 并将 -C linker-plugin-lto 标志传递给 rustc,则可以使 rustc 发出包含 llvm 位代码而不是机器代码的 .rlib 文件。我还编写了以下脚本,如果上述方法不适合您,它可以解压包含目标代码的 rlib 文件并将其打包为包含 llvm 位代码的 rlib 文件。

#!/bin/bash
dir="$(mktemp -d)"
trap "rm -rf $dir" INT TERM EXIT
archive=$(realpath -m $1)
cd "$dir"
ar x "$archive"
rm ./*.rcgu.o
for file in *.bc.z; do
len=`od -An -t u4 -j 15 -N4 $file`
blen=`od -An -t u8 -j $((len+19)) -N8 $file`
tail -c+$((len+28)) $file | head -c $blen > $file.bc.gz
printf "\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\x00" |cat - $file.bc.gz |gzip -dc > ${file%.bc.z}.o
done
rm *.bc.z
rm *.gz
rm "$archive"
llvm-ar rs "${archive}" ./*
Run Code Online (Sandbox Code Playgroud)

获得 rlib 文件后,您可以在它们上使用任何 llvm 工具链工具,就像使用包含 llvm 位代码的 .a 文件一样。

在执行最后的链接方面,有一些事情需要牢记。首先,rustc 自动生成符号__rust_alloc__rust_alloc_zeroed__rust_dealloc和,__rust_realloc并将它们分别指向__rg_alloc(和类似的__rg_符号),这是默认使用 jemalloc 的 GlobalAlloc 实现,或者__rdl_alloc(和分别类似的__rdl_符号),这是由 libc 支持的系统分配器malloc。如果您不使用 rustc 进行最终链接,则必须自己实现这些符号。

其次,libstd 和 libcore 依赖于您可能还必须链接的其他一些库。根据您使用的标准库的哪个部分,您可能会发现需要不同的库集,因此如果没有特定的错误消息,我无法帮助您,但我可以告诉您我的应用程序的库列表最终要求是,按顺序:std, core, alloc, unwind, compiler_builtins, panic_abort, backtrace_sys, rustc_demangle。如果你使用panic=unwind,你显然必须使用它。如果您发现仍然缺少符号,我建议使用 nm 查找包含缺少符号的库,并通过反复试验找出它在链接器顺序中的位置。

希望这会有所帮助,因为我花了相当多的精力来设计这个确切问题的解决方案(尽管不是为了交叉编译的目的)。