WebAssembly Micro RuntimeでRustアプリをマイコンで動かす!
はじめに
前回、もう一歩のところだったのですが、RAMが2MB搭載されていないと動かない状態でした。
tomo-wait-for-it-yuki.hatenablog.com
私はそんなマイコン持っていないため、今回は、256KB RAMが搭載されているマイコン (これも高性能品ですが) 上でRustアプリを動作させます。
問題点
データセグメントが0x100000番地に配置されていることが問題でした。
$ wasm-objdump -x target/wasm32-unknown-unknown/release/hello_wasm.wasm ... Data[1]: - segment[0] size=16 - init i32=1048576 - 0100000: 4865 6c6c 6f20 6672 6f6d 2052 7573 7400 Hello from Rust.
リンカオプションによる解決
調べていると、次のissueに行き当たりました。
The large memory size here is because we default to asking LLD to allocate a 1MB stack for all Rust binaries. If you'd like to reduce that though you can pass -C link-arg=-zstack-size=16 to rustc, for an appropriate stack size for your application. That should allow you to shrink quite a bit!
LLDにスタックを1MB割り当てるようなデフォルトになっており、このサイズを減らせば良い、ということでした。
ということで、リンカにオプションを与えます。
|> .cargo/config
[target.wasm32-unknown-unknown] rustflags = [ "-C", "link-arg=-zstack-size=16" ]
ビルドします。
$ cargo build --target=wasm32-unknown-unknown --release $ wasm-strip target/wasm32-unknown-unknown/release/hello_wasm.wasm
中身を確認してみましょう。
$ wasm-objdump -x target/wasm32-unknown-unknown/release/hello_wasm.wasm hello_wasm.wasm: file format wasm 0x1 Section Details: Type[3]: - type[0] (i32, i32) -> i32 - type[1] () -> nil - type[2] () -> i32 ... Code[2]: - func[1] size=2 - func[2] size=16 <main> Data[1]: - segment[0] size=16 - init i32=16 - 0000010: 4865 6c6c 6f20 6672 6f6d 2052 7573 7400 Hello from Rust.
これでデータセグメントが0x10 (16) から置かれるようになりました。
QEMUでの動作確認
実機で試す前に、QEMUを使って、RAM 64KB搭載のCortex-M3をターゲットにして、動作確認します。 (無理矢理動かすために、WebAssembly Micro Runtimeのページサイズを4KBにしています)
$ ninja run [0/1] To exit from QEMU enter: 'CTRL+a, x'[QEMU] CPU: cortex-m3 qemu-system-arm: warning: nic stellaris_enet.0 has no peer ***** Booting Zephyr OS zephyr-v1.14.0 ***** Hello from Rust
よし!
実機動作
手元に偶然あるnRF52840-DKで動かしてみます。 RAMも256KBあるので、なんとかなるはずです。
$ mkdir nrf52840 && cd $_ $ cmake -GNinja -DBOARD=nrf52840_pca10056 .. $ ninja [10/14] Linking C executable zephyr/zephyr_prebuilt.elf Memory region Used Size Region Size %age Used FLASH: 76436 B 1 MB 7.29% SRAM: 144328 B 256 KB 55.06% IDT_LIST: 56 B 2 KB 2.73% [14/14] Linking C executable zephyr/zephyr.elf
ビルドはOKです。
minicomでUARTを受信できるようにして、ファームウェアを書き込みます。
ninja flash
Welcome to minicom 2.7.1 OPTIONS: I18n Compiled on Aug 13 2017, 15:25:34. Port /dev/ttyUSB0, 20:35:14 Press CTRL-A Z for help on special keys ***** Booting Zephyr OS zephyr-v1.14.0 ***** Hello from Rust
OK! 無事動きました!
WebAssembly Micro Runtimeの方は、次の通りです。
|> src/main.c
// デフォルトの512 KBでは実機のRAM 256KBに入らないため static char global_heap_buf[128 * 1024] = { 0 };
|> iwasm/runtime/vmcore-wasm/wasm.h
// WASMは1ページ64KBとのことなので4KBから元に戻しています #define NumBytesPerPage 65536 #define NumBytesPerPageLog2 16