WebAssembly 二进制编码介绍(九)

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

WebAssembly的官方介绍: https://www.wasm.com.cn/docs/binary-encoding/

wasm的二进制模块包含11大组件:


二进制模块组件.png

官方文档中提供解析wasm二进制的方式:

  1. magic & version
    magic - uint32 - 0x6d736100
    version - uint32 - 0x1
  2. 根据不同的sec type 分别解析


    section信息.png
  3. 各section有详细字段说明


    section字段描述.png
  4. 在官方文档描述中,字段类型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
}
  1. 我们以长安链官方合约(镜像chainmaker-go-contract:1.1.1中的合约为例)进行解析。
5.1)执行hexdump main.wasm > main.dump命令以二进制形式查看。使用sublime等编辑工具打开。
hex.png
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

你可能感兴趣的:(WebAssembly 二进制编码介绍(九))