I'm instantiating a module. I need it to export a string and read that string from wasmtime. This is a testing scenario, so I don't want to resort to a full witx/wit approach. What is the simplest way to do this?
Compile time fixed or dynamic string?
Compile time.
You should be able to export pointer (offset) and length ints and read it from linear memory in wasmtime
Something like:
#[no_mangle]
pub static STRING: &'static str = "foo";
Yeah, that's what I expected too. But I haven't been able to figure out the exact invocation for that.
You could make that work, though afaik the layout of str
isn't stable
Yup. I know.
The moment I try to do that, module instantiation fails with:
command export 'STRING' is not a function
I think you'd need to export STRING.as_ptr()
(as usize
?) and STRING.len()
both are const fn
Same error with an i32
.
It seems like wasmtime really doesn't like anything compiled for wasm32-wasi
that exports anything that isn't a function.
My next attempt was:
#[no_mangle]
pub fn string() -> &'static str {
"foo"
}
... which linked and returned a function of:
FuncType { sig: WasmFuncType { params: [I32], externref_params_count: 0, returns: [], externref_returns_count: 0 } }
So it is obviously wanting me to provide a pointer to memory as input to store the fat pointer in.
But I'm not sure how it is possible to expose host memory directly to the guest like that.
Attempting to return (*const u8, usize)
produces the same signature.
I think it wants me to pass in a pointer to 16 bytes of memory. But I don't know how.
Val::null()
produces an externref
rather than an i32
.
So the function signatures don't match.
In general, that requires exporting a malloc
-like function from your wasm, so the host can allocate _guest_ memory. But I think there should be another way to do what you want... I'm not sure exactly what it is though.
Can you pub static STRING_PTR: *const u8 = STRING.as_ptr();
?
(nope)
Yeah, nope.
Statics require Sync
.
I guess it makes sense - static location isn't known until link time
You could write the pointer to a mutable static in an init function
That sounds horrible. :)
const STRING: &'static str = "Hello, world!";
#[no_mangle]
pub fn string() -> *const u8 {
STRING.as_ptr()
}
#[no_mangle]
pub fn length() -> usize {
STRING.len()
}
Or use two separate pub functions for ptr and len; I don't know if multi-value return is implemented in rust (yet?)
The above produces two functions with:
FuncType { sig: WasmFuncType { params: [], externref_params_count: 0, returns: [I32], externref_returns_count: 0 } }
Which means I can at least get the value out now.
https://github.com/rust-lang/rust/issues/73755#issuecomment-650252985
But I still don't know what to do with that integer.
Since I'm not sure which APIs to call to get raw access to guest memory.
https://docs.rs/wasmtime/2.0.2/wasmtime/struct.Instance.html#method.get_memory
I forget what the default memory name is...
"memory"
, typically
Linker::get("memory")
returns None
.
But the wat
says it is exported.
@Alex Crichton @Dan Gohman ^
If it's exported in wat
, I'm not sure offhand why it wouldn't show up in Linker::get("memory")
you probably need to use Instance::get
instead of Linker::get
Linker::get
is only used for items defined into the linker, and if you're just instantiating through the linker that doesn't instantiate more things into the linker
@Alex Crichton What is the right way to manually instantiate and call the start function?
Instance
construction runs the start function
yes presence of an Instance
means the wasm start
function was run
Unless you mean the _start
function, which - confusingly - is unrelated
(i.e. an "old"-style WASI command)
Wohoo! I managed to get an instance of a global!
That feels like real progress.
@Alex Crichton How do I translate the raw i32 result (which is obviously a pointer of some kind) into an offset into the exported memory?
The result of the exported global is 1048616
and the size of the exported memory is 1114112
.
So that seems sane. But the value isn't at that offset.
It should be - wasm guest pointers are offsets into their linear memory
yes it should be an offset into linear memory, if it isn't I don't know what it is
I think it is a rust &str
layout issue. The exported value points to just past the end of the string.
#[no_mangle]
pub static CONFIG: &'static str = "Hello, world!\0";
The value of CONFIG
as seen by wasmtime is 1048616
, but the string actually starts at 1048600
.
That's because CONFIG
, as a pointer is &&'static str
, you'd need to instead to static CONFIG: [u8; N] = *b"..."
if you want the raw addrss
Ah, right.
or alternatively you should be able to read the I32 that represents the &&str
, and then find the string at that address, right?
@Jamey Sharp That's the approach I took.
@Alex Crichton Since exploring this yesterday, I began thinking that a custom section might be more idiomatic. What is the status of custom section support? https://github.com/rust-lang/rust/pull/48883 was merged but I'm currently seeing cannot find attribute
on nightly.
It's implemented in rustc and hasn't changed since, not sure why you'd get a cannot find attribute error
@Alex Crichton Ah, vscode/analyzer was trying to build it for the host arch.
Last updated: Dec 23 2024 at 13:07 UTC