WAVM源码解析 —— wavm run的执行流程(一)

前言

本文主要讨论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主要实现了:

  • 两个辅助性工具assembledisassemble
  • 一个编译工具compile
  • 运行工具run

assembledisassemble没啥说的,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
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容