前言
本文主要讨论WAVM的实现,有关服务器端的WebAssembly的相关知识,推荐阅读 张秀宏 老师的《WebAssembly 原理与核心技术》。书中用Go语言实现了一个WASM解释器,我照葫芦画瓢,也实现了一个C语言版本的解释器:WCasm。

显然,解释器执行效率低下,WAVM基于LLVM实现了WASM JIT编译,从而提高执行了效率。
将一个C/C++程序编译为wasm二进制文件,然后用WAVM执行
1、使用wasi-sdk编译C/C++程序
如下C程序:
#include<stdio.h>
int main() {
printf("Hello World\n");
return 0;
}
使用wasi-sdk进行编译
CC="[WASI_SDK_PATH]/bin/clang --sysroot=[WASI_SDK_PATH]/share/wasi-sysroot"
$CC 1.c -o 1.wasm
2、使用WAVM执行
$ wavm run 1.wasm
Hello World
本文将分析wavm run的实现!
源码结构

主要的实现都放在了
/Lib目录中,头文件放在了/Include,生成的引用库名为libWAVM。
Programs存放的是wavm工具的实现源码,是基于/Lib库中的实现,如果我们需要调用libWAVM,Programs的实现将会给我们不错的参考。
我们将从Programs中的代码开始,着重分析libWAVM部分的实现。
命令行工具 wavm
我们可以直接运行wavm,查看其帮助文档
$ wavm
Usage: wavm <command> [command arguments]
Commands:
assemble Assemble WAST/WAT to WASM
disassemble Disassemble WASM to WAST/WAT
compile Compile a WebAssembly module
help Display help about command-line usage of WAVM
run Run a WebAssembly program
test Groups subcommands used to test WAVM
version Display information about the WAVM version
我们可以看到,wavm主要实现了:
- 两个辅助性工具
assemble和disassemble - 一个编译工具
compile - 运行工具
run
assemble和disassemble没啥说的,compile和JIT技术是息息相关的,运行wasm程序,wavm必须要先借助llvm将其编译,这部分是最难的对于我来说,对于llvm的部分我是没时间研究,因此这部分我们将跳过,只需要知道,wavm将wasm编译为了本地可执行的二进制形式。
wavm run
run命令则是我们窥探wavm实现的入口,查看其帮助文档(见文末):
-
--function=<name>,用于指定入口函数 -
--precompiled,是否为预编译过的wasm文件,wavm会将编译后的二进制数据写在wasm文件的自定义段中,这样的wasm文件就是预编译的文件,这样会节省运行时编译的时间 -
--nocache,是否使用缓存,WAVM可以将编译的OBJ数据缓存,这样遇到相同的wasm文件时,就不需要重复的编译了,此机制与precompiled相同,都是为了减少编译的时间,缓存机制目前使用的是MDB数据库 -
--enable <feature>,启用的feature,可用的feature列表见下,对于这里我的理解也不深刻 -
--abi=<abi>,用于指定接口函数,wavm是由原来的浏览器wasm发展而来,这部分对应的接口实现就是emscripten,可以和JS代码实现耦合;而wasi就是服务器端wasm的实现,wavm需要实现wasi标准定义的各种接口,这样才能实现我们的printf的实现。printf需要的接口,无非就是向标准输出中写入数据,也就是读写文件描述符的接口,我们使用wasm-objdump可以看一下前面的1.wasm,要求导入的函数:$ wasm-objdump -x 1.wasm | grep Import -A 5 Import[5]: - func[0] sig=2 <__wasi_proc_exit> <- wasi_snapshot_preview1.proc_exit - func[1] sig=3 <__wasi_fd_seek> <- wasi_snapshot_preview1.fd_seek - func[2] sig=4 <__wasi_fd_write> <- wasi_snapshot_preview1.fd_write - func[3] sig=5 <__wasi_fd_close> <- wasi_snapshot_preview1.fd_close - func[4] sig=6 <__wasi_fd_fdstat_get> <- wasi_snapshot_preview1.fd_fdstat_get -
--mount-root <dir>,用于指定wasm的根目录,实现了一个类似与chroot的功能,但是实际上就是在文件相关的接口加了一层限制而已 -
--wasi-trace=<level>,用于追踪系统调用
$ wavm run
Usage: wavm run [options] <program file> [program arguments]
<program file> The WebAssembly module (.wast/.wasm) to run
[program arguments] The arguments to pass to the WebAssembly function
Options:
--function=<name> Specify function name to run in module (default:main)
--precompiled Use precompiled object code in program file
--nocache Don't use the WAVM object cache
--enable <feature> Enable the specified feature. See the list of supported
features below.
--abi=<abi> Specifies the ABI used by the WASM module. See the list
of supported ABIs below. The default is to detect the
ABI based on the module imports/exports.
--mount-root <dir> Mounts <dir> as the WASI root directory
--wasi-trace=<level> Sets the level of WASI tracing:
- syscalls
- syscalls-with-callstacks
ABIs:
none No ABI: bare virtual metal.
emscripten Emscripten ABI, such as it is.
wasi WebAssembly System Interface ABI.
Features:
mvp WebAssembly MVP
import-export-mutable-globals Allows importing and exporting mutable globals
non-trapping-float-to-int Non-trapping float-to-int conversion
sign-extension Sign-extension
multivalue Multiple results and block parameters
bulk-memory Bulk memory
ref-types Reference types
simd 128-bit SIMD
atomics Shared memories and atomic instructions
exception-handling Exception handling
extended-name-section Extended name section
multi-memory Multiple memories
memory64 Memories with 64-bit addresses
all-proposed All features proposed for standardization
shared-tables * Shared tables
legacy-instr-names * Legacy instruction names
any-extern-kind-elems * Elem segments containing non-func externs
quoted-names * Quoted names in text format
wat-custom-sections * Custom sections in text format
interleaved-load-store * Interleaved SIMD load&store instructions
table64 * Tables with 64-bit indices
all * All features supported by WAVM
* Indicates a non-standard feature