首页 > 解决方案 > LLVM IR -> WebAssembly。Wasm 空模块 | 实例

问题描述

我正在尝试生成 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 不是函数

怎么了?

结果如下:

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

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

版本:

./llc --版本

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

./wasm-ld --version

LLD 10.0.0

标签: llvmwebassembly

解决方案


原因是您在链接期间没有导出任何符号。

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

构建可执行文件时,默认情况下仅导出入口点 ( _start) 和带有标志的符号。WASM_SYMBOL_EXPORTED

你有几个选择:

  1. 重命名main_start- 这将确保_start已导出并且它的任何依赖项都正确地从环境中导入,而不是完全从 GCd 中导入,就像现在发生的那样。
  2. wasm-ld使用标志调用--export-all- 这将导出目标文件中的所有符号。通常不建议使用此选项,因为您可能会阻止有用的尺寸优化并暴露您不想暴露的东西,但对于原型设计可能很好。
  3. 调用- 这将导出在 IR 级别标记为可见的所有符号wasm-ld--export-dynamic
  4. wasm-ld使用 eg调用时显式列出符号--export=main

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

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

为确保您不会遇到这种情况,请遵循选项 1 并将其重命名main_start特定于 Wasm 的入口点且不接受任何参数,或者将main函数的签名更改为正确的签名并接受两者argcargv喜欢C。

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


推荐阅读