@ledsun blog

無味の味は佳境に入らざればすなわち知れず

wasmバイナリのカスタムセクションを書いてみる

最小限のWebAssemblyのバイナリファイルを書く - @ledsun blog でwasmバイナリのプリアンブルの書き出しに成功しました。 続いてセクションを書き出してみます。

Modules — WebAssembly 2.0 (Draft 2023-07-24) によると

セクションの定義
1バイトのID、4バイトのサイズ、サイズで指定した中身のようです。

ID 0はカスタムセクションというデバッグ情報を埋め込むセクションです。 カスタムセクションはnameと呼ばれるUTF-8文字列を埋め込みます。 ということはnameがhogeなカスタムセクションは0x00 0x04 0x00 0x00 0x00 0x68 0x6f 0x67 0x65で良さそうです。

次のRubyスクリプトを使って書き出します。

File.open("custom_section.wasm", "wb") do
  # preamble
  _1.write [0].pack('C')          # 0x00
  _1.write 'asm'.bytes.pack('C3') # 0x61 0x73 0x6d
  _1.write [1].pack('I<')         # 0x01 0x00 0x00 0x00

  # custom section
  _1.write [0].pack('C')           # 0x00
  _1.write [4].pack('I<')          # 0x04 0x00 0x00 0x00
  _1.write 'hoge'.bytes.pack('C4') # 0x68 0x6f 0x67 0x65
end

これをGoogle Chromeコンパイルします。 実行するためのHTMLです。

<html>
  <title>Load wasm binary</title>
  <script>
    fetch('./custom_section.wasm')
      .then(response => response.arrayBuffer())
      .then(buffer => WebAssembly.compile(buffer))
      .then(module => console.log(module))
      .catch(e => console.error(e));
  </script>
</html>

すると次のエラーが起きます。

Google Chromeの出力したコンパイルエラー

(インデックス):8 CompileError: WebAssembly.compile(): section (code 111, "") extends past end of the module (length 103, remaining bytes 1) @+14

理由はよくわかっていません。 結論だけいうと、sizeを7にするとWebAssemblyモジュールとして認識されます。

# custom section
_1.write [0].pack('C')           
_1.write [7].pack('I<')  # 4ではなく7
_1.write 'hoge'.bytes.pack('C4')

この3バイトはどこからでてきたのでしょうか? sizeをセクションの頭から数えるなら、7ではなく8や9になりそうなものです。