获取 WebAssembly 导出函数的地址?

Get address of a WebAssembly exported function?

假设有这个 C 代码,

int add(int a, int b) { return a + b; }
int mul(int a, int b) { return a * b; }
void *add_ptr() { return add; }
void *mul_ptr() { return mul; }
int op(int a, int b, int (*op) (int a, int b)) { return op(a, b); }
void *op_ptr() { return op; }

并使用常规 clang 8/9 编译它以构建 wasm 文件,

clang --target=wasm32 a.c -nostdlib -Wl,--no-entry -Wl,--export=add -Wl,--export=mul -Wl,--export=mul_ptr -Wl,--export=add_ptr -Wl,--export=op -Wl,--export=op_ptr -o a.wasm

并且运行它使用html这样的页面,

<script>
WebAssembly.instantiateStreaming(fetch('a.wasm')).then(result => alert(`
add: ${result.instance.exports.add(2, 3)}
mul: ${result.instance.exports.mul(2, 3)}

op_add: ${result.instance.exports.op(2, 3, result.instance.exports.add_ptr())}
op_mul: ${result.instance.exports.op(2, 3, result.instance.exports.mul_ptr())}

add_ptr: ${result.instance.exports.add_ptr()}
mul_ptr: ${result.instance.exports.mul_ptr()}
op_ptr: ${result.instance.exports.op_ptr()}

add.name: ${result.instance.exports.add.name}
mul.name: ${result.instance.exports.mul.name}
add_ptr.name: ${result.instance.exports.add_ptr.name}
mul_ptr.name: ${result.instance.exports.mul_ptr.name}
op.name: ${result.instance.exports.op.name}
`));
</script>

这给出了,

add: 5
mul: 6

op_add: 5
op_mul: 6

add_ptr: 1
mul_ptr: 2
op_ptr: 3

add.name: 0
mul.name: 1
add_ptr.name: 2
mul_ptr.name: 3
op.name: 4

在没有 {add|mul}_ptr 类函数的情况下,在 WebAssembly 实例中获取 add/mul 指针地址的可靠方法是什么?它不能是 .name,因为 op.name 不同于 op_ptr 结果。

这里的最终目的(我已经将我的用例缩减为这个片段)是有 addmul 地址并将它传递给 op 就像获取函数的函数指针。

WebAssembly 函数及其包含的可执行代码位于与数据不同的命名空间中。因此,您无法获取函数的地址/指针并将其用作调用它的间接机制。

我认为您在代码中看到的是 WebAssembly 模块 function section.

中函数的索引
add_ptr: 1
mul_ptr: 2
op_ptr: 3

可以通过底层 call_indirect WebAssembly 操作执行动态函数调用。这允许您调用存储在 table section.

中的函数

但是,我不确定 clang 编译器是否支持利用此功能来支持您正在寻找的行为的方法。