Javascript 使用WebAssembly在Rust中尝试Hello World时出现链接错误

Javascript 使用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

我正在尝试运行一个用WebAssembly制作的hello world程序,但在尝试加载该程序时收到一条错误消息

我在遵循我发现的一些教程时能够运行它,问题是他们使用Emscripten创建JavaScript和HTML来加载代码,但是这个JavaScript和HTML包含大量的样板文件和其他东西。我有点迷路了,相反,我想尝试得到一个非常简单的例子,我正在加载自己

我运行以下命令来编译hello.wasm

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中断来调用操作系统的函数。这有一些优点(例如,您不需要将程序与操作系统链接)