Javascript 使用WebAssembly在Rust中尝试Hello World时出现链接错误
我正在尝试运行一个用WebAssembly制作的hello world程序,但在尝试加载该程序时收到一条错误消息 我在遵循我发现的一些教程时能够运行它,问题是他们使用Emscripten创建JavaScript和HTML来加载代码,但是这个JavaScript和HTML包含大量的样板文件和其他东西。我有点迷路了,相反,我想尝试得到一个非常简单的例子,我正在加载自己 我运行以下命令来编译hello.wasmJavascript 使用WebAssembly在Rust中尝试Hello World时出现链接错误,javascript,rust,webassembly,Javascript,Rust,Webassembly,我正在尝试运行一个用WebAssembly制作的hello world程序,但在尝试加载该程序时收到一条错误消息 我在遵循我发现的一些教程时能够运行它,问题是他们使用Emscripten创建JavaScript和HTML来加载代码,但是这个JavaScript和HTML包含大量的样板文件和其他东西。我有点迷路了,相反,我想尝试得到一个非常简单的例子,我正在加载自己 我运行以下命令来编译hello.wasm echo'fn main(){println!(“你好,Emscripten!”;}>He
echo'fn main(){println!(“你好,Emscripten!”;}>Hello.rs
rustc--target=wasm32未知emscripten hello.rs
为了加载hello.wasm,我从Mozilla WebAssembly文档中获取了这个示例,并尝试运行它
var importObject = {
imports: {
imported_func: function(arg) {
console.log(arg);
}
}
};
fetch('hello.wasm').then(response =>
response.arrayBuffer()
).then(bytes =>
WebAssembly.instantiate(bytes, importObject)
).then(results => {
// Do something with the compiled results!
});
WebAssembly.实例化
崩溃:
链接器错误:导入#0 module=“env”错误:模块不是对象或函数
我发现这个错误与缺少的东西有关,样板代码应该加载,但是通过查看自动生成的HTML和JavaScript,我无法准确地找出它可能是什么。Summary
您必须定义一组由WASM模块导入的函数和值。当WASM模块导入未正确定义的内容时,会出现此链接器错误。Emscripten生成了一大堆JS代码,这些代码定义了WASM模块所需的所有导入(在本例中,这很“容易”,因为Emscripten还生成了WASM模块本身)
现在,您要么使用Emscripten运行时(JS文件),要么自己做很多事情
我将尝试更详细地解释,请耐心听我说:
装配与WASM 汇编是人类可读的机器代码形式(但这两个术语通常可以互换使用,所以在本文中我们也不关心,只称之为汇编)。汇编是为机器/CPU执行而设计的,因此非常简单。汇编基本上是一个指令列表,其中每条指令执行一个特定的、微小的操作。例如,有一条指令可以添加两个数字,在不同的地址执行指令,等等 明显缺失的是
打印
指令。print
的某些功能是一个完全不同的抽象级别,它的作用远不止一条指令。此外,我们所说的“印刷”是什么意思?我们希望我们的程序能够访问某种控制台。重复重要部分:WASM没有print
指令或任何类似指令强>
打印之类的东西需要由环境提供。对于大多数程序和大多数计算机科学来说,这个环境就是操作系统。它管理“控制台”,让你打印。然而,WASM程序的直接环境是浏览器!因此,浏览器必须为您提供一种打印方式
连接
链接是将不同模块/编译单元的导入和导出相互连接(“解析”)的过程。例如,在C++中使用<代码>外部CRATE < /C>>S时,需要进行链接,而在C++中编译多个<代码> .CPP < /Cord>文件时,
在实例化WASM模块时,这也是必要的,因为该模块可能有导入。在我们可以执行模块之前,需要解决这些导入问题
那么你的模块有导入吗?让我们看看!您可以使用工具wasm dis
(反汇编程序)将二进制wasm
代码转换为可读性或多或少的汇编代码:$wasm dis hello.wasm>hello.wast
。查看此文件,我们可以看到以下内容:
(导入“环境”动态处理(全局$import$0 i32))
(导入“环境”STACKTOP(全局$import$1 i32))
(导入“环境”堆栈_MAX(全局$import$2 i32))
(导入“环境”中止(func$import$3(参数i32)))
...
(58个以上)
即使不知道如何阅读此wast
格式,我们也可以做出合理的猜测,并假设您的模块确实导入了内容。我们应该知道,因为我们想要打印,并且没有print
指令
(您可能想知道为什么没有(导入“env”“print”…)
。我无法完全解释这一点,但基本原因是:它比这更复杂。Emscripten只使用一小部分重要导入,并使用这些导入从环境访问其他函数。)
与WASM(和Emscripten)链接
WASM中的链接是由。正如您在链接文档中所看到的,此方法采用importObject
。未能在此对象中定义函数/值(WASM模块的每次导入一个函数/值),将导致WebAssembly.LinkError
。有道理
如果要实例化由文件hello.WASM
定义的WASM模块,必须定义所有62个导入。这看起来真的很烦人,对吗?事实上,并不期望您这样做:这就是为什么Emscripten为您生成必要的JS代码Emscripten生成的WASM模块应该使用Emscripten生成的JS加载程序加载强>
在普通程序中打印?
值得一看在本机环境(操作系统)中运行的程序是如何进行打印的。它们当然也需要与环境(即操作系统)联系起来,对吗?不是真的
虽然Rust、C和C++的编程语言确实有一个用于打印的标准库,但这个标准库不是操作系统的一部分。它只使用操作系统本身。最后,为了打印,使用了一个系统调用。系统调用使用CPU中断来调用操作系统的函数。这有一些优点(例如,您不需要将程序与操作系统链接)