• 不使用标准库
    • 使用 libc
    • 不用标准库编写可执行程序
    • 关于 language items 的更多细节

    不使用标准库

    no-stdlib.md


    commit 893f42a83466cf02b6fd6d3c82d5419cdad47474

    Rust 的标准库提供了很多有用的功能,不过它假设它的 host 系统的多种功能的支持:线程,网络,堆分配和其他功能。有些系统并没有这些功能,不过,Rust也能在这些系统上工作。为此,我们可以通过一个属性来告诉 Rust 我们不想使用标准库:#![no_std]

    注意:这个功能技术上是稳定的,不过有些附加条件。其一,你可以构建一个稳定的#![no_std]库,但二进制文件不行。关于没有标准库的库文件的细节,查看关于#![no_std]的章节。

    很显然你并不一定需要标准库:可以使用#[no_std来构建一个可执行程序。

    使用 libc

    为了构建一个#[no_std]可执行程序,我们需要 libc 作为依赖。可以在Cargo.toml文件中指定:

    1. [dependencies]
    2. libc = { version = "0.2.14", default-features = false }

    注意默认功能被禁用了。这是关键的一步————libc 的默认功能引用了标准库所以必须被禁用。

    不用标准库编写可执行程序

    有两种可能的控制入口点的方法:#[start]属性,或者用你自己的代码 override C main函数的默认 shim。

    被标记为#[start]的函数传递的参数格式与 C 一致:

    1. #![feature(lang_items, core_intrinsics)]
    2. #![feature(start)]
    3. #![no_std]
    4. use core::intrinsics;
    5. // Pull in the system libc library for what crt0.o likely requires.
    6. extern crate libc;
    7. // Entry point for this program.
    8. #[start]
    9. fn start(_argc: isize, _argv: *const *const u8) -> isize {
    10. 0
    11. }
    12. // These functions are used by the compiler, but not
    13. // for a bare-bones hello world. These are normally
    14. // provided by libstd.
    15. #[lang = "eh_personality"]
    16. #[no_mangle]
    17. pub extern fn rust_eh_personality() {
    18. }
    19. // This function may be needed based on the compilation target.
    20. #[lang = "eh_unwind_resume"]
    21. #[no_mangle]
    22. pub extern fn rust_eh_unwind_resume() {
    23. }
    24. #[lang = "panic_fmt"]
    25. #[no_mangle]
    26. pub extern fn rust_begin_panic(_msg: core::fmt::Arguments,
    27. _file: &'static str,
    28. _line: u32) -> ! {
    29. unsafe { intrinsics::abort() }
    30. }

    要 override 编译器插入的main shim,你必须使用#![no_main]禁用它并通过正确的 ABI 和正确的名字来创建合适的函数,这也需要需要覆盖编译器的命名改编:

    1. #![feature(lang_items, core_intrinsics)]
    2. #![feature(start)]
    3. #![no_std]
    4. #![no_main]
    5. use core::intrinsics;
    6. // Pull in the system libc library for what crt0.o likely requires.
    7. extern crate libc;
    8. // Entry point for this program.
    9. #[no_mangle] // ensure that this symbol is called `main` in the output
    10. pub extern fn main(_argc: i32, _argv: *const *const u8) -> i32 {
    11. 0
    12. }
    13. // These functions are used by the compiler, but not
    14. // for a bare-bones hello world. These are normally
    15. // provided by libstd.
    16. #[lang = "eh_personality"]
    17. #[no_mangle]
    18. pub extern fn rust_eh_personality() {
    19. }
    20. // This function may be needed based on the compilation target.
    21. #[lang = "eh_unwind_resume"]
    22. #[no_mangle]
    23. pub extern fn rust_eh_unwind_resume() {
    24. }
    25. #[lang = "panic_fmt"]
    26. #[no_mangle]
    27. pub extern fn rust_begin_panic(_msg: core::fmt::Arguments,
    28. _file: &'static str,
    29. _line: u32) -> ! {
    30. unsafe { intrinsics::abort() }
    31. }

    关于 language items 的更多细节

    目前编译器对能够被可执行文件调用的符号做了一些假设。正常情况下,这些函数是由标准库提供的,不过没有它你就必须定义你自己的了。这些符号被称为“language items”,并且他们每个都有一个内部的名称,和一个必须符合签名的实现。

    这些函数中的第一个,eh_personality,被编译器的错误机制使用。它通常映射到 GCC 的特性函数上(查看libstd实现来获取更多信息),不过对于不会触发恐慌的包装箱可以确定这个函数不会被调用。language item 的名称是eh_personality

    第二个函数,rust_begin_panic,也被作为编译器的错误机制使用。当发生 panic 时,它控制显示在屏幕上的信息。虽然 language item 的名称是panic_fmt,但是符号的名称是rust_begin_panic

    第三个函数,rust_eh_unwind_resume,在target 选项中的custom_unwind_resume flag 被设置时也是必需的。它允许自定义在 landing pads 的最后的 resuming unwind 过程。language item 的名字是eh_unwind_resume