WebAssembly 是基于棧式虛擬機(jī)的虛擬二進(jìn)制指令集(V-ISA),它被設(shè)計(jì)為高級編程語言的可移植編譯目標(biāo)。長安鏈?zhǔn)褂玫氖莣asm的二進(jìn)制模塊,我們這里著重分析WebAssembly的二進(jìn)制模塊。WebAssembly的各組件含義及關(guān)聯(lián)關(guān)系需要一段時(shí)間的學(xué)習(xí)來掌握,需要大家自己不斷的研究與琢磨。
WebAssembly的官方介紹: https://www.wasm.com.cn/docs/binary-encoding/
wasm的二進(jìn)制模塊包含11大組件:
官方文檔中提供解析wasm二進(jìn)制的方式:
- magic & version
magic - uint32 - 0x6d736100
version - uint32 - 0x1 -
根據(jù)不同的sec type 分別解析
section信息.png -
各section有詳細(xì)字段說明
section字段描述.png - 在官方文檔描述中,字段類型uint32、int32比較好理解4字節(jié)。但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
中的合約為例)進(jìn)行解析。
5.1)執(zhí)行hexdump main.wasm > main.dump
命令以二進(jìn)制形式查看。使用sublime等編輯工具打開。
5.2)magic & version
a) 開始00 61 73 6d
四個(gè)字節(jié)表示magic,二進(jìn)制使用的是小端方式編碼(大小端的含義還需要自行百度學(xué)習(xí)),實(shí)際為:0x6d736100
b) 隨后01 00 00 00
四個(gè)字節(jié)表示version,0x01
5.3)Type Section
該組件定義了函數(shù)的簽名聲明信息,定義函數(shù)的入?yún)ⅰ⒎祷刂祩€(gè)數(shù)及類型。解析如下:
a) 隨后一個(gè)字節(jié)01
表示下面的section為Type Section
。
b) 隨后varuint32類型
的73
一個(gè)字節(jié),表示該section的長度,通常在處理的時(shí)候會(huì)忽略該字段,除非session的id 為0。
c)隨后12
表示后面有18個(gè)type要描述(12
是16進(jìn)制)。
d) 隨后60
作為每個(gè)type的分割符,隨后01
表示一個(gè)形參,隨后7f
表示該形參的類型為i32。
e)隨后00
表示函數(shù)返回值為0個(gè)。
f)重復(fù)d,e流程,直到遍歷18個(gè)type
5.4)Function Section
該組件包含指向Type Section的Index,F(xiàn)unction Section是數(shù)組結(jié)構(gòu),數(shù)組下標(biāo)與Code Section組件一一對應(yīng),Index表示執(zhí)行Type Section的函數(shù)簽名。
5.5)Code Section
該組件包含函數(shù)具體的實(shí)現(xiàn)邏輯以及本地變量信息,Code Section是一個(gè)數(shù)組,大小與Function Section相對應(yīng)。
5.6)Export Section
該組件描述的是外部可訪問的內(nèi)存、變量、方法等。以方法組件為例,每個(gè)Export Section元素會(huì)關(guān)聯(lián)一個(gè)Index,該Index指向Code Section。當(dāng)外部調(diào)用某method,可以先在export區(qū)找到匹配的method,在通過export的index,找到要執(zhí)行的字節(jié)碼,然后裝載執(zhí)行。
5.7)Data Section
該組件描述對線性的memory進(jìn)行數(shù)據(jù)初始化,組件記錄數(shù)據(jù)信息以及要初始化的位置信息。
5.8)Memory Section
該組件描述程序內(nèi)存塊數(shù)量以及最大、最小值等。
wasm二進(jìn)制執(zhí)行流程可以參照:https://github.com/mathetake/gasm.git,學(xué)習(xí)字節(jié)碼的解析流程。長安鏈基于該開源代碼進(jìn)行bug修復(fù),描述在 chainmaker-go/module/vm/gasm/README.md
。