为啥 WASM 文件不同?

Posted

技术标签:

【中文标题】为啥 WASM 文件不同?【英文标题】:Why are the WASM files different?为什么 WASM 文件不同? 【发布时间】:2020-11-14 02:13:33 【问题描述】:

我想使用 WebAssembly,所以我必须将 C 文件编译为 WASM 文件。

C文件内容如下

//The online 'add.c'
WASM_EXPORT
int add(int a, int b)
 
    return a + b;

这是一个非常简单的 C 文件。

此 WASM 文件由在线编译工具 WebAssembly Studio 编译。我使用一个工具“wasm2wat”将其反汇编为Text文件,内容如下

(module
 (type $t0 (func))
 (type $t1 (func (param i32 i32) (result i32)))
 (func $__wasm_call_ctors (type $t0))
 (func $add (type $t1) (param $p0 i32) (param $p1 i32) (result i32)
   local.get $p1
   local.get $p0
   i32.add)
 (table $T0 1 1 funcref)
 (memory $memory 2)
 (global $g0 (mut i32) (i32.const 66560))
 (global $__heap_base i32 (i32.const 66560))
 (global $__data_end i32 (i32.const 1024))
 (export "memory" (memory 0))
 (export "__heap_base" (global 1))
 (export "__data_end" (global 2))
 (export "add" (func $add)))

而且我还使用“emcc add.c -s WASM=1 -O3 -o add.js”来编译本地的“add.c”

//The local 'add.c'
EMSCRIPTEN_KEEPALIVE
int add(int a, int b)

    return a + b;

上述命令得到的WASM文件是

(module
 (type $t0 (func))
 (type $t1 (func (param i32 i32) (result i32)))
 (func $b (type $t0)
   nop)
 (func $c (type $t1) (param $p0 i32) (param $p1 i32) (result i32)
   local.get $p0
   local.get $p1
   i32.add)
 (table $a 1 1 funcref)
 (export "a" (table 0))
 (export "b" (func $b))
 (export "c" (func $c)))

为什么两个结果不一样?为什么上面的文件可以用在html中,下面的不行?

【问题讨论】:

【参考方案1】:

这是两个略有不同的编译器驱动程序(尽管都基于 llvm+clang),它们针对的环境略有不同。嵌入器的 ABI/API/合约在一些方面有所不同。例如,在 emscripten 中,默认契约是在 JS 中创建 WebAssembly 内存对象并导出到 WebAssembly 文件中。 WASI(web 之外的 wasm)的默认设置是在 wasm 文件中创建内存对象并将其导出到嵌入器(因此在您的第一种情况下是“内存”导出)。

您的第一个示例中的一些多余元素可能会通过在结果输出上运行wasm-opt 来消除。例如,如果你的小例子既没有使用内存也没有使用表,那么理论上这两者都可以完全删除。

【讨论】:

我明白了。但是为什么上面的文件可以在HTML中使用,而下面的却不行呢?网页上编译的wasm文件可以在JS中使用,但是本地用“emcc”编译的wasm会报错。为什么?以及如何在JS中使用“emcc”工具正确编译wasm文件?

以上是关于为啥 WASM 文件不同?的主要内容,如果未能解决你的问题,请参考以下文章

生成返回字符串的函数时,为啥 wasm-opt 在 wasm-pack 构建中失败?

保护 wasm 二进制文件的最佳实践

是否可以从 AssemblyScript 导入 .wasm 文件?

如何在 Django 中提供 WASM 文件

未解决:fatal error: wasm.h: 没有那个文件或目录 #include <wasm.h>

如何加载存储在子目录中的 .wasm 文件?