AssemblyでもWebAssemblyを書きたい
はじめに
Assembly (以下アセンブリ)でも WebAssembly (以下 Wasm) を書きたいと思ったのですが、そのようなツールは調べた限りありませんでした。
そのため自分でアセンブリから Wasm を書くツールを作ろうと思いました。
と思っていたのですが意外と難航していたので Cursor という AI エディタの力を使って作成しました。
作成したツール
https://github.com/famasoon/asm2wasm
Assembly という名を冠している WebAssembly を果たしてアセンブリで書けるのかという疑問を解消するために作成しました。
C++ を使用して x86 アセンブリから Wasm を生成するコードを作成しました。
とは言うものの、アセンブリを素直に解析してくれる基盤はなかなか見つからなかったです。
リフターというものを使用すればアセンブリを解析できますが、リフターはいまのところバイナリファイルの対応をしているものばかりで、asmコードを解析するものは私が調べた限り見つかりませんでした。
仕方がないので簡易的なアセンブリのパーサと、パースしたアセンブリの命令をLLVM IRに変換するコードを書き、そこからさらに Wasm に変換するコードを書きました。
asm2wasm/build on master [?] via △ v3.28.3
❯ cat ../examples/simple_add.asm
start:
mov %eax, 10
mov %ebx, 20
add %eax, %ebx
ret
asm2wasm/build on master via △ v3.28.3
❯ ./asm2wasm ../examples/simple_add.asm
Output files are not specified, using ../examples/simple_add.wasm and ../examples/simple_add.wat
Parsing Assembly file: ../examples/simple_add.asm
Outputting WebAssembly binary: ../examples/simple_add.wasm
Outputting WebAssembly text: ../examples/simple_add.wat
Generated WebAssembly text:
----------------------------------------
(module
(memory 1 65536)
(func $start (result i32) (local $0 i32) (local $1 i32) (local $2 i32) (local $3 i32) (local $4 i32) (local $5 i32) (local $6 i32) (local $7 i32)
local.get 1
i32.const 10
i32.store
local.get 0
i32.const 20
i32.store
local.get 1
i32.load
local.set 2
local.get 0
i32.load
local.set 3
local.get 2
local.get 3
i32.add
local.set 6
local.get 1
local.get 6
i32.store
local.get 1
i32.load
local.set 4
local.get 4
return
)
)
----------------------------------------
WebAssembly conversion completed.
シンプルに加算を行う start 関数を Wasm に変換しています。
まだまだバグだらけ、最適化できそうな箇所も多く残っていますが、アセンブリから Wasm を生成できることが確認できました。
Cursor での開発
Cursor での開発はとても便利でした。
特に AI エディタの力を借りることで、LLVM IR の生成を自動で行ってくれました。
これといったコンテキストエンジニアリングもしていません。
エラーや最適化できそうな箇所を見つけたら都度修正するようにエージェントに指示を出していったら、あっという間に修正が完了しました。
まとめ
アセンブリから Wasm を生成するツールを作成しました。
ですが、かなりしんどいので C/Zig/Tiny Go なりで Wasm を書く方が楽だと思います。
Discussion