位元格式

大家也許會很好奇,用 wat2wasm 把文字轉成 wasm 檔的時候,跑出一大堆數字的部份是代表什麼意思?其實那就是轉換之後檔案裡實際的內容,也就是我們接下來要介紹的位元格式

LEB128 (Little-Endian Base 128)

雖然整數通常會有固定長度,像是 8, 16, 32, 64 bits,但是以 32 bits 來說,實際上常常不需要用到 32 bits 來表示。為了精減大小,WebAssembly 在位元格式上常常會使用 LEB128 格式來表示整數。

解碼

每個 byte 只用 7 bits 表示數值,剩下的 1 bit 表示是否結束

如果長度不夠,照有號/無號整數的方式補足長度,得到有號/無號整數的數值

編碼

  • 負數

  • 正數

以 32 位元整數來說,最多用到 5 個 byte,如果全都是 1 開頭的話表示錯誤;64 位元整數最多 10 個,16 位元最多 3 個,也是用這種方法檢查錯誤

雖然在數值接近最大值的時候,是用更多位元表示相同的數,不過大部分的狀況數值不會那麼大,所以用 LEB128 可以有效的降低檔案大小

數值型別的位元格式

模組的位元格式

接下來講解模組中各部份的位元格式,大家可以對照 wat2wasm 的輸出結果做印證

前文 (Preamble)

這部份固定佔 8 bytes,大部分的位元格式中幾乎都會有前文,用來區別不同的位元格式

  • 魔術數字 (Magic number) 4 bytes

    • 0x00 0x61 0x73 0x6d,用字碼轉換成文字之後就是 "\0asm",表示這是 wasm 格式

  • 版本 (Version) 4 bytes

    • 0x01 0x00 0x00 0x00,表示這是 0x01 版的 WebAssembly,在之前也有 0x0a, 0x0b, 0x0c, 0x0d的先行版本,之後如果推出新版的 WebAssembly,這邊就會變動

各部份標頭 (Section header)

接下來會分成許多部份 (Section),對照到在 模組 章節一般格式的各個部份。每個部份都不是必須的,沒有用到的話就不會產生

每個部份在依開始都會有個標頭 (header),標示各個部份的代碼還有長度

  • 代碼 (Section code)

    用來區分是哪個部份

  • 長度 (Section size)

    用一個 LEB128 32 位元無號整數,表示整個部份的長度 (不包括標頭)

    在 wat2wasm 的輸出裡會看到這邊是 section size (guess),既然是guess,表示這的值是亂猜的,不用理會,也不會被編進檔案裡

    真正的值在下面 FIXUP section size 的地方,在編進檔案的時候也是這個真正值會被寫到section size (guess)的位置上

函式型別 (Type section)

  • 數量 (num types)

    • 用一個 LEB128 32 位元無號整數,表示總共有多少函式型別

  • 函式型別

引入 (Import section)

  • 數量 (num imports)

    • 用一個 LEB128 32 位元無號整數,表示總共有多少引入物件

  • 引入物件:

在引入物件中,接下來的部份會依據不同的引入種類,而有不同的格式:

  • 函式

    • 一個 LEB128 32 位元無號整數,表示函式型別的編號

  • 函式表

  • 記憶體

  • 全域變數

函式 (Function section)

  • 數量 (num functions)

    • 用一個 LEB128 32 位元無號整數,表示總共有多少函式

  • 編號

    • 一個或多個 LEB128 32 位元無號整數,表示該函式使用的函式型別編號

函式表 (Table section)

  • 數量 (num tables)

    • 用一個 LEB128 32 位元無號整數,表示總共有多少函式表 (目前只會是 1)

  • 函式表

記憶體 (Memory section)

  • 數量 (num memories)

    • 用一個 LEB128 32 位元無號整數,表示總共有多少記憶體 (目前只會是 1)

  • 記憶體

全域變數 (Global section)

  • 數量 (num globals)

    • 用一個 LEB128 32 位元無號整數,表示總共有多少全域變數

  • 全域變數

輸出 (Export section)

  • 數量 (num exports)

    • 用一個 LEB128 32 位元無號整數,表示總共有多少全域變數

  • 輸出物件

起始函式 (Start section)

  • 索引值 (index)

    • 一個 LEB128 32 位元無號整數,表示起始函式在模組中的編號

函式表元素 (Element section)

  • 數量 (num elements)

    • 用一個 LEB128 32 位元無號整數,表示總共有多少函式表元素

  • 函式表元素

    • 會根據這邊的資料,指定函式表的值

程式碼 (Code section)

程式碼部份表示函式的內容

  • 數量 (num functions)

    • 用一個 LEB128 32 位元無號整數,表示總共有多少函式內容

  • 函式內容

  • 區域變數 (在函式內容裏面)

    相同種類且接連在一起宣告的區域變數,會合併成一個區域變數格式,所以才會有"數量"欄位

資料 (Data section)

資料部份表示記憶體的初始資料

  • 數量 (num data)

    • 用一個 LEB128 32 位元無號整數,表示總共有多少資料指定物件

  • 資料指定物件

指令

指令的部份大部份是一個 byte 編碼,有些指令會加上額外的參數

控制指令

  • br_table 額外參數

    • 跳回層數數量 : 一個 LEB128 32 位元無號整數

    • 跳回層數 : 1\ge 1 個 LEB128 32 位元無號整數

參數指令

記憶體指令

  • 記憶體額外參數

    • 對齊 (alignment) : 一個 LEB128 32 位元無號整數

      (WasmVM 不會用到這個值)

    • 位移 (offset) : 一個 LEB128 32 位元無號整數

常數指令

算術指令

Last updated