<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://johnwick.cc/index.php?action=history&amp;feed=atom&amp;title=How_Rust_Targets_WebAssembly%3A_Inside_the_wasm32_Backend</id>
	<title>How Rust Targets WebAssembly: Inside the wasm32 Backend - Revision history</title>
	<link rel="self" type="application/atom+xml" href="https://johnwick.cc/index.php?action=history&amp;feed=atom&amp;title=How_Rust_Targets_WebAssembly%3A_Inside_the_wasm32_Backend"/>
	<link rel="alternate" type="text/html" href="https://johnwick.cc/index.php?title=How_Rust_Targets_WebAssembly:_Inside_the_wasm32_Backend&amp;action=history"/>
	<updated>2026-05-06T17:55:54Z</updated>
	<subtitle>Revision history for this page on the wiki</subtitle>
	<generator>MediaWiki 1.44.1</generator>
	<entry>
		<id>https://johnwick.cc/index.php?title=How_Rust_Targets_WebAssembly:_Inside_the_wasm32_Backend&amp;diff=102&amp;oldid=prev</id>
		<title>PC: Created page with &quot;You’ve probably seen it before: “Compile Rust to WebAssembly and run it in the browser.”  Sounds magical, right? You cargo build --target wasm32-unknown-unknown, and suddenly your Rust code is running inside Chrome’s JavaScript engine. But what really happens between those two steps?  How does Rust — a systems language that talks directly to hardware — suddenly become a safe sandboxed bytecode that the browser can execute? Let’s lift the curtain. ...&quot;</title>
		<link rel="alternate" type="text/html" href="https://johnwick.cc/index.php?title=How_Rust_Targets_WebAssembly:_Inside_the_wasm32_Backend&amp;diff=102&amp;oldid=prev"/>
		<updated>2025-11-15T16:42:02Z</updated>

		<summary type="html">&lt;p&gt;Created page with &amp;quot;You’ve probably seen it before: “Compile Rust to WebAssembly and run it in the browser.”  Sounds magical, right? You cargo build --target wasm32-unknown-unknown, and suddenly your Rust code is running inside Chrome’s JavaScript engine. But what really happens between those two steps?  How does Rust — a systems language that talks directly to hardware — suddenly become a safe sandboxed bytecode that the browser can execute? Let’s lift the curtain. ...&amp;quot;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;New page&lt;/b&gt;&lt;/p&gt;&lt;div&gt;You’ve probably seen it before:&lt;br /&gt;
