Sometimes I need to write fast calculations for a browser. For that use case, I can use Rust to compile WASM code.
When I use these Rustflags:
-Ctarget-feature=+multivalue -Clink-args=-zstack-size=64000
And I use these settings in Cargo.toml
:
[profile.release]
lto = true
opt-level = "z"
strip = "debuginfo"
[lib]
crate-type = ["cdylib"]
And I use this code:
#[no_mangle]
fn flip(a: u32, b: u32) -> (u32, u32) {
(b, a)
}
And I build using cargo build --release --target=wasm32-unknown-unknown
, I can then convert the resulting .wasm to .wat (using an outside library). When I do, I get this:
(module
(type $t0 (func (param i32 i32) (result i32 i32)))
(func $flip (export "flip") (type $t0) (param $p0 i32) (param $p1 i32) (result i32 i32)
(local.get $p1)
(local.get $p0))
(memory $memory (export "memory") 1)
(global $__data_end (export "__data_end") i32 (i32.const 64000))
(global $__heap_base (export "__heap_base") i32 (i32.const 64000)))
Some helpful digging by Bjorn3 in this post revealed that the linker unilaterally exports __data_end
and __heap_base
without the possibility for a user override. Rather than guessing that they are always needed, the need to produce these variables should be detectable by the compiler. If these are needed by various pieces of wasm32-unknown-unknown
tooling, then it might make sense to produce a global
for these variables, but export
ing them should be decided by the user because the target OS is unknown, and the target may not need access to these exports.