TranslateProject/translated/tech/20210316 How to write -Hello World- in WebAssembly.md
2021-03-25 08:45:26 +08:00

166 lines
7.5 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

[#]: subject: (How to write 'Hello World' in WebAssembly)
[#]: via: (https://opensource.com/article/21/3/hello-world-webassembly)
[#]: author: (Stephan Avenwedde https://opensource.com/users/hansic99)
[#]: collector: (lujun9972)
[#]: translator: (geekpi)
[#]: reviewer: ( )
[#]: publisher: ( )
[#]: url: ( )
如何在 WebAssembly 中写 “Hello World”
======
通过这个分步教程,开始用人类可读的文本编写 WebAssembly。
![Hello World inked on bread][1]
WebAssembly 是一种字节码格式,[几乎所有的浏览器][2]都可以将它编译成其主机系统的机器代码。除了 JavaScript 和 WebGL 之外WebAssembly 还满足了将应用移植到浏览器中以实现平台独立的需求。作为 C++ 和 Rust 的编译目标WebAssembly 使 Web 浏览器能够以接近原生的速度执行代码。
当你谈论 WebAssembly、应用时你必须区分三种状态
1. **源码(如 C++ 或 Rust** 你有一个用兼容语言编写的应用,你想把它在浏览器中执行。
2. **WebAssembly 字节码:** 你选择 WebAssembly 字节码作为编译目标。最后,你得到一个 `.wasm` 文件。
3. **机器码opcode** 浏览器加载 `.wasm` 文件,并将其编译成主机系统的相应机器码。
WebAssembly 还有一种文本格式,用人类可读的文本表示二进制格式。为了简单起见,我将其称为 **WASM-text**。WASM-text 可以比作高级汇编语言。当然,你不会基于 WASM-text 来编写一个完整的应用,但了解它的底层工作原理是很好的(特别是对于调试和性能优化)。
本文将指导你在 WASM-text 中创建经典的 _Hello World_ 程序。
### 创建 .wat 文件
WASM-text 文件通常以 `.wat` 结尾。第一步创建一个名为 `helloworld.wat` 的空文本文件,用你最喜欢的文本编辑器打开它,然后粘贴进去:
```
(module
    ;; Imports from JavaScript namespace
    (import  "console"  "log" (func  $log (param  i32  i32))) ;; Import log function
    (import  "js"  "mem" (memory  1)) ;; Import 1 page of memory (54kb)
   
    ;; Data section of our module
    (data (i32.const 0) "Hello World from WebAssembly!")
   
    ;; Function declaration: Exported as helloWorld(), no arguments
    (func (export  "helloWorld")
        i32.const 0  ;; pass offset 0 to log
        i32.const 29  ;; pass length 29 to log (strlen of sample text)
        call  $log
        )
)
```
WASM-text 格式是基于 S 表达式的。为了实现交互JavaScript 函数用 `import` 语句导入WebAssembly 函数用 `export` 语句导出。在这个例子中,从 `console` 模块中导入 `log` 函数,它需要两个类型为 `i32` 的参数作为输入以及一页内存64KB来存储字符串。
字符串将被写入偏移量 `0``data` 部分。`data` 部分是你的内存的覆盖,内存是在 JavaScript 部分分配的。
函数用关键字 `func` 标记。当进入函数时,栈是空的。在调用另一个函数之前,函数参数会被压入栈中(这里是偏移量和长度)(见 `call $log`)。当一个函数返回一个 `f32` 类型时(例如),当离开函数时,一个 `f32` 变量必须保留在栈中(但在本例中不是这样)。
### 创建 .wasm 文件
WASM-text 和 WebAssembly 字节码有 1:1 的对应关系,这意味着你可以将 WASM-text 转换成字节码(反之亦然)。你已经有了 WASM-text现在将创建字节码。
转换可以通过 [WebAssembly Binary Toolkit][3]WABT来完成。从链接克隆仓库并按照安装说明进行安装。
建立工具链后,打开控制台并输入以下内容,将 WASM-text 转换为字节码:
```
`wat2wasm helloworld.wat -o helloworld.wasm`
```
你也可以用以下方法将字节码转换为 WASM-text
```
`wasm2wat helloworld.wasm -o helloworld_reverse.wat`
```
一个从 `.wasm` 文件创建的 `.wat` 文件不包括任何函数或参数名称。默认情况下WebAssembly 用它们的索引来识别函数和参数。
### 编译 .wasm 文件
目前WebAssembly 只与 JavaScript 共存,所以你必须编写一个简短的脚本来加载和编译 `.wasm` 文件并进行函数调用。你还需要在 WebAssembly 模块中定义你要导入的函数。
创建一个空的文本文件,并将其命名为 `helloworld.html`,然后打开你喜欢的文本编辑器并粘贴进去:
```
<!DOCTYPE  html>
<html>
  <head>
    <meta  charset="utf-8">
    <title>Simple template</title>
  </head>
  <body>
    <script>
   
      var memory = new  WebAssembly.Memory({initial:1});
      function  consoleLogString(offset, length) {
        var  bytes = new  Uint8Array(memory.buffer, offset, length);
        var  string = new  TextDecoder('utf8').decode(bytes);
        console.log(string);
      };
      var  importObject = {
        console: {
          log:  consoleLogString
        },
        js : {
          mem:  memory
        }
      };
     
      WebAssembly.instantiateStreaming(fetch('helloworld.wasm'), importObject)
      .then(obj  => {
        obj.instance.exports.helloWorld();
      });
     
    </script>
  </body>
</html>
```
`WebAssembly.Memory(...)` 方法返回一个大小为 64KB 的内存页。函数 `consoleLogString` 根据长度和偏移量从该内存页读取一个字符串。这两个对象作为 `importObject` 的一部分传递给你的 WebAssembly 模块。
在你运行这个例子之前,你可能必须允许 Firefox 从这个目录中访问文件,在地址栏输入 `about:config`,并将 `privacy.file_unique_origin` 设置为 `true`
![Firefox setting][4]
Stephan Avenwedde, [CC BY-SA 4.0][5]
> **注意:** 这样做会使你容易受到 [CVE-2019-11730][6] 安全问题的影响。
现在,在 Firefox 中打开 `helloworld.html`,按下 **Ctrl**+**K** 打开开发者控制台。
![Debugger output][7]
Stephan Avenwedde, [CC BY-SA 4.0][5]
### 了解更多
这个 Hello World 的例子只是 MDN 的[了解 WebAssembly 文本格式][8]文档中的教程之一。如果你想了解更多关于 WebAssembly 的知识以及它的工作原理,可以看看这些文档。
--------------------------------------------------------------------------------
via: https://opensource.com/article/21/3/hello-world-webassembly
作者:[Stephan Avenwedde][a]
选题:[lujun9972][b]
译者:[geekpi](https://github.com/geekpi)
校对:[校对者ID](https://github.com/校对者ID)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]: https://opensource.com/users/hansic99
[b]: https://github.com/lujun9972
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/helloworld_bread_lead.jpeg?itok=1r8Uu7gk (Hello World inked on bread)
[2]: https://developer.mozilla.org/en-US/docs/WebAssembly#browser_compatibility
[3]: https://github.com/webassembly/wabt
[4]: https://opensource.com/sites/default/files/uploads/firefox_setting.png (Firefox setting)
[5]: https://creativecommons.org/licenses/by-sa/4.0/
[6]: https://www.mozilla.org/en-US/security/advisories/mfsa2019-21/#CVE-2019-11730
[7]: https://opensource.com/sites/default/files/uploads/debugger_output.png (Debugger output)
[8]: https://developer.mozilla.org/en-US/docs/WebAssembly/Understanding_the_text_format