LLVM IR -> WebAssembly。 wasm 空模块 |实例

LLVM IR -> WebAssembly. Wasm empty module | instance

我正在尝试生成 WebBrowser (Firefox) 可以正确理解的有效 wasm 文件,但我不确定我在这里做错了

这是Main.ll文件

define i32 @main() {
  ret i32 42
}

那么我正在使用 llc (Linux):

./llc -mtriple=wasm32-unknown-unknown -O3 -filetype=obj main.ll -o main.o

然后我使用 wasm-ld (Linux):

./wasm-ld main.o -o main.wasm --no-entry -allow-undefined

然后我将main.wasm复制到Windows然后打开这个本地文件页面:

|-- fille.html
|-- main.wasm

<div id="test">
</div>

<style>
    #test
    {
        border: 3px solid red;
        width: 100%;
        height: 100%;
    }
</style>

<script>
    fetch("main.wasm")
        .then(response => response.arrayBuffer())
        .then(bytes => WebAssembly.instantiate(bytes, {}))
        .then(results => {
          window.alert(results.instance.exports.main());
        });
</script>

但是

TypeError: results.instance.exports.main is not a function

怎么了?

结果如下:

console.log(JSON.stringify(results));

{"module":{},"instance":{}}

版本:

./llc --version

LLVM (http://llvm.org/):
LLVM version 10.0.0

./wasm-ld --version

LLD 10.0.0

原因是您在链接过程中没有导出任何符号。

您可能想查看 the Exports section of wasm-ld docs 了解详细信息,但这是他们对默认值的看法:

When building an executable, only the entry point (_start) and symbols with the WASM_SYMBOL_EXPORTED flag are exported by default.

您有两个选择:

  1. main 重命名为 _start - 这将确保 _start 被导出并且它的任何依赖项都从环境中正确导入,而不是完全 GCd,就像发生的事情一样现在。
  2. 使用 --export-all 标志调用 wasm-ld - 这将导出目标文件中的所有符号。通常不推荐使用此选项,因为您可能会阻止有用的大小优化并暴露您不想暴露的内容,但可能适合原型制作。
  3. 使用 --export-dynamic 调用 wasm-ld - 这将导出在 IR 级别标记为可见的所有符号。
  4. 在调用 wasm-ld 时明确列出符号,例如--export=main.

除 (1) 之外的所有选项中需要注意的另一个警告是 main 以特殊方式处理,并且使用您当前的代码将导致两个不同的符号:

  1. main - 一个自动生成的函数包装器,带有两个用于调用函数的 argcargv 参数。
  2. __original_main - 您实际定义的函数的符号。

为了确保你不 运行 进入这个,要么按照选项 1 并将 main 重命名为 _start,这是一个特定于 Wasm 的入口点并且不接受任何参数,或将 main 函数的签名更改为正确的签名并接受 argcargv,就像在 C.

中一样

希望这一切能让你继续前进。