Konubinix' opinionated web of thoughts

Rust to Machine Code


Rust currently allocates on to the stack at the beginning of a function call and deallocates stack memory at the end of a function call.


If you want to see the asm of your project, you can use this cargo command

  • cargo rustc – –emit asm
  • cargo rustc –release – –emit asm

and the asm will be in these files (where crate_name is the name of your crate) target/debug/deps/crate_name.s target/release/deps/crate_name.s


You can take a small Rust program and trace its journey through the compiler.

The first step is parsing. We can ask rustc to stop after parsing and just pretty-print the code:

$ rustc –pretty normal foo.rs fn main() { println!(“Hello, world!”); }

The next step is expansion of macros and syntax extensions. You can see the result with

$ rustc –pretty expanded foo.rs

This contains some libstd imports that were implicit in the source. Also the println! macro has expanded to a dozen lines of code. The result is 23 lines in total.

Now the code is ready for typechecking. rustc infers a type for every expression, then checks that they all make sense together. You can see the inferred types with

$ rustc –pretty typed foo.rs

That’s 38 lines. Next we can look at the LLVM code produced by the compiler:

$ rustc –emit ir foo.rs && cat foo.ll

107 lines. As others pointed out, the “VM” name is misleading. This is a SSA intermediate representation like you might find in any traditional compiler. It looks a bit like assembly code for a hypothetical machine that has an infinite number of registers. LLVM itself, the C++ library, is responsible for turning this into assembly for an actual machine. You can see the result with

$ rustc –emit asm foo.rs && cat foo.s

111 lines. LLVM is an extremely impressive piece of software. It contains about 2 million lines of code, developed by hundreds of people over a decade. Rust performance utterly depends on LLVM’s optimization passes, which can rip through the abstractions used in idiomatic Rust code and produce machine code equivalent to what you’d get from C. Compared to LLVM, Rust is a tiny project; it’s really fantastic that we get to use all of this machinery developed by others. If you run the above commands with –opt-level 3, you’ll see that rustc itself doesn’t perform much in the way of optimization; it’s all LLVM.

There are a ton of steps I left out of this description. You can give the flag -Z time-passes to rustc and it will print a full list of what it’s doing