作者:黑白大彩电,软件工程专业,多年C++开发经验,在Annchain团队负责Websocket、RPC以及WebAssembly方面的研发工作。
WebAssembly按照字面意思就是Web世界(浏览器)里的Assembly(汇编语言),也就是浏览器支持的一种底层的语言,它的指令集确实类似汇编指令,虽然事实上并不完全是,但还是有些接近。严格来说,WebAssembly是一种浏览器支持的二进制文件格式标准,该文件格式定义了基于堆栈运行的图灵完备的指令集所组成的二进制代码段,以及为了运行指定的代码(函数)所需要的相关环境,比如:数据类型、函数签名、数据区、内存区、表区、开始区、代码区等。
WebAssembly文件布局
图一: WebAssembly文件布局
如图一所示,WebAssembly文件(称之为模块)总体上由三块组成:魔数(固定值:0x6d736100,小端存储)、版本号(当前值:0x00000001,小端存储)、以及若干个区(section)。其中,每个区由三部分组成:类型、长度以及实际数据。图中的varuint32表示使用leb128编码方式。因为WebAssembly是在网络上传输的,所以该格式为了尽量缩小文件体积,在内部广泛使用了数据压缩格式leb128,leb128是变长的整数压缩编码形式。因为在很多情况下,比如一个32位的整数在大部分时间存储的值只需要一个8位的字节存储即可,但是将来又有可能需要32位,因此可以采用采用leb128编码。leb128采用的方式是从低字节开始,每个字节中的最高位不是存储实际的值,而是用来作为标志位,当该位置位时,表示下一字节还有数据,否则表示下一字节没有数据,没有数据的字节直接省略,从而达到了数据压缩的目的。
模块里定义的各个区根据不同的类型,它们的实际数据有着不同的定义结构。目前支持的区类型范围是整数1到11这11种。如图二所示:
图二:区类型定义
在详细介绍每个区结构之前,先来了解下基础知识点:
- 数据类型,WebAssembly只有四种数据类型i32、i64、f32、f64。分别表示32位整数、64位整数、32位浮点数、64位浮点数。
- 函数签名,WebAssembly的函数签名是由各个参数类型外加返回值类型组成,形如:(param1_type, param2_type [,...]) result_type。当前版本的函数只支持一个返回值。
- 索引空间,WebAssembly模块中的函数、内存、表、全局变量都各自有自己的索引空间,用于记录各自的顺序,方便相关指令引用访问。
有了以上三点基础知识之后,下面分别介绍每个区的结构
类型区(type值为1):
&nbs