[英]How to compile Rust to LLVM bitcode including dependencies?
我正在使用SAW验证一些 Rust 代码。 SAW 要求您编译为LLVM bitcode ,然后您可以导入并验证它。 我知道您可以使用 rustc 的--emit=llvm-bc
标志生成位码,这对于没有依赖项的项目非常有用。
尝试编译使用外部 crate 的项目时会出现问题。 这是一个示例 Cargo.toml 文件:
[package]
name = "foobar"
version = "0.1.0"
edition = "2018"
[dependencies]
pythagoras = "0.1.1"
这是我们可能想要编译和验证的基本src/lib.rs
:
pub use pythagoras;
#[no_mangle]
pub extern "C" fn calc_hypot(a: u32, b: u32) -> f64 {
pythagoras::theorem(a, b)
}
我们可以将它编译成这样的位码: RUSTFLAGS="--emit=llvm-bc" cargo build --release
。 问题是当前模块的位码及其依赖项是单独生成的(在target/release/deps/foobar-something.bc
和target/release/deps/pythagoras-somethingelse.bc
)。 它们仅在生成实际编译库时才合并。
有没有办法生成一个包含当前模块及其所有依赖项的单个位码文件,所以这个文件可以被导入,并且不会引用任何外部名称? 我意识到这是一个非常小众的案例,所以 hacky 解决方案(例如:编译到 C static lib,然后以某种方式将其转换回 LLVM 位码)也是完全合理的。
扩展Aiden4的评论:
rm -r target/
RUSTFLAGS="--emit=llvm-bc" cargo build --release
编译它llvm-link target/release/deps/*.bc > withdeps.bc
这将为您提供几乎所有依赖项。 事实证明,所有 Rust 程序都对core
或std
有隐含的依赖(尽管你可以通过不稳定的#![no_core]
避免这种情况,但祝你好运,实际上可以通过这种方式编译),所以你可能想要得到位码也是如此。
最简单的方法是将标准库从源代码编译为位码。 cargo
具有从 source 构建标准库的实验性支持,因此只需 append -Z build-std --target x86_64-unknown-linux-gnu
(并在需要时更新目标)到您的cargo
build 命令。 当使用-Z build-std
所需的--target
时,构建文件被放置在特定于目标的目录中,在这种情况下target/x86_64-unknown-linux-gnu/release/deps/
。 targetless 目录包含标准库的构建依赖项:我们不希望这样!
我们不想链接所有的标准库。 我们实际上只需要std
及其依赖项:这里不需要proc_macro
,因为我们正在编译为二进制文件,而不是 proc-macro。 我们还需要与proc_abort
或panic_unwind
链接,将其与我们选择的展开代码生成设置相匹配。 默认是展开,所以让我们删除另一个, proc_abort
。 让我们将这些库发送到砧板: rm target/x86_64-unknown-linux-gnu/release/deps/{panic_abort,proc_macro}-*.bc
。
这次让我们尝试真正的链接:
rm -r target/
RUSTFLAGS="--emit=llvm-bc" cargo build --release -Z build-std --target x86_64-unknown-linux-gnu
rm target/x86_64-unknown-linux-gnu/release/deps/{panic_abort,proc_macro}-*.bc
llvm-link target/x86_64-unknown-linux-gnu/release/deps/*.bc > withalldeps.bc
是的,它奏效了,嗯。 除了对其中未定义函数的调用仍然设法通过。 __rust_alloc
、 __rust_dealloc
、 __rust_realloc
和__rust_alloc_zeroed
是使用 Rust 的 LLVM 分支时定义的魔术函数。 标准库还依赖于libpthread
和dlsym
,它们是与语言无关的库/函数,通常在 C 中实现。 您可以使用clang
和支持使用 Clang 编译的libc
实现(GNU libc 没有,我认为 musl 可能在这里工作?)如果需要的话。 此外,如果您正在编译为可执行文件,则无法从_start
找到main
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.