TinyWasmは、軽量なWebAssembly (WASM) ランタイム実装の学習プロジェクトです。このプロジェクトは、RustでWasm Runtimeを実装するの記事を参考にして作成されました。WebAssemblyの仕組みとRustでの実装方法を学ぶことを目的としています。
- WebAssemblyバイナリのパースと解析方法
- WebAssemblyの実行環境の構築
- WASIインターフェースの基本実装
- Rustを使った低レベルプログラミング
プロジェクトは以下のモジュール構成になっています:
-
binary
: WASMバイナリの解析とパースinstruction
: WASM命令の定義と解析module
: WASMモジュールの構造と処理opecode
: 命令のオペコード定義section
: WASMセクションの解析types
: データ型の定義
-
execution
: 実行環境runtime
: WASMプログラムの実行エンジンstore
: メモリ、関数、テーブルなどの状態管理value
: WASMの値型と操作wasi
: WASI APIの実装import
: 外部関数のインポート機能
use anyhow::Result;
use tinywasm::execution::{runtime::Runtime, wasi::WasiSnapshotPreview1};
fn main() -> Result<()> {
// WASIサポート付きでランタイムを初期化
let wasi = WasiSnapshotPreview1::new();
let wasm = include_bytes!("path/to/your/program.wasm");
let mut runtime = Runtime::instantiate_with_wasi(wasm, wasi)?;
// エントリポイント関数を実行
runtime.call("_start", vec![])?;
Ok(())
}
このプロジェクトでは、WASI(WebAssembly System Interface)の一部を学習のために実装しています。現在実装されている主な機能は以下の通りです:
- ファイルディスクリプタ(stdin, stdout, stderr)のサポート
fd_write
関数の実装(標準出力への書き込み)
WASIの初期化は以下のように行います:
// WASIの初期化 let wasi = WasiSnapshotPreview1::new(); // WASI対応のランタイム生成 let mut runtime = Runtime::instantiate_with_wasi(wasm, wasi)?;
関数名 | 説明 |
---|---|
fd_write | ファイルディスクリプタに対するデータ書き込み |
以下は「Hello, World!」を表示するWATサンプルです:
(module
;; WASIのfd_write関数をインポート
(import "wasi_snapshot_preview1" "fd_write"
(func $fd_write (param i32 i32 i32 i32) (result i32))
)
;; メモリ定義
(memory 1)
;; "Hello, World!\n"をメモリにセット
(data (i32.const 0) "Hello, World!\n")
;; メイン関数
(func $hello_world (result i32)
(local $iovs i32)
;; IOVecの設定
(i32.store (i32.const 16) (i32.const 0))
(i32.store (i32.const 20) (i32.const 14))
(local.set $iovs (i32.const 16))
;; fd_writeを呼び出し
(call $fd_write
(i32.const 1) ;; ファイルディスクリプタ (stdout)
(local.get $iovs) ;; IOVecのポインタ
(i32.const 1) ;; IOVecの数
(i32.const 24) ;; 書き込みサイズを格納する位置
)
)
;; _start関数としてエクスポート
(export "_start" (func $hello_world))
)
WATファイルはWasmバイナリに変換してから使用します:
# wat2wasmツールを使用してバイナリに変換
wat2wasm hello_world.wat -o hello_world.wasm
このプロジェクトを通じて学習した主なWASM実装:
- 基本的な命令セット(算術演算、ローカル変数操作など)
- メモリ操作
- 関数呼び出し
- WASI(WebAssembly System Interface)の基本実装
anyhow
: エラーハンドリングnom
: バイナリパーサーnom-leb128
: LEB128エンコードされた数値のデコードnum-derive
/num-traits
: 数値型の変換ユーティリティ
# ビルド
cargo build
# テスト実行
cargo test
# Hello Worldサンプルの実行
cargo run