You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

WebAssembly中load与store的使用及内存管理方法问询

Understanding load and store for WebAssembly Memory in WAT

Great question! It’s true that most Wasm examples rely on C/C++ compiles, so diving into raw WAT for memory operations is a fantastic way to grasp how Wasm works under the hood. Let’s break this down step by step with practical, hands-on examples.

First: Declare and Export Memory

Before you can read or write memory, you need to define a memory instance in your WAT module. Wasm memory is split into "pages" (each 64KB), and you’ll need to set an initial size (required) and can optionally set a maximum size. Exporting the memory lets external code (like JavaScript) interact with it too.

Here’s how to add memory to your module:

(module
  ; Define memory: 1 initial page (64KB), no max limit specified
  (memory 1)
  ; Export the memory so external code can access it
  (export "memory" (memory 0))
)

Using store to Write to Memory

The store family of instructions writes values from the Wasm stack into a specific memory address. For 32-bit integers, we use i32.store—it pulls two values from the stack: first the target memory address (byte offset), then the value to store.

Let’s add a function that stores an i32 at a user-specified address:

(func (export "store_i32") (param $addr i32) (param $value i32)
  get_local $addr   ; Push the target address onto the stack
  get_local $value  ; Push the value we want to store onto the stack
  i32.store         ; Write the value to the address (stack pops both values)
)

Key Notes for store:

  • Memory addresses are byte offsets. Since an i32 takes 4 bytes, consecutive i32 values should be stored at addresses spaced by 4 (e.g., 0, 4, 8) to avoid overlapping data.
  • For smaller data types, use specialized instructions:
    • i32.store8: Write only the lowest 8 bits of an i32 to a single byte (no 4-byte alignment required)
    • i32.store16: Write the lowest 16 bits to two bytes

Using load to Read from Memory

The load family does the opposite: it reads a value from a memory address and pushes it onto the Wasm stack. For i32 values, use i32.load.

Here’s a function to read an i32 from a specified address:

(func (export "load_i32") (param $addr i32) (result i32)
  get_local $addr  ; Push the address we want to read from onto the stack
  i32.load         ; Read 4 bytes from the address, push the resulting i32 to the stack
)

Key Notes for load:

  • Like store, specialized instructions exist for smaller types:
    • i32.load8_u: Read 1 byte as an unsigned 32-bit integer
    • i32.load8_s: Read 1 byte as a signed 32-bit integer
    • i32.load16_u/i32.load16_s: Read 2 bytes as unsigned/signed values
  • Wasm uses little-endian byte order for multi-byte values (matching x86 systems).

Combining with Global Variables

You can use global variables to track base addresses for your data (so you don’t have to hardcode offsets everywhere). Let’s update our module to include a global base address for organized storage:

(module
  (memory 1)
  (export "memory" (memory 0))

  ; Global variable: base address for our data (start at 16 to avoid reserved memory)
  (global $data_base i32 (i32.const 16))

  ; Store a value directly at the base address
  (func (export "store_to_base") (param $value i32)
    get_global $data_base
    get_local $value
    i32.store
  )

  ; Load a value directly from the base address
  (func (export "load_from_base") (result i32)
    get_global $data_base
    i32.load
  )
)

Full Working Example

Here’s a complete WAT module wrapping all these concepts together. Save it as memory_demo.wat, then compile it with wat2wasm memory_demo.wat -o memory_demo.wasm:

(module
  (memory 1)
  (export "memory" (memory 0))

  (global $data_base i32 (i32.const 16))

  (func (export "store_i32") (param $addr i32) (param $value i32)
    get_local $addr
    get_local $value
    i32.store)

  (func (export "load_i32") (param $addr i32) (result i32)
    get_local $addr
    i32.load)

  (func (export "store_to_base") (param $value i32)
    get_global $data_base
    get_local $value
    i32.store)

  (func (export "load_from_base") (result i32)
    get_global $data_base
    i32.load)

  (func (export "store_u8") (param $addr i32) (param $value i32)
    get_local $addr
    get_local $value
    i32.store8)

  (func (export "load_u8") (param $addr i32) (result i32)
    get_local $addr
    i32.load8_u)
)

Quick JS Interaction (Bonus)

If you want to test this module in JavaScript, here’s a snippet to call the exported functions and even directly access the memory buffer:

async function runMemoryDemo() {
  const wasmModule = await WebAssembly.instantiateStreaming(fetch('memory_demo.wasm'));
  const { memory, store_i32, load_i32, store_to_base, load_from_base } = wasmModule.instance.exports;

  // Store 42 at address 20, then read it back
  store_i32(20, 42);
  console.log(load_i32(20)); // Logs: 42

  // Store 123 at the global base address, then read it back
  store_to_base(123);
  console.log(load_from_base()); // Logs: 123

  // Directly access memory via a Uint32Array view
  const memoryView = new Uint32Array(memory.buffer);
  console.log(memoryView[5]); // Address 20 = 5 * 4 bytes, logs: 42
}
runMemoryDemo();

内容的提问来源于stack exchange,提问作者Lance Pollard

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.26 07:05:35