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

时间:2018-10-22 07:49:16

标签: rust llvm

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

  1. 使用rustc生成LLVM IR。
  2. 使用我自己的optllc将LLVM IR转换为机器代码。

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

1 个答案:

答案 0 :(得分:0)

您应该注意几件事。最重要的是,如果从rustup或发行版软件包管理器获得rustc,则rustc默认使用的LLVM版本是/ not /实际的LLVM版本,并且实际上可能与特定的llvm版本不兼容。我们通过使用--llvm-root标志进行配置来从源构建锈来解决我项目中的此问题。然后,您可以使用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}" ./*

一旦有了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查找包含丢失符号的库,并通过反复试验找出它在链接器顺序中的位置。

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