为何编译时创建原始指针用于缓冲区后Wasm二进制代码为空?
为何两次Wasm构建结果差异巨大?
我尝试以wasm32-unknown-unknown目标构建no_std Rust代码,遇到了两种写法生成完全不同Wasm的问题:
情况1:函数内创建局部变量指针
Rust代码:
#[no_mangle] pub fn test() { let mut idx: i32 = 10; let ptr = &mut idx as *mut i32; let buffer = unsafe { core::slice::from_raw_parts_mut(ptr, 10) }; for pixel in buffer.iter_mut() { *pixel = 0x7d2b7500; } }
用wasm2wat转换后得到的Wasm:
(module (type (;0;) (func)) (func (;0;) (type 0) nop) (memory (;0;) 16) (global (;0;) i32 (i32.const 1048576)) (global (;1;) i32 (i32.const 1048576)) (export "memory" (memory 0)) (export "test" (func 0)) (export "__data_end" (global 0)) (export "__heap_base" (global 1)))
此时test函数为空,仅包含nop指令。
情况2:指针作为外部参数传入
修改后的Rust代码:
#[no_mangle] pub fn test(ptr: *mut i32) { let buffer = unsafe { core::slice::from_raw_parts_mut(ptr, 10) }; for pixel in buffer.iter_mut() { *pixel = 0x7d2b7500; } }
生成的Wasm:
(module (type (;0;) (func (param i32))) (func (;0;) (type 0) (param i32) local.get 0 i64.const 9019431323700000000 i64.store offset=32 align=4 local.get 0 i64.const 9019431323700000000 i64.store offset=24 align=4 local.get 0 i64.const 9019431323700000000 i64.store offset=16 align=4 local.get 0 i64.const 9019431323700000000 i64.store offset=8 align=4 local.get 0 i64.const 9019431323700000000 i64.store align=4) (memory (;0;) 16) (global (;0;) i32 (i32.const 1048576)) (global (;1;) i32 (i32.const 1048576)) (export "memory" (memory 0)) (export "test" (func 0)) (export "__data_end" (global 0)) (export "__heap_base" (global 1)))
这里test函数生成了实际的内存写入逻辑。
差异原因
第一种情况触发了Rust编译器的死代码消除优化:
- 局部变量
idx是栈上分配的,仅占4字节,但你通过它创建的slice试图操作从该地址开始的10个i32(共40字节),这本身属于越界访问。 - 编译器判断这段代码没有任何对外可见的副作用——既没有修改导出的Wasm内存,也没有返回值或调用外部函数,所以直接把整个循环和变量定义都优化掉,只留下空的
nop指令占位。
第二种情况中,指针是外部传入的,编译器无法确定指针指向的内存范围和用途,无法证明这段内存操作没有副作用,因此保留了循环逻辑,甚至做了常量传播+循环展开优化:把循环中重复的固定值赋值操作,直接展开成多个i64.store指令(每个指令写入两个i32的数值,0x7d2b7500重复两次拼接成64位常量)。
让第一种情况生成预期代码的方法
如果想保留第一种写法的逻辑,需要让编译器认为操作有副作用:
- 改用堆内存分配:使用
alloccrate在Wasm的堆内存中分配空间(需配置wasm32-unknown-unknown的alloc环境),确保操作的是导出的内存区域; - 强制禁止优化:用
core::ptr::write_volatile替代普通赋值,比如把*pixel = 0x7d2b7500;改成unsafe { core::ptr::write_volatile(pixel, 0x7d2b7500); },但这种方法仅用于验证优化行为,不推荐在生产代码中使用。
内容的提问来源于stack exchange,提问作者impe
相关产品推荐
相关产品推荐

