Rust on Linux without any libc

Hello!
I want to make a really barebones application being as small as possible which cannot depend on glibc. I tried the musl target, but that resulted in a 350KB binary with just an infinite loop in the main function and all general optimizations in release profile (stripped, lto, one codegen unit, Oz, panic abort with custom built std)

I really don't want to write that thing in pure assembly or C and as there are already crates for syscalls, which is all I really need externally, I wonder if there is any way to really have a "raw" linux target?

Thanks

AFAIK this excellent post by Philipp Oppermann is still relevant and shows how to build a binary without a C runtime: A Freestanding Rust Binary | Writing an OS in Rust

Oh yeah I know that blog, but is the barebones thumb target really what I want? I mean doesn't linux still have some guard lines to how its elf files look and calling conventions etc.?

Edit: philipp also says something about "This binary expects various things, for example, that a stack is initialized when the _start function is called" and looking at thumbv7m-none-eabi - The rustc book it seems like those thumb targets are meant for arm, not x86_64?

Did you also use panic_immediate_abort, that omits the entire panic machinery, which should save a fair amount of space.

Read this and the resources linked within

Yes, forgot to mention that, I used panic abort aswell as

This isn't really helpful as that's already what I am doing and I really just want basic syscalls

Edit: The no_std example seems interesting, but that still needs glibc dynamic linking. That but with a linux target that doesn't link against libc would be great.

Found an issue asking for exactly such targets:

1 Like

Can I acheive something like that with a custom specified target spec json?

There is already such a target for x86_64.

2 Likes

That was what I was searching all the time :face_holding_back_tears: Thank you!

1 Like

Uhm..

toolchain 'stable-x86_64-unknown-linux-gnu' does not support target 'x86_64-unknown-linux-none';

do I need a custom toolchain?

Either that or build core for that target with Cargo's unstable build-std feature. From the target page:

Rust does not yet ship pre-compiled artifacts for this target. To compile for this target, you will either need to build Rust with the target enabled (see "Building the target" above), or build your own copy of core by using build-std or similar.

I get this error when doing rustup target add x86_64-unknown-linux-none, or does this also handle that?

You can't install the target via rustup. There is nothing to install. It's a built-in target, so you should see it if you run rustc --print target-list. Try running:

cargo +nightly build -Z build-std=core --target x86_64-unknown-linux-none

after you added the source code for your host via

rustup +nightly component add rust-src

(taken from this SO answer)

1 Like

Just panic=abort or also -Zbuild-std-features=panic_immediate_abort? The former keeps most of the panic machinery and for example still supports RUST_BACKTRACE, while the latter turns every panic into a SIGILL.

1 Like

hmm I'll keep that in mind for release build, thanks

On important insight that is still missing from min-sized-rust (one day I will contribute a fix unless someone beats me to it) is that 300 kB of a hello world Rust program comes from code to read object file sections and debug information to allow Rust programs to print a nice backtrace upon panics (both for panic abort and panic unwind).

So explicitly disabling the backtrace feature of libstd will make binaries significantly smaller. See my comment at Rust symbol demangling · Issue #110 · google/bloaty · GitHub under "Common Source of Rust Binary Bloat" for more details.

The tip from bjorn3 to build with panic_immediate_abort will remove even more code though through lto. But -Zbuild-std and -Zbuild-std-features will probably become stable before panic_immediate_abort.

1 Like