01 基本工具
WebAssembly
文本格式(.wat
)和WebAssembly
汇编格式(.wasm
)的关系类似于汇编代码与机器代码的关系。
01.01 wabt 工具集
wabt
工具集提供了.wat
和 .wasm
文件相互转换的工具。
wabt
工具集github
地址:
https://github.com/WebAssembly/wabt/releases
win:https://github.com/WebAssembly/wabt/releases/download/1.0.29/wabt-1.0.29-windows.tar.gz
mac:https://github.com/WebAssembly/wabt/releases/download/1.0.29/wabt-1.0.29-macos.tar.gz
linux:https://github.com/WebAssembly/wabt/releases/download/1.0.29/wabt-1.0.29-ubuntu.tar.gz
上面对应的wabt版本,解压后,加入环境变量即可。
也可以下载完整源码,里面有些demo.
git clone --recursive https://github.com/WebAssembly/wabt.git
cd wabt
git submodule update --init
## linux and macos
mkdir build
cd build
cmake ..
cmake --build .
## windows vs
mkdir build
cd build
cmake .. -DCMAKE_BUILD_TYPE=DEBUG -DCMAKE_INSTALL_PREFIX=..\ -G "Visual Studio 17 2022"
cmake --build . --config DEBUG --target install
01.02 emsdk
git clone https://github.com/juj/emsdk.git --depth=1
cd emsdk
git pull
# 需要安装nodejs 和 python
# 当前稳定版本
# emcmdprompt.bat
# emsdk_env.bat
#emsdk install sdk-3.1.17-64bit
#emsdk install 3.1.17
#emsdk help
#emsdk list
#emsdk install --build=Release sdk-fastcomp-tag-1.38.31-64bit binaryen-tag-1.38.31-64bit
:: 安装
emsdk install latest
:: 启用
emsdk activate latest
# 查看版本信息
emcc -v
01.03 在线验证demo
https://webassembly.github.io/wabt/demo/wat2wasm/
01.04 官方文档
wasm 语法更新较快,尽量看官网语法说明。实在不行,直接在源码里面查找。
https://webassembly.org/getting-started/developers-guide/
hello_world.c
#include <stdio.h>
int main() {
printf("hello, world!");
return 0;
}
# 默认生成 a.out.js,a.out.wasm
./emcc tests/hello_world.c
node a.out.js
# 可以指定-o 输出 .html 文件,方便测试(hello.js, hello.wasm, hello.html)
./emcc tests/hello_world.c -o hello.html
# 浏览器打开 hello.html,在调试状态下, console窗口,可以看到输出: hello, world!
02 wat
WebAssemble 文本格式demo,及到wasm格式的转换。
;;wsam0201.wat
(module
(import "console" "log" (func $log (param i32)))
(func $add (param i32 i32)
local.get 0
local.get 1
i32.add
call $log
)
(export "add" (func $add))
)
:: 设置 emsdk 及 wabt 工具集路径
E:\src\html\app\wasm>set PATH=e:\git\emsdk;e:\git\wabt\bin;%PATH%
:: 运行环境脚本,初始化环境变量
E:\src\html\app\wasm>e:\git\emsdk\emsdk_env.bat
Adding directories to PATH:
PATH += E:\git\emsdk
PATH += E:\git\emsdk\upstream\emscripten
PATH += E:\git\emsdk\node\14.18.2_64bit\bin
:: wat 到 wasm 格式的转换
E:\src\html\app\wasm>wat2wasm wasm0201.wat -o wasm0201.wasm
:: 查看 wat 的汇编输出,二进制格式描述
E:\src\html\app\wasm>wat2wasm wasm0201.wat -v
0000000: 0061 736d ; WASM_BINARY_MAGIC
0000004: 0100 0000 ; WASM_BINARY_VERSION
; section "Type" (1)
0000008: 01 ; section code
0000009: 00 ; section size (guess)
000000a: 02 ; num types
; func type 0
000000b: 60 ; func
000000c: 01 ; num params
000000d: 7f ; i32
000000e: 00 ; num results
; func type 1
000000f: 60 ; func
0000010: 02 ; num params
0000011: 7f ; i32
0000012: 7f ; i32
0000013: 00 ; num results
0000009: 0a ; FIXUP section size
; section "Import" (2)
0000014: 02 ; section code
0000015: 00 ; section size (guess)
0000016: 01 ; num imports
; import header 0
0000017: 07 ; string length
0000018: 636f 6e73 6f6c 65 console ; import module name
000001f: 03 ; string length
0000020: 6c6f 67 log ; import field name
0000023: 00 ; import kind
0000024: 00 ; import signature index
0000015: 0f ; FIXUP section size
; section "Function" (3)
0000025: 03 ; section code
0000026: 00 ; section size (guess)
0000027: 01 ; num functions
0000028: 01 ; function 0 signature index
0000026: 02 ; FIXUP section size
; section "Export" (7)
0000029: 07 ; section code
000002a: 00 ; section size (guess)
000002b: 01 ; num exports
000002c: 03 ; string length
000002d: 6164 64 add ; export name
0000030: 00 ; export kind
0000031: 01 ; export func index
000002a: 07 ; FIXUP section size
; section "Code" (10)
0000032: 0a ; section code
0000033: 00 ; section size (guess)
0000034: 01 ; num functions
; function body 0
0000035: 00 ; func body size (guess)
0000036: 00 ; local decl count
0000037: 20 ; local.get
0000038: 00 ; local index
0000039: 20 ; local.get
000003a: 01 ; local index
000003b: 6a ; i32.add
000003c: 10 ; call
000003d: 00 ; function index
000003e: 0b ; end
0000035: 09 ; FIXUP func body size
0000033: 0b ; FIXUP section size
02.02
;;wasm0202.wat
;;wat2wasm wasm0202.wat -o wasm0202.wasm
(module
(func (export "showMeTheAnswer") (result i32)
i32.const 42
)
)
<!DOCTYPE html>
<!-- wasm0202.html -->
<html>
<head>
<meta charset="utf-8">
<title>wasm0202</title>
</head>
<body>
<script>
fetch('wasm0202.wasm')
.then((response) => response.arrayBuffer())
.then((bytes) => WebAssembly.instantiate(bytes))
.then((result) => console.log(result.instance.exports.showMeTheAnswer()));
</script>
</body>
</html>
02.03
;;wasm0204.wat
;; wat2wasm wasm0204.wat -o wasm0204.wasm
(module
;;import js:print as js_print()
(import "js" "print" (func $js_print (param i32 i32)))
(import "js" "mem" (memory 1)) ;;import js:mem as memory
(data (i32.const 0) "你好,WASM")
(func (export "hello")
i32.const 0 ;; pass offset 0 to js_print
i32.const 13 ;;pass length 13 to js_print
call $js_print
)
)
<!DOCTYPE html>
<!-- wasm0204.html -->
<html>
<head>
<meta charset="utf-8">
<title>wasm0204</title>
</head>
<body>
<script>
var wasmMem = new WebAssembly.Memory({initial:1});
function printStr(offset, length) {
var bytes = new Uint8Array(wasmMem.buffer, offset, length);
var string = new TextDecoder('utf8').decode(bytes);
console.log(string);
}
var importObj = {js: {print: printStr, mem: wasmMem}};
fetch('wasm0204.wasm').then(response =>
response.arrayBuffer()
).then(bytes =>
WebAssembly.instantiate(bytes, importObj)
).then(result =>
result.instance.exports.hello()
);
</script>
</body>
</html>