|
1 |
| -# Beneath std |
| 1 | +# Beneath `std` |
2 | 2 |
|
3 |
| -This section documents (or will document) features that are provided by the standard library and |
4 |
| -that `#![no_std]` developers have to deal with (i.e. provide) to build `#![no_std]` binary crates. A |
5 |
| -(likely incomplete) list of such features is shown below: |
| 3 | +This section documents features that are normally provided by the `std` crate and |
| 4 | +that `#![no_std]` developers have to deal with (i.e. provide) to build |
| 5 | +`#![no_std]` binary crates. |
6 | 6 |
|
7 |
| -- `#[lang = "eh_personality"]` |
8 |
| -- `#[lang = "start"]` |
9 |
| -- `#[lang = "termination"]` |
10 |
| -- `#[panic_implementation]` |
| 7 | +## Using `libc` |
| 8 | + |
| 9 | +In order to build a `#[no_std]` executable we will need `libc` as a dependency. |
| 10 | +We can specify this using our `Cargo.toml` file: |
| 11 | + |
| 12 | +```toml |
| 13 | +[dependencies] |
| 14 | +libc = { version = "0.2.146", default-features = false } |
| 15 | +``` |
| 16 | + |
| 17 | +Note that the default features have been disabled. This is a critical step - |
| 18 | +**the default features of `libc` include the `std` crate and so must be |
| 19 | +disabled.** |
| 20 | + |
| 21 | +Alternatively, we can use the unstable `rustc_private` private feature together |
| 22 | +with an `extern crate libc;` declaration as shown in the examples below. |
| 23 | + |
| 24 | +## Writing an executable without `std` |
| 25 | + |
| 26 | +We will probably need a nightly version of the compiler to produce |
| 27 | +a `#![no_std]` executable because on many platforms, we have to provide the |
| 28 | +`eh_personality` [lang item], which is unstable. |
| 29 | + |
| 30 | +Controlling the entry point is possible in two ways: the `#[start]` attribute, |
| 31 | +or overriding the default shim for the C `main` function with your own. |
| 32 | +Additionally, it's required to define a [panic handler function](panic-handler.html). |
| 33 | + |
| 34 | +The function marked `#[start]` is passed the command line parameters |
| 35 | +in the same format as C (aside from the exact integer types being used): |
| 36 | + |
| 37 | +```rust |
| 38 | +#![feature(start, lang_items, core_intrinsics, rustc_private)] |
| 39 | +#![allow(internal_features)] |
| 40 | +#![no_std] |
| 41 | + |
| 42 | +// Necessary for `panic = "unwind"` builds on some platforms. |
| 43 | +#![feature(panic_unwind)] |
| 44 | +extern crate unwind; |
| 45 | + |
| 46 | +// Pull in the system libc library for what crt0.o likely requires. |
| 47 | +extern crate libc; |
| 48 | + |
| 49 | +use core::panic::PanicInfo; |
| 50 | + |
| 51 | +// Entry point for this program. |
| 52 | +#[start] |
| 53 | +fn main(_argc: isize, _argv: *const *const u8) -> isize { |
| 54 | + 0 |
| 55 | +} |
| 56 | + |
| 57 | +// These functions are used by the compiler, but not for an empty program like this. |
| 58 | +// They are normally provided by `std`. |
| 59 | +#[lang = "eh_personality"] |
| 60 | +fn rust_eh_personality() {} |
| 61 | +#[panic_handler] |
| 62 | +fn panic_handler(_info: &PanicInfo) -> ! { core::intrinsics::abort() } |
| 63 | +``` |
| 64 | + |
| 65 | +To override the compiler-inserted `main` shim, we have to disable it |
| 66 | +with `#![no_main]` and then create the appropriate symbol with the |
| 67 | +correct ABI and the correct name, which requires overriding the |
| 68 | +compiler's name mangling too: |
| 69 | + |
| 70 | +```rust |
| 71 | +#![feature(lang_items, core_intrinsics, rustc_private)] |
| 72 | +#![allow(internal_features)] |
| 73 | +#![no_std] |
| 74 | +#![no_main] |
| 75 | + |
| 76 | +// Necessary for `panic = "unwind"` builds on some platforms. |
| 77 | +#![feature(panic_unwind)] |
| 78 | +extern crate unwind; |
| 79 | + |
| 80 | +// Pull in the system libc library for what crt0.o likely requires. |
| 81 | +extern crate libc; |
| 82 | + |
| 83 | +use core::ffi::{c_char, c_int}; |
| 84 | +use core::panic::PanicInfo; |
| 85 | + |
| 86 | +// Entry point for this program. |
| 87 | +#[no_mangle] // ensure that this symbol is included in the output as `main` |
| 88 | +extern "C" fn main(_argc: c_int, _argv: *const *const c_char) -> c_int { |
| 89 | + 0 |
| 90 | +} |
| 91 | + |
| 92 | +// These functions are used by the compiler, but not for an empty program like this. |
| 93 | +// They are normally provided by `std`. |
| 94 | +#[lang = "eh_personality"] |
| 95 | +fn rust_eh_personality() {} |
| 96 | +#[panic_handler] |
| 97 | +fn panic_handler(_info: &PanicInfo) -> ! { core::intrinsics::abort() } |
| 98 | +``` |
| 99 | + |
| 100 | +If you are working with a target that doesn't have binary releases of the |
| 101 | +standard library available via rustup (this probably means you are building the |
| 102 | +`core` crate yourself) and need compiler-rt intrinsics (i.e. you are probably |
| 103 | +getting linker errors when building an executable: |
| 104 | +``undefined reference to `__aeabi_memcpy'``), you need to manually link to the |
| 105 | +[`compiler_builtins` crate] to get those intrinsics and solve the linker errors. |
| 106 | + |
| 107 | +[`compiler_builtins` crate]: https://crates.io/crates/compiler_builtins |
| 108 | +[lang item]: https://doc.rust-lang.org/nightly/unstable-book/language-features/lang-items.html |
0 commit comments