iT邦幫忙

2018 iT 邦幫忙鐵人賽
DAY 3
2
Modern Web

謙虛,踏實的Web Assembly練習系列 第 3

[練習 02] 編譯工具以及文字格式

官方的編譯工具

wabt

在寫程式之前,需要先準備好編譯工具。Web Assembly官方就有提供編譯工具,就是之前提到過的:wabt (Web Assembly Binary Toolkit)

git clone --recursive https://github.com/WebAssembly/wabt下來之後,還需要先安裝Cmake以及作業系統可以使用的編譯器,例如Visual C++、clang、gcc、MinGW等等,依照他的說明,應該就可以編譯出執行檔。編譯出來的執行檔會放在clone目錄的bin之下。

編譯好之後,可以看到幾個執行檔:

  • spectest-interp
  • wabt-unittests
  • wasm-interp
  • wasm-link
  • wasm-objdump
  • wasm-opcodecnt
  • wasm-validate
  • wasm2wat
  • wast2json
  • wat-desugar
  • wat2wasm

使用方法,可以用[執行檔] --help的方式查詢。之後這些也不會全用到,大概主要就是使用wat2wasm把文字格式的wat程式編譯成wasm,或是反過來把wasm轉成wat。另外一個我有使用的工具,是為了理解實際上編譯出來的wasm與wat有什麼差異,就是wat-desugar,後面會稍微提到。

binaryen

如果只是想用wat來寫wasm,其實用wabt就可以。但是如果是想把asm.js跟wasm互轉、把llvm的Web Assembly Backend編譯出來的.s檔轉成wasm等等工作,就可以使用binaryen。他也一樣可以拿來把wat/wast編譯成wasm或者反過來產出wat/wast。

安裝的方式跟wabt大同小異:

  1. git clone https://github.com/WebAssembly/binaryen.git
  2. cd binaryen
  3. cmake . && make

執行檔也會放在bin目錄,可以看到:

  • asm2wasm
  • wasm-as
  • wasm-dis
  • wasm-metadce
  • wasm-reduce
  • s2wasm
  • wasm-ctor-eval
  • wasm-merge
  • wasm-opt
  • wasm-shell
  • wasm2asm

使用wasm-as可以把wat/wast編譯成wasm,wasm-dis可以把wasm反組議程wat/wast。wasm-merge可以把幾個wasm檔合併成一個,wasm-opt可以最佳化產出的wasm檔,wasm-shell可以執行wat/wast檔並協助除錯等。

跟binaryen比較起來,wabt是比較簡潔的工具,所以我會先使用wabt,有需要再來看一看binaryen。

文字格式

文字格式,顧名思義就是用人可閱讀的方式來寫程式,然後再編譯成wasm。

Web Assembly官網有解說文字格式的文件:Text Format。除了提到可以使用的編譯工具外,這個簡短的說明其實就是兩個重點

  1. Web Assembly的文字格式,主要使用S-表達式 (S-Expression)這個格式來表示模組及各種定義。
  2. 程式部份,則使用線性的指令來寫(就像組合語言啦)

所以再回頭看一下之前寫的myadd.wat:

(module
	(func (export "add") (param $a i32) (param $b i32) (result i32)
		get_local $a
		get_local $b
		i32.add))

這裡面,程式部份就是三行:

get_local $a
get_local $b
i32.add

但是這三行其實並不符合S-Expression的語法。之前自己試寫的時候,以為全部都會用S-Expression,但是寫出來的東西完全過不了編譯...原來文件裡面寫很清楚,但是我沒仔細看XD

把格式的問題搞清楚以後,就可以開始研究怎麼寫程式。所以明天先稍微看看關於Web Assembly這個語言的一些基礎知識。

bonus:wat vs wasm 以及語法糖

如果有看上一篇,會發現一件事情,就是跟文字格式比較起來,wasm檔有更多Section...所以在可能在編譯過程中,編譯器多做了一些事情。wabt裡面有一個工具叫做wat-desugar,可以去掉語法糖把程式最佳化。可以來看看用他處理myadd.wat的結果:

(module
  (func (;0;) (param $a i32) (param $b i32) (result i32)
    get_local $a
    get_local $b
    i32.add)
  (export "add" (func 0))
  (type (;0;) (func (param i32 i32) (result i32))))

這樣對照起來,func、code、export、type區段就都有了。程式中只寫了一個function,他的index就是0,然後在export以及type中,都是用這個index來參考到這個function。

原本的export是寫在func中,編譯的時候他會被拉出成一個export區段,使用add這個名字來對應到index是0的func。而type區段,其實也就是把func中宣告參數及回傳類型的資訊拉出來,同樣用index來對應。


上一篇
[練習 01] 參考文件、可用工具、Hello add與習作
下一篇
[練習 03] 了解Web Assembly的語言要素
系列文
謙虛,踏實的Web Assembly練習20
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言