You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何编译时创建原始指针用于缓冲区后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位常量)。

让第一种情况生成预期代码的方法

如果想保留第一种写法的逻辑,需要让编译器认为操作有副作用:

  • 改用堆内存分配:使用alloc crate在Wasm的堆内存中分配空间(需配置wasm32-unknown-unknown的alloc环境),确保操作的是导出的内存区域;
  • 强制禁止优化:用core::ptr::write_volatile替代普通赋值,比如把*pixel = 0x7d2b7500;改成unsafe { core::ptr::write_volatile(pixel, 0x7d2b7500); },但这种方法仅用于验证优化行为,不推荐在生产代码中使用。

内容的提问来源于stack exchange,提问作者impe

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.02 22:07:28