“Compile Rust to WebAssembly and run it in the browser.”&lt;br /&gt;
&lt;br /&gt;
Sounds magical, right? You cargo build --target wasm32-unknown-unknown, and suddenly your Rust code is running inside Chrome’s JavaScript engine.&lt;br /&gt;
But what really happens between those two steps? &lt;br /&gt;
How does Rust — a systems language that talks directly to hardware — suddenly become a safe sandboxed bytecode that the browser can execute?&lt;br /&gt;
Let’s lift the curtain. &lt;br /&gt;
We’re going deep into how Rust targets WebAssembly, what actually happens in the wasm32 backend, and why it’s one of the most underrated feats of compiler engineering in modern programming.&lt;br /&gt;
&lt;br /&gt;
The Emotional Truth: Rust and WebAssembly Were Made for Each Other&lt;br /&gt;
&lt;br /&gt;
When Rust and WebAssembly first met, it wasn’t love at first sight. &lt;br /&gt;
Rust was designed for low-level systems work — drivers, kernels, embedded systems. WebAssembly (WASM) was designed for high-level, portable execution in browsers.&lt;br /&gt;
&lt;br /&gt;
But then developers realized:&lt;br /&gt;
“Wait, WASM gives me a safe sandbox and zero-cost abstractions. Rust gives me memory safety and zero-cost abstractions. They speak the same language!”&lt;br /&gt;
&lt;br /&gt;
That synergy turned Rust into the number-one language for serious WebAssembly projects — from Figma’s rendering engine to Cloudflare Workers.&lt;br /&gt;
And at the heart of it all lies the wasm32 backend — a quiet piece of compiler machinery that turns your .rs files into .wasm binaries.&lt;br /&gt;
&lt;br /&gt;
Step 1: The Target Triple — wasm32-unknown-unknown&lt;br /&gt;
When you tell Rust to compile for WebAssembly, you’re invoking this target:&lt;br /&gt;
cargo build --target wasm32-unknown-unknown&lt;br /&gt;
&lt;br /&gt;
This triple means:&lt;br /&gt;
&lt;br /&gt;
| Part      | Meaning                                  |&lt;br /&gt;
| --------- | ---------------------------------------- |&lt;br /&gt;
| `wasm32`  | 32-bit WebAssembly architecture          |&lt;br /&gt;
| `unknown` | No OS — just the WebAssembly environment |&lt;br /&gt;
| `unknown` | No vendor — completely generic           |&lt;br /&gt;
&lt;br /&gt;
Rust has several other WASM targets too:&lt;br /&gt;
&lt;br /&gt;
| Target                      | Description                                                   |&lt;br /&gt;
| --------------------------- | ------------------------------------------------------------- |&lt;br /&gt;
| `wasm32-unknown-unknown`    | Bare-metal WASM (no std, pure core)                           |&lt;br /&gt;
| `wasm32-wasi`               | WASI (WebAssembly System Interface — like a fake OS for WASM) |&lt;br /&gt;
| `wasm32-unknown-emscripten` | Legacy target for Emscripten toolchain                        |&lt;br /&gt;
&lt;br /&gt;
When you use wasm32-unknown-unknown, you’re basically telling the compiler:&lt;br /&gt;
“Forget the operating system. Just emit raw WebAssembly instructions.”&lt;br /&gt;
&lt;br /&gt;
Step 2: The Compilation Pipeline — From Rust to WASM Bytecode&lt;br /&gt;
The magic happens in the backend pipeline. Here’s a high-level diagram of how your Rust code flows through the system:&lt;br /&gt;
&lt;br /&gt;
      ┌──────────────────────────────┐&lt;br /&gt;
      │      Rust Source (.rs)       │&lt;br /&gt;
      └──────────────┬───────────────┘&lt;br /&gt;
                     │&lt;br /&gt;
                     ▼&lt;br /&gt;
          ┌──────────────────────┐&lt;br /&gt;
          │   HIR / MIR (IRs)   │&lt;br /&gt;
          └──────────┬───────────┘&lt;br /&gt;
                     │&lt;br /&gt;
                     ▼&lt;br /&gt;
        ┌───────────────────────────┐&lt;br /&gt;
        │  LLVM (wasm32 backend)    │&lt;br /&gt;
        └──────────┬────────────────┘&lt;br /&gt;
                   │&lt;br /&gt;
                   ▼&lt;br /&gt;
        ┌───────────────────────────┐&lt;br /&gt;
        │   WebAssembly (.wasm)     │&lt;br /&gt;
        └───────────────────────────┘&lt;br /&gt;
