eyra 0.16.2

Rust programs written entirely in Rust
eyra-0.16.2 doesn't have any documentation.

Eyra is a package that supports building Rust programs implemented entirely in Rust.

It uses Origin for program and thread startup and shutdown, and c-gull for ABI-compatible libc function implementations.

Quick start

Check out this hello world example.

In detail

Eyra needs two things. First, a Cargo.toml dependency, which we can add with:

cargo add eyra --rename=std

And, a build.rs file to add -nostartfiles to the link flags to disable the host startup code, so that Eyra can provide its own. build.rs:

fn main() {
    println!("cargo:rustc-link-arg=-nostartfiles");
}

With these two steps, on Nightly Rust, on x86-64, x86, aarch64, or riscv64 Linux, this crate prints "Hello, world!". And under the covers, it uses Origin to start and stop the program, c-ward to handle libc calls from std, and rustix to do the printing, so it's completely implemented in Rust.

Optional logging

Eyra has a log feature to enable Rust log tracing of program and thread startup and shutdown, and an env_logger feature to install env_logger as the logger, which can be enabled in Cargo.toml:

[dependencies]
std = { package = "eyra", version = "<current-version>", features = ["log", "env_logger"] }

With this, and setting the RUST_LOG environment variable to "trace", the hello world program output like this:

[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`

Known Limitations

Known limitations in Eyra include:

  • Dynamic linking isn't implemented yet.
  • Many libc C functions that aren't typically needed by most Rust programs aren't implemented yet.

Compatibility with -Zbuild-std

Eyra works with -Zbuild-std, however the std trick used above doesn't work, so it's necessary to instead use this cargo add invocation:

cargo add eyra

and to also add this line to the program's main.rs file:

extern crate eyra;

to ensure that the Eyra libraries are linked in.

Reducing code size

Eyra can be used with the techniques in min-sized-rust to produce very small statically-linked binaries. Check out the hello-world-small example.

Background

Eyra is similar to Mustang and uses the same underlying code, but instead of using a custom target and -Z build-std, Eyra just needs users to add -nostartfiles to their link line, such as via build.rs in the example.

Like Mustang, Eyra currently runs on Nightly Rust on Linux on x86-64, x86, aarch64, and riscv64. It aims to support all Linux versions supported by Rust, though at this time it's only tested on relatively recent versions. It's complete enough to run:

Eyra isn't about making anything safer, for the foreseeable future. The major libc implementations are extraordinarily well tested and mature. Eyra for its part is experimental and contains lots of unsafe.

Design philosophy

Eyra and the libraries it uses have some design goals.

Normal Rust, all the way down

Sometimes in libc implementation code, there's a temptation to say "it's ok if some things are technically Undefined Behavior, because this is Low Level Code and We Know What We're Doing".

Origin, c-scape, c-gull, rustix, and the others strive to resist this temptation, and follow the Rust rules, including strict provenance, I/O safety, and all the rest, all the way down to the syscalls.

It's just normal Rust code, as far down as we can go in userspace, and when we eventually do have to switch to inline asm, we do as little of it as we can.

Currently there is only one known place where this goal is not achieved. In a "static PIE" executable (eg. built with RUSTFLAGS="-C target-feature=+crt-static"), the dynamic linker isn't used, so the executable has to handle all its relocations itself. However, that means storing to memory locations that wouldn't otherwise be considered mutable. Origin's code for doing this is currently disabled by default, and can be enabled with the "experimental-relocate" cargo feature.

C compatibility as a layer on top of Rust, not vice versa

Eyra is built on a collection of Rust crates with idiomatic Rust APIs, and two crates, c-scape and c-gull, which are relatively thin layers on top that implement the libc-compatible C ABI.

It's sometimes more work to write the code as separate layers like this, but it has the advantage of clearly separating out the unsafe associated with things like C pointers and strings in libc APIs from the essential unsafe needed to implement things like system calls, thread primitives, and other features. And it means that Rust programs that don't want to go through the C compatibility layer can use the underlying crates directly.