Hi, I am trying to embed wasmtime (using the C API currently) and wonder how to best copy data out from linear memory. Let's say the WebAssembly calls a host function with a pointer into linear data and a length. How to safely copy that data from linear memory to the host?
Host probably has access to the instance's Memory
. You can find data_unchecked()
slice there https://docs.rs/wasmtime/0.19.0/wasmtime/struct.Memory.html#method.data_unchecked
So there is a single Memory object for data + stack + heap?
/me does not understand the question above as it is stated
Instance normally has (created or imported) memory. How wasm code is using it, depends on the compiler to wasm target.
Wasm call stack is not exposed, but can be traced via Trap
structure
Maybe it is me who is not understanding WASM but my understanding was that WASM has a memory section and a data section and that both of these will reside in linear memory. Are both of those located in the same Memory object?
yeah, during instantiation engine constructs Memory based on memory and data sections.
Gotcha. And stack is separate and not meant to be accessible to the host? At least not for passing data from wasmtime to host functions.
now define "stack", is it wasm call stack or "shadow" stack that was simulated by C or Rust compiler
I think what I am talking about is the shadow stack. The one where the webassembly code could allocate values on, not the part used for tracking return addresses and restoring registers when doing function calls.
okay, so if you have wasm "pointer" at the host, you can slice that from Memory's data_unchecked()
Thanks, I need to check it out. The reason i was confused is because I saw things like "(global $__heap_base (export "__heap_base") i32 (i32.const 1049080))" in code compiled by rustc making me think that the linear memory must be non-contiguous due to the big distance from zero while the Memory documentation pages says Memory objects are contiguous.
Actually, I think you are not wrong in terms of distance 0x1001F8. Look at (memory) min limit.
it shall be > 0x10
means, the instance reserves that much memory
From the wasm:
(memory $memory (export "memory") 17)
(global $g0 (mut i32) (i32.const 1048576))
(global $__data_end (export "__data_end") i32 (i32.const 1049080))
(global $__heap_base (export "__heap_base") i32 (i32.const 1049080))
(elem $e0 (i32.const 1) func $_ZN3std5alloc24default_alloc_error_hook17hcb82c7fe7df69521E)
(data $d0 (i32.const 1048576) "aaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"))
yep 17 * 65536 = 0x110000
rest of the memory probably goes to shadow stack
(global $g0 (mut i32) (i32.const 1048576))
<-- it starts from high address = 0x100000
Aha! That makes a lot of sense. So Rust allocates 17 pages for shadow stack? Not that much memory but enough that I need to be careful about it.
16 pages, last page for data (segment)
I think linker options allow to make it less (I cannot find it, but hope it is there :)
Thanks again. This made things a lot clearer for me.
Last updated: Dec 23 2024 at 13:07 UTC