WebAssembly 是基于栈式虚拟机的虚拟二进制指令集(V-ISA),它被设计为高级编程语言的可移植编译目标。长安链使用的是wasm的二进制模块,我们这里着重分析WebAssembly的二进制模块。WebAssembly的各组件含义及关联关系需要一段时间的学习来掌握,需要大家自己不断的研究与琢磨。
WebAssembly的官方介绍: https://www.wasm.com.cn/docs/binary-encoding/
wasm的二进制模块包含11大组件:

官方文档中提供解析wasm二进制的方式:
- magic & version
magic - uint32 - 0x6d736100
version - uint32 - 0x1 -
根据不同的sec type 分别解析
section信息.png -
各section有详细字段说明
section字段描述.png - 在官方文档描述中,字段类型uint32、int32比较好理解4字节。但varuintN、varintN并未见过,这是
LEB128编码格式,具体解码方式可参考下述代码
func DecodeUint32(r io.Reader) (ret uint32, num uint64, err error) {
const (
uint32Mask uint32 = 1 << 7
uint32Mask2 = ^uint32Mask
)
for shift := 0; shift < 35; shift += 7 {
b, err := readByteAsUint32(r)
if err != nil {
return 0, 0, fmt.Errorf("readByte failed: %w", err)
}
num++
ret |= (b & uint32Mask2) << shift
if b&uint32Mask == 0 {
break
}
}
return
}
- 我们以长安链官方合约(
镜像chainmaker-go-contract:1.1.1中的合约为例)进行解析。
5.1)执行hexdump main.wasm > main.dump命令以二进制形式查看。使用sublime等编辑工具打开。

5.2)magic & version
a) 开始00 61 73 6d四个字节表示magic,二进制使用的是小端方式编码(大小端的含义还需要自行百度学习),实际为:0x6d736100
b) 随后01 00 00 00四个字节表示version,0x01
5.3)Type Section
该组件定义了函数的签名声明信息,定义函数的入参、返回值个数及类型。解析如下:
a) 随后一个字节01表示下面的section为Type Section。
b) 随后varuint32类型的73一个字节,表示该section的长度,通常在处理的时候会忽略该字段,除非session的id 为0。
c)随后12表示后面有18个type要描述(12是16进制)。
d) 随后60作为每个type的分割符,随后01表示一个形参,随后7f 表示该形参的类型为i32。
e)随后00表示函数返回值为0个。
f)重复d,e流程,直到遍历18个type
5.4)Function Section
该组件包含指向Type Section的Index,Function Section是数组结构,数组下标与Code Section组件一一对应,Index表示执行Type Section的函数签名。
5.5)Code Section
该组件包含函数具体的实现逻辑以及本地变量信息,Code Section是一个数组,大小与Function Section相对应。
5.6)Export Section
该组件描述的是外部可访问的内存、变量、方法等。以方法组件为例,每个Export Section元素会关联一个Index,该Index指向Code Section。当外部调用某method,可以先在export区找到匹配的method,在通过export的index,找到要执行的字节码,然后装载执行。
5.7)Data Section
该组件描述对线性的memory进行数据初始化,组件记录数据信息以及要初始化的位置信息。
5.8)Memory Section
该组件描述程序内存块数量以及最大、最小值等。
wasm二进制执行流程可以参照:https://github.com/mathetake/gasm.git,学习字节码的解析流程。长安链基于该开源代码进行bug修复,描述在 chainmaker-go/module/vm/gasm/README.md。

