Files
..

Rust on MontaukOS

Phase 1: no_std + alloc programs, cross-compiled from Linux with a stock nightly toolchain and a custom target spec. No compiler fork.

Setup (once)

curl --proto '=https' -sSf https://sh.rustup.rs | sh -s -- -y --default-toolchain none
~/.cargo/bin/rustup toolchain install nightly --component rust-src

rust-toolchain.toml selects nightly + rust-src for this directory. make programs builds the Rust programs when that toolchain is present and prints a notice and skips them otherwise. It never downloads a toolchain (RUSTUP_AUTO_INSTALL=0).

Building

make -C programs rust          # cargo build --release, copies to bin/os/*.elf
cd programs/rust && cargo build --release

Output: target/x86_64-unknown-montauk/release/<name>, installed as programs/bin/os/<name>.elf. Add new binaries to RUST_PROGRAMS in programs/GNUmakefile and to the workspace members.

Layout

Path Purpose
x86_64-unknown-montauk.json Target spec: static non-PIE ET_EXEC, no red zone, local-exec TLS, panic=abort
.cargo/config.toml -Zbuild-std=core,alloc, linker = x86_64-montauk-gcc
montauk-rt/ Runtime: syscalls, allocator, print!, argv, threads, futex Mutex, panic handler
rusthello/ Smoke test (rusthello, rusthello panic, rusthello panic-thread)

The GCC driver links crt1/crti/crtbegin, the libc and libgcc from toolchain/sysroot, the same as ports. After changing programs/lib/libc, re-run toolchain/build-montauk-toolchain.sh so Rust programs pick it up.

Syscall numbers and status codes are generated at build time by montauk-rt/build.rs from programs/include/Api/Syscall.hpp and kernel/src/Common/StatusCodes.hpp, so there is nothing to keep in sync by hand.

Writing a program

#![no_std]
#![no_main]
extern crate alloc;

montauk_rt::entry!(main);

fn main() -> i32 {
    montauk_rt::println!("hello from Rust");
    0
}

Limits (Phase 1)

  • No std. No std::fs, std::net, std::process or std::thread; use montauk_rt equivalents where they exist.
  • panic = "abort". A panic on any thread prints the message and kills the whole process.
  • Thread stacks are owned by the JoinHandle. An unjoined thread leaks its stack.

Phase 2 (a forked rustc at ~/dev/mtk/rust with a native target_os = "montauk" std) replaces the JSON spec with a built-in target.