I have a compiled .wasm
file which does not use memory. I am trying to run it using wasmtime
. It seems wasmtime
needs the .wasm
file to export memory.
The .wasm
file is a simple file which just exits with a specific non-zero exit code. On executing it with wasmtime
, I currently face the following:
$ wasmtime tmp
Error: failed to run main module `tmp`
Caused by:
0: failed to invoke command default
1: error while executing at wasm backtrace:
0: 0xa7 - <unknown>!<wasm function 1>
1: 0xce - <unknown>!<wasm function 3>
2: 0xb4 - <unknown>!<wasm function 2>
3: 0xda - <unknown>!<wasm function 4>
2: missing required memory export
Please, could someone possibly share if there is any flag in wasmtime
that allows executing without memory export? Also, does wasmtime
allow/support memory import in .wasm
file?
Some doubts:
.wasm
files that wasmtime
expects? C/C++
code with emscripten
, I found the following functions exported in the generated .wasm
file (export "__wasm_call_ctors" (func 0))
(export "main" (func 3))
(export "__indirect_function_table" (table 0))
(export "__errno_location" (func 21))
(export "fflush" (func 20))
(export "emscripten_stack_init" (func 10))
(export "emscripten_stack_get_free" (func 11))
(export "emscripten_stack_get_base" (func 12))
(export "emscripten_stack_get_end" (func 13))
(export "stackSave" (func 6))
(export "stackRestore" (func 7))
(export "stackAlloc" (func 8))
(export "emscripten_stack_get_current" (func 9)))
Please, could someone possibly share what these functions do and/or where I could find information about the working of these functions?
I would be really grateful for any help on the above. Thank you.
emscripten targets the Web and relies on its generated JS to fulfil all its imports and manage its exports. it isn't really going to work in non-Web environments.
if you are trying to target wasmtime, you'd be better served by wasi-sdk: https://github.com/WebAssembly/wasi-sdk
For 1. The wasmtime cli expects a wasi module. The wasi specification requires a memory to be exported. If you want to use a non-wasi wasm module you will have to use wasmtime as library and manually expose whichever interface you want to the wasm module.
Thank you so much for the clarification! This is very helpful!
Using wasi
, how can one print an integer or float to screen? There is fd_write
in the wasi
api documentation, but it seems it is only for printing strings. I attempted to store an integer in memory and then print it using fd_write
as follows:
(func $main (export "_start")
(i32.store (i32.const 12) (i32.const 26)) ;; store the number
;; iov vector
(i32.store (i32.const 4) (i32.const 12))
(i32.store (i32.const 8) (i32.const 4))
(call $fd_write
(i32.const 1) ;; 1 for stdout
(i32.const 4) ;; *iovs
(i32.const 1) ;; iovs_len
(i32.const 0) ;; nwritten
)
drop
)
It does not print any output. Printing an integer by storing it directly in memory using (data (i32.const 12) "26")
works (because we are just printing it as string), but by storing it as (i32.store (i32.const 12) (i32.const 26))
does not work. Please, could someone possibly share what I might be missing and/or how to print integers/float to stdout using wasi
?
There is no WASI-level support for formatted output of numbers. Typically programs would link with a source language's standard library, which would implement this in wasm, such as format!(...)
in Rust or printf
in C or other things in other languages.
I'm attempting to write some basic memory-logic to be able to pass strings to a wasm module, following this article.
It appears however that the wasmtime api have changed a bit since, and functions that return values no seem to require get_typed_func::<Params, Returns>()
(which is great btw). What I don't understand is how to type guest functions that return a raw pointer to memory, and what difference it does if I use a i32
or u32
etc. for that.
Given this function defined in rust and compiled to wasm:
#[no_mangle]
pub extern "C" fn alloc(len: usize) -> *mut u8 {
let mut buf = Vec::with_capacity(len);
let ptr = buf.as_mut_ptr();
std::mem::forget(buf);
return ptr;
}
how do I type that on the hose side?
let alloc = instance.get_typed_func::<??, ??>(&mut store, "alloc")?;
For wasm32 you did use a 32bit int and for wasm64 a 64bit int. Using an unsigned integer makes most sense.
By the way have you seen wit-bindgen? It takes care of a lot of work to pass higher level types like structs and arrays between the host and wasm.
Last updated: Dec 23 2024 at 14:03 UTC