Skip to content

Commit ddfa421

Browse files
authored
Fill "Beneath std" (#413)
1 parent e3f3af6 commit ddfa421

File tree

1 file changed

+106
-8
lines changed

1 file changed

+106
-8
lines changed

src/beneath-std.md

+106-8
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,108 @@
1-
# Beneath std
1+
# Beneath `std`
22

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.
66

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

Comments
 (0)