我正在编写一个 wasm 程序,它将动态生成 wasm 函数作为字节码(包括类型签名、局部向量和主体指令序列; defines a function according to the spec 的所有内容)。我想要一种有效的方法来从已经实例化的正在运行的模块中执行这些函数(即能够获取它们的 funcref )。
似乎大多数实现都是通过简单地从生成的代码中创建一个新模块,连接必要的导入,然后从 JavaScript 调用新模块来完成此类操作。
我需要在没有 JavaScript 的情况下完成此操作,理想情况下也不需要创建新模块。看起来这应该可以通过相对简单的方式实现:
- 只需使用新的
funcidx
将新函数添加到当前模块的现有函数向量中即可。显然,必须注意确保生成的代码通过适当的索引引用其他函数、全局变量、导入等。 - 通过新的
funcidx
引用新函数,包括调用ref.func
来获取funcref
来间接调用它。
根据我对 wasm 的理解,第 1 步是不可能的,因为没有说明向默认 funcref
表添加新函数。将来这可能会发生变化吗?浏览所有 wasm 规范提案有点困难,因此希望这篇文章能够引起解决此问题的人的关注,至少链接到有关当前事态的一些提示。
如果规范中的实际指令无法启动,似乎可以通过运行时 API(例如 WASI)来实现,它可以引入 API 方法来就地修改当前正在运行的模块。 AFAICT WASI 目前没有为此进行设计,也没有计划这样做。我的想法是错的还是有另一个运行时接口(interface)确实计划这样做?
最佳答案
WebAssembly 支持通过函数表向运行实例添加函数,函数表可以从主机环境导入。
一个非常重要的例子是 Emscripten 实现了完全独立的 WebAssembly 模块与现有模块的动态链接 ( https://emscripten.org/docs/compiling/Dynamic-Linking.html )。特别是,Emscripten 解决了向正在运行的 WebAssembly 实例添加功能(具有非常高的性能)的问题。 Emscripten中dlopen的实现利用了可以外部修改函数表的功能。
如果您转到https://pyodide.org/en/stable/console.html并输入“import numpy”,然后输入“numpy.array(10)”,然后 (1) numpy 的所有 C 代码在实例化后都会添加到正在运行的 Python Wasm 实例中,(2) 您刚刚调用了其中之一来自 Python WASM 实例的 C 函数(REPL 是其中的一部分)。这也非常快,例如,它不会经过缓慢的 Javascript 层。
这建立在现有的 WebAssembly 规范之上。但这并不平凡!例如,实现这项工作的关键组件是 wasm32-unknown-emscripten 目标,它是 LLVM 的一部分,它生成实际的位置无关代码 (-fPIC)。我不知道除了C/C++之外是否还有其他WebAssembly语言支持-fPIC。请参阅https://github.com/WebAssembly/tool-conventions/blob/main/DynamicLinking.md另外,如果你看看 emscripten 本身,例如 https://github.com/emscripten-core/emscripten/blob/main/src/library_dylink.js里面有解析wasm动态库的代码等。
关于webassembly - 是否可以向实例化的 Webassemble 模块添加新功能?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/71803962/