You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
I've been experimenting with using Rust based WASM modules as scripts in my game. One of the frustrations with that is the lack of getrandom and thus rand in the WASM guest environment. In WASM on the web or as a WASI executable there are existing tools to solve that problem but hosting directly in rust is a bit more raw. Turns out it's not that hard to do.
I'm just talking about the getrandom issue here. If my WASM scripting continues to work out well I'll likely write more about how I'm setting the over all system up.
I'm using wasmer as my runtime. On the host side you'll need to write a shim that calls the host's version of getrandom and then pass that into the WASM module when it's initialized. Then on the guest side you have to configure getrandom to call the external shim.
Host setup
First you need to setup some context objects that will be used by the shim function:
let store = Store::default();#[derive(WasmerEnv,Clone,Default)]pubstructEnv{#[wasmer(export)]memory:LazyInit<Memory>,}
The interesting bit here is Env.memory which will be initialized by the runtime with a reference to the guest's main memory. We need that because we're going to need to resolve pointers into that memory inside the shim:
// ptr and len represent a slice object on the guest side into which need to write the random bitsfn__get_random(env:&Env,ptr:i32,len:i32){ifletSome(memory) = env.memory_ref(){// retrieve a MemoryView (basically a Vec<Cell<u8>>) of the guest's memorylet view:MemoryView<u8> = memory.view();letmut buff:Vec<u8> = vec![0; len asusize];// Actually get the randomness from the host's getrandom
getrandom::getrandom(&mut buff).unwrap();// and write it into guest memoryfor(dst, src)in view[ptr asusize..ptr asusize + len asusize].iter().zip(buff){
dst.set(src);}}}
Once we have that shim we setup the import object that will inject it into the guest and then initialize the guest module itself:
And that's it on the host side. Now the guest has access to the host's getrandom.
Guest setup
Switching to the crate that will be our WASM guest. First off it needs to have it's getrandom dependency declared with the "custom" feature which allows us to delegate to the shim function injected by the host. Then we just wire up the shim:
use getrandom::register_custom_getrandom;use getrandom::Error;extern{// the function injected by the hostfn__get_random(ptr:i32,len:i32);}fnexternal_getrandom(buf:&mut[u8]) -> Result<(),Error>{let len = buf.len();let ptr = buf.as_ptr();unsafe{__get_random(ptr asi32, len asi32);}Ok(())}register_custom_getrandom!(external_getrandom);
There's not much going on there except that we convert the slice which getrandom gives us into a ptr and a length which we can pass across the guest->host boundary.
And hopefully that saves someone an afternoon of fussing with this stuff.
reacted with thumbs up emoji reacted with thumbs down emoji reacted with laugh emoji reacted with hooray emoji reacted with confused emoji reacted with heart emoji reacted with rocket emoji reacted with eyes emoji
-
I've been experimenting with using Rust based WASM modules as scripts in my game. One of the frustrations with that is the lack of
getrandom
and thusrand
in the WASM guest environment. In WASM on the web or as a WASI executable there are existing tools to solve that problem but hosting directly in rust is a bit more raw. Turns out it's not that hard to do.I'm just talking about the
getrandom
issue here. If my WASM scripting continues to work out well I'll likely write more about how I'm setting the over all system up.I'm using wasmer as my runtime. On the host side you'll need to write a shim that calls the host's version of
getrandom
and then pass that into the WASM module when it's initialized. Then on the guest side you have to configuregetrandom
to call the external shim.Host setup
First you need to setup some context objects that will be used by the shim function:
The interesting bit here is
Env.memory
which will be initialized by the runtime with a reference to the guest's main memory. We need that because we're going to need to resolve pointers into that memory inside the shim:Once we have that shim we setup the import object that will inject it into the guest and then initialize the guest module itself:
And that's it on the host side. Now the guest has access to the host's getrandom.
Guest setup
Switching to the crate that will be our WASM guest. First off it needs to have it's getrandom dependency declared with the "custom" feature which allows us to delegate to the shim function injected by the host. Then we just wire up the shim:
There's not much going on there except that we convert the slice which getrandom gives us into a ptr and a length which we can pass across the guest->host boundary.
And hopefully that saves someone an afternoon of fussing with this stuff.
Beta Was this translation helpful? Give feedback.
All reactions