22 个版本
0.16.11 | 2024年5月18日 |
---|---|
0.16.10 | 2024年2月29日 |
0.16.9 | 2023年12月20日 |
0.16.5 | 2023年11月20日 |
0.14.5 | 2023年9月20日 |
#51 in FFI
每月 44 次下载
在 3 crates 中使用
79KB
Eyra 是一个支持使用 Rust 完全实现 Rust 程序的包。
它使用 Origin 进行程序和线程的启动和关闭,以及使用 c-gull 来实现与 ABI 兼容的 libc 函数。目前它支持 Nightly Rust 在 Linux 的 x86-64、x86、aarch64 和 riscv64 上运行。
快速入门
在 Eyra 下运行 Rust 程序需要两个步骤。首先,添加 Cargo.toml 依赖项,我们可以使用以下方式添加:
cargo add eyra --rename=std
然后,添加一个 build.rs 文件,将 -nostartfiles
添加到链接标志中,以禁用主机启动代码,这样 Eyra 就可以提供自己的。build.rs
fn main() {
println!("cargo:rustc-link-arg=-nostartfiles");
}
有了这些,cargo build
,cargo run
,cargo test
(使用 Nightly)等将正常工作,任何 *-unknown-linux-gnu*
目标都将正常工作。
在底层,它使用 Origin 来启动和关闭程序,使用 c-ward 来处理从 std
的 libc 调用,使用 rustix 来进行打印,因此它完全使用 Rust 实现。
示例
以下步骤的示例,请查看这个“Hello World”示例。
其他示例包括
为什么?
为什么使用Eyra?
-
它解决了Rust的
set_var
不安全问题。环境变量实现内部内存泄漏(它是可选的,但默认启用),因此setenv
等是线程安全的。 -
整个程序LTO,包括libc。这有时会产生更小的静态二进制文件,有时会产生更快的代码(尽管另一方面,有时并不,尽管另一方面,还有一些低垂的果实,所以考虑尝试并提交问题)。
要实现更多的代码大小缩减,请参阅hello-world-small示例中的技术。
-
支持使用Eyra和
-Zbuild-std
编译程序,以完全从源代码构建程序。 -
完全静态链接支持平台NSS/DNS配置。“这是否可能?” “是的,可能的。”
-
或者,提出你自己的原因!发挥创意,做自己想做的事情,并告诉我们。
为什么不使用Eyra?
-
它不如主要的libc实现成熟。
-
它不如主要的libc实现完整。它可以运行大多数Rust代码和一些流行的C库,但仍然缺乏许多典型C代码所使用的功能。
-
它目前依赖于Rust Nightly,并且只能在Linux上运行,目前仅在x86-64、x86、aarch64和riscv64上运行。
-
它目前无法在Miri下运行,因为Miri目前无法识别从汇编代码中发出的系统调用。话虽如此,Eyra确实努力遵守严格的来源和避免整个过程中出现未定义的行为,因此如果Miri获得了对这些系统调用的支持,Eyra应该处于有利地位。
-
不支持动态链接。
似乎“内存安全”可能是使用Eyra的理由,Eyra确实有很多用安全Rust编写的代码,因此它确实从Rust的内存安全性中受益。然而,Eyra也有很多unsafe
代码(实现libc不可避免)。在代码得到更彻底的验证之前,将其视为比成熟的C代码更安全是不现实的。
完全静态链接
Eyra的可执行文件不依赖于任何动态库,然而默认情况下,它们仍然依赖于动态链接器(例如,“/lib64/ld-linux-x86-64.so.2”)。
对于完全静态链接,目前有两种选择
-
使用以下命令构建:
RUSTFLAGS=-C target-feature=+crt-static -C relocation-model=static
。这禁用了位置无关可执行文件(PIE)模式,这是直接的,但会失去地址空间布局随机化(ASLR)的安全性优势。 -
使用
RUSTFLAGS=-C target-feature=+crt-static
构建,并启用experimental-relocate
特性。这允许PIE模式和ASLR工作,但它是通过启用重定位的实验性实现来实现的。到目前为止,这段代码似乎在实践中的应用是成功的,但它涉及到Rust代码在运行时自我修补,这超出了任何Rust语义。
可选日志记录
Eyra有一个log
特性,可以启用Rust log
对程序和线程的启动和关闭进行跟踪,以及一个env_logger
特性,用于安装env_logger
作为日志记录器,这可以在Cargo.toml中启用
[dependencies]
std = { package = "eyra", version = "<current-version>", features = ["log", "env_logger"] }
有了这个,并将环境变量RUST_LOG
设置为"trace",hello world程序将输出如下
[TRACE origin::program] Program started
[TRACE origin::thread] Main Thread[51383] initialized
[TRACE origin::program] Calling `.init_array`-registered function `0x55e86306bb80(1, 0x7ffd0f76aad8, 0x7ffd0f76aae8)`
[TRACE origin::program] Calling `origin_main(1, 0x7ffd0f76aad8, 0x7ffd0f76aae8)`
Hello, world!
[TRACE origin::program] `origin_main` returned `0`
[TRACE origin::thread] Thread[51383] calling `at_thread_exit`-registered function
[TRACE origin::thread] Thread[51383] calling `at_thread_exit`-registered function
[TRACE origin::program] Program exiting with status `0`
与-Zbuild-std
的兼容性
Eyra与-Zbuild-std
兼容,但是上面使用的--rename=std
技巧不起作用,因此需要使用这个cargo add
调用
cargo add eyra
并将此行添加到程序的main.rs
文件中
extern crate eyra;
以确保链接Eyra库。
减少代码大小
Eyra可以使用min-sized-rust中的技术生成非常小的静态链接二进制文件。查看hello-world-small示例。
与Mustang的关系
Eyra类似于Mustang并使用相同的底层代码,但与使用自定义目标和-Z build-std不同,Eyra只需要用户将-nostartfiles
添加到他们的链接行,例如通过示例中的build.rs。
与Mustang一样,Eyra目前运行在Linux上的Nightly Rust,支持x86-64、x86、aarch64和riscv64。它旨在支持所有由Rust支持的Linux版本(支持的平台),尽管目前只在相对较新的版本上进行了测试。它已经足够完善,可以运行
编译C程序
Eyra还可以编译成libc.a,可用于编译C程序;请参阅eyra-c存储库。
设计哲学
Eyra及其使用的库有一些设计目标。
从头到尾的正常Rust
有时在libc实现代码中,有一种诱惑要说“如果某些东西在技术上是不确定的,因为这是低级代码,我们知道我们在做什么”。
Origin、c-scape、c-gull、rustix和其他努力抵制这种诱惑,并遵循Rust规则,包括严格的来源、I/O安全以及所有其他规则,一直到底层系统调用。
这只是正常的Rust代码,只要我们在用户空间中能够走多远,当我们最终不得不切换到内联汇编时,我们尽可能少地做。
目前只知道一个地方没有实现这个目标。在“静态 PIE”可执行文件(例如,使用 RUSTFLAGS="-C target-feature=+crt-static"
构建)中,动态连接器没有被使用,所以可执行文件必须自己处理所有的重定位。然而,这意味着将数据存储在通常不会被考虑为可变的内存位置。Origin 实现这一功能的代码默认是禁用的,可以通过“experimental-relocate” cargo 功能来启用。
作为 Rust 之上的 C 兼容性层,而不是相反
Eyra 是基于一系列带有惯用 Rust API 的 Rust crate 构建,以及两个相对薄的层,c-scape 和 c-gull,这两个层实现了与 libc 兼容的 C ABI。
以这种方式编写代码可能需要更多的工作,但它有一个优点,即可以清楚地分离出与 C 指针和字符串等事物相关的 unsafe
,这些事物是 libc API 中的基本 unsafe
所必需的,例如系统调用、线程原语和其他功能。这意味着不希望通过 C 兼容性层的 Rust 程序可以直接使用底层 crate。
依赖关系
~12–21MB
~386K SLoC