Compiling simple wasm program includes `memory` section in the compiled file

Hei there! I am currently trying to run wasm on embedded devices, therefore memory constraints are quite a thing. When I compile the following rust code:

extern "C" {
    pub fn read();
}

#[no_mangle]
pub fn start() {
    unsafe { read(); }
}

using the latest stable compiler (1.55) to the target wasm32-unknown-unkown, the resulting wasm module looks like this:

(module
  (type $t0 (func))
  (import "env" "read" (func $read (type $t0)))
  (func $start (export "start") (type $t0)
    (call $read)
    (return))
  (table $T0 1 1 funcref)
  (memory $memory (export "memory") 16)
  (global $g0 (mut i32) (i32.const 1048576))
  (global $__data_end (export "__data_end") i32 (i32.const 1048576))
  (global $__heap_base (export "__heap_base") i32 (i32.const 1048576)))

What I don't understand in the output is the memory section, that is initialized with 16(!) pages, each 64kB big. Is this my fault or why does the compiler add the section?

I think this represents the stack.

1 Like

Ahh I See, but if I delete the memory section and run it inside a runtime (in my case wasmi), I don't get any error as wasmi allocates it's own stack when a program starts.

Do you know if I could have an influence on the size of it (if it's the stack)?

Your host functions will use that memory export for accessing anything inside the WebAssembly module's address space - so that includes the heap, static variables, or values on the stack. I don't think the stack is allocated separately because whenever I've written host functions I've been able to read values using the same export regardless of whether the value lives on the stack or the heap.

I'm not sure where the number 16 comes from (16 pages = 16 * 64kb = 1024 kb), though.

I am almost certainly sure that wasmi allocates on it's own, but I will have a look. I am also using their StackRecycler in order to keep a lower memory footprint.

Looking at the number 16 there I'm quite sure this is the page number, quoting MDN:

The 1 (in (memory 1) ) indicates that the imported memory must have at least 1 page of memory (WebAssembly defines a page to be 64KB.)

1 Like

That is a different stack. There are two stacks:

  • The wasm stack. Instructions can only push and pop. Statically checked that every instruction manipulates it correctly. (right types, no stack underflow, ...)
  • The stack in the linear memory. This one is used when the address of a value on the stack needs to be taken or if the value is larger than a single wasm primitive value as stored on the wasm stack. This one needs the memory section.
1 Like

Ah I See, thanks a lot for the explanation! I found out where rust sets this big stack: rust/wasm_base.rs at a16f686e4a0ea15dcd3b5aa3db7b1cba27bb9453 · rust-lang/rust · GitHub. I managed to reduce it to fit my target via rustflags = ["-C", "link-args=-z stack-size=64000"].