【问题标题】:Wrong result of call_indirect in WebAssemblyWebAssembly 中 call_indirect 的错误结果
【发布时间】:2020-02-16 21:39:42
【问题描述】:

不明白如何正确使用 call_indirect。

在网上搜索,我发现要让函数指针在 web 汇编中工作并不容易。函数的地址存储在 Table 中,基本上是 i32 标识符。 好吧..让我们编码!

在中间表示中定义语义(call-indirect.ll 文件):

define i32 @call_indirect_method(i32 (i32, i32)* %callee, i32 %arg, i32 %arg2) {
%t = call i32 %callee(i32 %arg, i32 %arg2)
ret i32 %t
}

编写程序(program.c文件):

#include <emscripten.h>

int EMSCRIPTEN_KEEPALIVE call_indirect_method();

int EMSCRIPTEN_KEEPALIVE sum(int a, int b)
{
    return (a + b);
}

int EMSCRIPTEN_KEEPALIVE calc(int a, int b)
{
    return call_indirect_method();
}

一堆js(index.js):

const fs = require("fs");
const raw_source = new Uint8Array(fs.readFileSync(`module.wasm`));
const wasm_module = new WebAssembly.Module(raw_source);

var table = new WebAssembly.Table({initial: 1, element: "anyfunc"});
var memory = new WebAssembly.Memory({initial: 1});

const _exp = new WebAssembly.Instance(wasm_module, {
    "env": {
        __memory_base: 0,
        __table_base: 0,
        memoryBase: 0,
        tableBase: 0,
        memory: memory,
        table: table,
        nullFunc_X: () => console.info("nullFunc_X()"),
        jsCall_X: () => console.info("jsCall_X()"),
        abort: err => {
            throw new Error('abort ' + err);
        },
        abortOnCannotGrowMemory: err => {
            throw new Error('abortOnCannotGrowMemory ' + err);
        },
        abortStackOverflow: err => {
            throw new Error('abortStackOverflow ' + err); // Wellcome here if compile with -O0 level.
        }
    }
}).exports;

table.set(0, _exp._sum);

console.log(_exp._calc(1, 2)); // expect to be 3, got 0 instead

我构建 .wasm 的方式:

emcc -O1 -s WASM=1 -s SIDE_MODULE=1 -s ONLY_MY_CODE=1 -s FILESYSTEM=0 -s TOTAL_MEMORY=65536 -s TOTAL_STACK=1024 -s ENVIRONMENT='web' -s ALLOW_MEMORY_GROWTH=0 -s NO_EXIT_RUNTIME=1 -s STACK_OVERFLOW_CHECK=0 call-indirect.ll program.c -o module.wasm

最后,调用:

node index.js

当一切都“组装好”时 - 我在控制台中有 0。但期待 3。

另外(一件小事,但是..)如果您尝试构建没有优化的代码 -O0 它将由于堆栈溢出错误而中止。不知道为什么。任何想法? (是的,我已经在尝试增加内存了)。

那么,也许有人知道我的情况有什么问题?

【问题讨论】:

  • 不确定这应该如何工作,program.c 中对call_indirect_method 的调用没有传递 call-indirect.il 中预期的任何参数。我很惊讶这甚至会生成有效的 Wasm 并且不会陷阱。
  • 知道如何正确处理 call_indirect 指令吗?或者,也许我误解了这个概念,并且有更简单的方法可以让函数指针工作? :)

标签: javascript c function-pointers webassembly


【解决方案1】:

嗯,看来你应该为你的函数创建一个额外的表。

几点说明:

  • 而且看起来这张表会放在堆内存的开头,但这不是 100% 的信息;
  • 而且,当您有多个函数指针类型时,我不会检查这种情况;
  • 另外,您可能会在 JS 中使用表格的初始大小)。
#include <emscripten.h>

typedef int (*FPTR_TYPE)(int,int);
FPTR_TYPE fMathOp;

int EMSCRIPTEN_KEEPALIVE add(int a, int b)
{
    return (a + b);
}

int EMSCRIPTEN_KEEPALIVE sub(int a, int b)
{
    return (a - b);
}

FPTR_TYPE my_table[] = {
    add,
    sub
};

int EMSCRIPTEN_KEEPALIVE calc(int a, int b)
{
    return fMathOp(a, b);
}

所以“call-indirect.ll”可能会被删除。

【讨论】:

    猜你喜欢
    • 2021-11-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-05-20
    • 2019-02-13
    • 2016-01-20
    • 2019-09-16
    • 2016-09-27
    相关资源
    最近更新 更多