I'm converting a native driver into web assembly just to see if I can do it (because if so it would make things a lot easier for me). The driver requires a base address for the device, and then I can calculate register offsets. What is the safest way of exposing a global variable to the host that can then be updated to recompute register offsets?
#[no_mangle] static will be exported from the WASM module:
#[no_mangle] pub static mut BASE_ADDR: usize = 0;
(module (table (;0;) 1 1 funcref) (memory (;0;) 17) (global (;0;) (mut i32) (i32.const 1048576)) (global (;1;) i32 (i32.const 1048576)) (global (;2;) i32 (i32.const 1048580)) (global (;3;) i32 (i32.const 1048580)) (export "memory" (memory 0)) (export "BASE_ADDR" (global 1)) (export "__data_end" (global 2)) (export "__heap_base" (global 3)))
Okay, but what if I want to do that safely without
static mut? Can I just do a regular
pub static or would Rust not export it then? Basically, I'm trying to do this:
#[no_mangle] pub static mut BASE_ADDR: u64 = 0x00; static REG1: u64 = BASE_ADDR + 0x04;
Such that when
BASE_ADDR is updated,
REG1 is recomputed as well.
An immutable static can't depend on the value of a mutable static.
Thanks. One last question about WASM: is there a way I can force-generate a trap without doing an illegal op? For instance, if I use WASM in an environment where I need to monitor for interrupts, is there a way I can "pause" the execution of a WASM module? Or do no WASM interpreter libraries allow that kind of thing?
You can use core::arch::wasm32::unreachable - Rust to generate a trap instruction. You could also potentially export a function that could be used for that from the host into the module.
It depends on your runtime. I use
wasmer and they've got a
wasmer::raise_user_trap() function which, when called from a host function, will raise a trap and abort the WebAssembly call.
You can later call
RuntimeError::downcast() to extract the underlying error, giving you a way to differentiate between different the traps you may raise. I don't think you can use it as a mechanism for pausing execution though, the stack frames are probably thrown away and not resumable.