From ddfa4214487686e91b21aa29afb972c08a8f0d5b Mon Sep 17 00:00:00 2001 From: kadiwa Date: Fri, 22 Sep 2023 19:04:10 +0200 Subject: [PATCH] Fill "Beneath `std`" (#413) --- src/beneath-std.md | 114 +++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 106 insertions(+), 8 deletions(-) diff --git a/src/beneath-std.md b/src/beneath-std.md index 6f05182b..02a02bd7 100644 --- a/src/beneath-std.md +++ b/src/beneath-std.md @@ -1,10 +1,108 @@ -# Beneath std +# Beneath `std` -This section documents (or will document) features that are provided by the standard library and -that `#![no_std]` developers have to deal with (i.e. provide) to build `#![no_std]` binary crates. A -(likely incomplete) list of such features is shown below: +This section documents features that are normally provided by the `std` crate and +that `#![no_std]` developers have to deal with (i.e. provide) to build +`#![no_std]` binary crates. -- `#[lang = "eh_personality"]` -- `#[lang = "start"]` -- `#[lang = "termination"]` -- `#[panic_implementation]` +## Using `libc` + +In order to build a `#[no_std]` executable we will need `libc` as a dependency. +We can specify this using our `Cargo.toml` file: + +```toml +[dependencies] +libc = { version = "0.2.146", default-features = false } +``` + +Note that the default features have been disabled. This is a critical step - +**the default features of `libc` include the `std` crate and so must be +disabled.** + +Alternatively, we can use the unstable `rustc_private` private feature together +with an `extern crate libc;` declaration as shown in the examples below. + +## Writing an executable without `std` + +We will probably need a nightly version of the compiler to produce +a `#![no_std]` executable because on many platforms, we have to provide the +`eh_personality` [lang item], which is unstable. + +Controlling the entry point is possible in two ways: the `#[start]` attribute, +or overriding the default shim for the C `main` function with your own. +Additionally, it's required to define a [panic handler function](panic-handler.html). + +The function marked `#[start]` is passed the command line parameters +in the same format as C (aside from the exact integer types being used): + +```rust +#![feature(start, lang_items, core_intrinsics, rustc_private)] +#![allow(internal_features)] +#![no_std] + +// Necessary for `panic = "unwind"` builds on some platforms. +#![feature(panic_unwind)] +extern crate unwind; + +// Pull in the system libc library for what crt0.o likely requires. +extern crate libc; + +use core::panic::PanicInfo; + +// Entry point for this program. +#[start] +fn main(_argc: isize, _argv: *const *const u8) -> isize { + 0 +} + +// These functions are used by the compiler, but not for an empty program like this. +// They are normally provided by `std`. +#[lang = "eh_personality"] +fn rust_eh_personality() {} +#[panic_handler] +fn panic_handler(_info: &PanicInfo) -> ! { core::intrinsics::abort() } +``` + +To override the compiler-inserted `main` shim, we have to disable it +with `#![no_main]` and then create the appropriate symbol with the +correct ABI and the correct name, which requires overriding the +compiler's name mangling too: + +```rust +#![feature(lang_items, core_intrinsics, rustc_private)] +#![allow(internal_features)] +#![no_std] +#![no_main] + +// Necessary for `panic = "unwind"` builds on some platforms. +#![feature(panic_unwind)] +extern crate unwind; + +// Pull in the system libc library for what crt0.o likely requires. +extern crate libc; + +use core::ffi::{c_char, c_int}; +use core::panic::PanicInfo; + +// Entry point for this program. +#[no_mangle] // ensure that this symbol is included in the output as `main` +extern "C" fn main(_argc: c_int, _argv: *const *const c_char) -> c_int { + 0 +} + +// These functions are used by the compiler, but not for an empty program like this. +// They are normally provided by `std`. +#[lang = "eh_personality"] +fn rust_eh_personality() {} +#[panic_handler] +fn panic_handler(_info: &PanicInfo) -> ! { core::intrinsics::abort() } +``` + +If you are working with a target that doesn't have binary releases of the +standard library available via rustup (this probably means you are building the +`core` crate yourself) and need compiler-rt intrinsics (i.e. you are probably +getting linker errors when building an executable: +``undefined reference to `__aeabi_memcpy'``), you need to manually link to the +[`compiler_builtins` crate] to get those intrinsics and solve the linker errors. + +[`compiler_builtins` crate]: https://crates.io/crates/compiler_builtins +[lang item]: https://doc.rust-lang.org/nightly/unstable-book/language-features/lang-items.html