&lt;br /&gt;
Let’s break down those phases.&lt;br /&gt;
&lt;br /&gt;
1. MIR — Rust’s Middle Intermediate Representation&lt;br /&gt;
After parsing and type checking, Rust converts your functions into MIR (Mid-level IR) — a simpler, SSA-like version of your code that’s independent of platform.&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
fn add(a: i32, b: i32) -&amp;gt; i32 {&lt;br /&gt;
    a + b&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
MIR (simplified):&lt;br /&gt;
bb0: {&lt;br /&gt;
    _0 = Add(a, b);&lt;br /&gt;
    return;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
This step is pure Rust logic. Nothing platform-specific happens yet.&lt;br /&gt;
&lt;br /&gt;
2. LLVM IR — The Universal Layer&lt;br /&gt;
Next, MIR is lowered to LLVM IR — the universal language that all Rust targets share.&lt;br /&gt;
LLVM is what actually knows how to generate machine code for various targets, including x86_64, ARM, and… WebAssembly.&lt;br /&gt;
Example (LLVM IR):&lt;br /&gt;
&lt;br /&gt;
define i32 @add(i32 %a, i32 %b) {&lt;br /&gt;
entry:&lt;br /&gt;
  %sum = add i32 %a, %b&lt;br /&gt;
  ret i32 %sum&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
This is what the Rust compiler sends to LLVM’s wasm32 backend.&lt;br /&gt;
&lt;br /&gt;
3. wasm32 Backend in LLVM&lt;br /&gt;
Here’s the star of the show. LLVM’s wasm32 backend transforms the generic IR into WebAssembly bytecode.&lt;br /&gt;
It’s not trivial — because WebAssembly is a stack machine, not a register machine like x86.&lt;br /&gt;
&lt;br /&gt;
Let’s see the same add function in WebAssembly Text Format (WAT):&lt;br /&gt;
(func $add (param $a i32) (param $b i32) (result i32)&lt;br /&gt;
  local.get $a&lt;br /&gt;
  local.get $b&lt;br /&gt;
  i32.add)&lt;br /&gt;
&lt;br /&gt;
Notice what’s different?&lt;br /&gt;
* 		There are no registers, only a stack.&lt;br /&gt;
* 		Each instruction pushes/pops values.&lt;br /&gt;
* 		Control flow is explicit (if, block, loop).&lt;br /&gt;
&lt;br /&gt;
LLVM’s wasm32 backend rewrites SSA-style code into this stack-based format, optimizing along the way (constant folding, dead code elimination, etc.).&lt;br /&gt;
&lt;br /&gt;
Step 3: Linking and Exporting&lt;br /&gt;
When you build a Rust → WASM binary, Cargo uses wasm-ld (the WebAssembly linker).&lt;br /&gt;
&lt;br /&gt;
It strips away all unnecessary runtime parts, leaving only the exported functions.&lt;br /&gt;
Example:&lt;br /&gt;
#[no_mangle]&lt;br /&gt;
pub extern &amp;quot;C&amp;quot; fn greet() {&lt;br /&gt;
    println!(&amp;quot;Hello from Rust!&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Run:&lt;br /&gt;
cargo build --target wasm32-unknown-unknown --release&lt;br /&gt;
&lt;br /&gt;
Output:&lt;br /&gt;
target/wasm32-unknown-unknown/release/your_app.wasm&lt;br /&gt;
&lt;br /&gt;
To call this from JavaScript:&lt;br /&gt;
import init, { greet } from &amp;#039;./your_app.js&amp;#039;;&lt;br /&gt;
&lt;br /&gt;
init().then(() =&amp;gt; {&lt;br /&gt;
  greet();&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
Under the hood, the WASM binary exposes a function named greet that JavaScript can import.&lt;br /&gt;
&lt;br /&gt;
Step 4: Memory and the WebAssembly Sandbox&lt;br /&gt;
Here’s where things get emotional for systems developers. &lt;br /&gt;
You don’t get malloc. You don’t get threads. You get one linear memory — a single contiguous array of bytes.&lt;br /&gt;
&lt;br /&gt;
Rust’s allocator (when using wasm-bindgen or wee_alloc) manages that memory manually.&lt;br /&gt;
&lt;br /&gt;
Example (simplified):&lt;br /&gt;
static mut MEMORY: [u8; 65536] = [0; 65536]; // 64KB&lt;br /&gt;
&lt;br /&gt;
#[no_mangle]&lt;br /&gt;
pub extern &amp;quot;C&amp;quot; fn alloc(size: usize) -&amp;gt; *mut u8 {&lt;br /&gt;
    // Return a pointer into our linear memory&lt;br /&gt;
    unsafe { MEMORY.as_mut_ptr() }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Of course, the real allocator is far smarter — but conceptually, this is what happens. Every pointer in Rust maps to an offset inside WebAssembly’s linear memory.&lt;br /&gt;
&lt;br /&gt;
Step 5: Host Bindings (wasm-bindgen)&lt;br /&gt;
WASM by itself can’t print, open files, or use DOM APIs — it’s isolated. That’s where wasm-bindgen comes in: it bridges Rust and JavaScript.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
use wasm_bindgen::prelude::*;&lt;br /&gt;
&lt;br /&gt;
#[wasm_bindgen]&lt;br /&gt;
pub fn greet(name: &amp;amp;str) {&lt;br /&gt;
    web_sys::console::log_1(&amp;amp;format!(&amp;quot;Hello, {}!&amp;quot;, name).into());&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Now you can call this directly from JS:&lt;br /&gt;
import { greet } from &amp;#039;./pkg/hello.js&amp;#039;;&lt;br /&gt;
greet(&amp;quot;World&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
Under the hood, wasm-bindgen generates the glue code to pass strings, memory pointers, and function calls across the WASM-JS boundary.&lt;br /&gt;
Architecture of Rust → WebAssembly Toolchain&lt;br /&gt;
&lt;br /&gt;
┌────────────────────────────┐&lt;br /&gt;
 │       Rust Source          │&lt;br /&gt;
 └──────────────┬─────────────┘&lt;br /&gt;
                ▼&lt;br /&gt;
      ┌──────────────────────┐&lt;br /&gt;
      │      rustc Frontend  │&lt;br /&gt;
      │  (Parse, MIR, LLVM)  │&lt;br /&gt;
      └──────────┬───────────┘&lt;br /&gt;
                 ▼&lt;br /&gt;
        ┌──────────────────────┐&lt;br /&gt;
        │   LLVM wasm32 Backend│&lt;br /&gt;
        └──────────┬───────────┘&lt;br /&gt;
                   ▼&lt;br /&gt;
        ┌──────────────────────┐&lt;br /&gt;
        │   wasm-ld Linker     │&lt;br /&gt;
        └──────────┬───────────┘&lt;br /&gt;
                   ▼&lt;br /&gt;
        ┌──────────────────────┐&lt;br /&gt;
        │  .wasm Binary Output │&lt;br /&gt;
        └──────────────────────┘&lt;br /&gt;
&lt;br /&gt;
Why Rust Compiles So Well to WASM&lt;br /&gt;
Here’s the real reason Rust became the language of choice for WebAssembly:&lt;br /&gt;
&lt;br /&gt;
| Rust Feature                | WebAssembly Benefit              |&lt;br /&gt;
| --------------------------- | -------------------------------- |&lt;br /&gt;
| No runtime GC               | Small binary size                |&lt;br /&gt;
| Deterministic memory layout | Easy linear memory mapping       |&lt;br /&gt;
| Strict ownership model      | Safe across the sandbox boundary |&lt;br /&gt;
| LLVM backend                | Reuses mature wasm32 codegen     |&lt;br /&gt;
| Zero-cost abstractions      | Near-native speed                |&lt;br /&gt;
&lt;br /&gt;
Rust doesn’t need a garbage collector or JIT like JavaScript. It compiles straight to linear memory operations, meaning your WASM modules can run almost as fast as native code.&lt;br /&gt;
&lt;br /&gt;
Real-World Example: Figma’s Rendering Engine&lt;br /&gt;
Figma uses Rust compiled to WASM to handle its vector math and rendering logic.&lt;br /&gt;
&lt;br /&gt;
Why? Because JavaScript couldn’t keep up with 60 FPS transforms and zooms.&lt;br /&gt;
Rust’s predictable performance and WASM’s portability meant the same rendering core could run in the browser and on the desktop — identical logic, shared codebase.&lt;br /&gt;
&lt;br /&gt;
That’s the true power of wasm32.&lt;br /&gt;
What’s Next for Rust + WASM&lt;br /&gt;
&lt;br /&gt;
The ecosystem is evolving fast:&lt;br /&gt;
* 		WASI adds system calls (files, sockets) to WASM, making it a real OS target.&lt;br /&gt;
* 		Component Model aims to make WASM modules interoperable between languages.&lt;br /&gt;
* 		Async and threading are coming to WASM 2.0.&lt;br /&gt;
&lt;br /&gt;
Rust’s compiler team is already aligning its backend with these new features — especially multi-memory and interface types.&lt;br /&gt;
We’re heading toward a world where you can build entire applications in Rust, deploy them on the web, and never write a line of JS glue again.&lt;br /&gt;
&lt;br /&gt;
Key Takeaways&lt;br /&gt;
&lt;br /&gt;
| Concept         | Description                                          |&lt;br /&gt;
| --------------- | ---------------------------------------------------- |&lt;br /&gt;
| `wasm32` Target | The WebAssembly backend for Rust                     |&lt;br /&gt;
| LLVM            | Translates Rust IR to stack-based WASM bytecode      |&lt;br /&gt;
| Linear Memory   | A single contiguous memory block for all allocations |&lt;br /&gt;
| wasm-bindgen    | Bridges Rust functions to JS and the browser         |&lt;br /&gt;
| WASI            | Expands WASM beyond browsers into servers and CLIs   |&lt;br /&gt;
&lt;br /&gt;
Final Thoughts&lt;br /&gt;
The wasm32 backend is one of Rust’s quiet triumphs. It takes a language built for bare metal and retargets it to a virtual machine sandbox — without losing performance, safety, or soul.&lt;br /&gt;
&lt;br /&gt;
Rust didn’t just adapt to WebAssembly; it elevated it. Every time you see a silky-smooth Rust-powered Web app, remember that under the hood, the compiler is performing a delicate dance — translating ownership, safety, and lifetimes into stack operations and bytes.&lt;br /&gt;
&lt;br /&gt;
Rust and WebAssembly aren’t just compatible — they’re spiritually aligned.&lt;/div&gt;</summary>
		<author><name>PC</name></author>
	</entry>
</feed>