WebAssembly上でのシステムコールの扱い、および現時点でのEmscriptenで既存Cライブラリの移植性がどこまで担保されているのか、調べた内容をまとめます。
WebAssemblyとEmscriptenの守備範囲
WebAssemblyでは実行バイナリのフォーマットや利用可能オペコードなどは定義されていますが、守備範囲は仮想CPUの周辺領域までだというのが筆者の理解です。つまり、WebAssemblyのレイヤでシステムコールや標準Cライブラリが提供されるようなことはないはずです。
しかし、システムコールやlibcが無ければ既存のC資産は全く使い物になりません。なければ作るしかないということで、Emscriptenでは軽量libc実装のmuslを採用しており、これを静的リンクしてwasmファイルを生成しています。また、システムコールについてはJavaScriptで実装して提供しています(下記ファイルを参照)。
- https://github.com/kripken/emscripten/blob/master/src/library.js
- https://github.com/kripken/emscripten/blob/master/src/library_syscall.js
- https://github.com/kripken/emscripten/blob/master/src/library_signals.js
このような努力のおかげで、Emscriptenでは既存のC資産がそれなりにビルドできる環境を提供できているわけです。
Emscriptenでのシステムコール実装の概要
Emscriptenで実装されているシステムコールはLinuxのものです。世間的にもLinux対応のCソースコードが多いはずですから、この方針自体は問題ないでしょう。もっとも、これはビルドエラーを避けてギリギリ動かすための実装であり、普通のOSのような動きをするわけではありません(OSが動いていない以上当然ですが)。
システムコールのエミュレーション実装を見ると、ネットワーク系とファイルシステム系についてJSの世界で可能な範囲で実装しているほかは適当な値を返すものが多い印象です。
たとえば、uidやgidは常に0を返します。また、uname(2)
は次のように独自の文字列を返します。ちょっと面白いですね。
__syscall122: function(which, varargs) { // uname
var buf = SYSCALLS.get();
if (!buf) return -ERRNO_CODES.EFAULT
var layout = {{{ JSON.stringify(C_STRUCTS.utsname) }}};
function copyString(element, value) {
var offset = layout[element];
writeAsciiToMemory(value, buf + offset);
}
copyString('sysname', 'Emscripten');
copyString('nodename', 'emscripten');
copyString('release', '1.0');
copyString('version', '#1');
copyString('machine', 'x86-JS');
return 0;
},
必ずエラーを返すシステムコールたち
どんなシステムコールが実装できないのか傾向を知るため、現時点のEmscriptenの実装でエラーを返すシステムコールを列挙してみます。
常にENOSYS (Function not implemented)を返すもの
- raise
- pipe
- acct
- setitimer
- mincore
- pselect
- pipe2
常にEAGAIN (Resource temporarily unavailable)を返すもの
- fork
- vfork
常にENOEXEC (Exec format error)を返すもの
- execve
常にECHILD (No children)を返すもの
- wait
- waitid
- waitpid
- wait3
- wait4
常にEPERM (Not super-user)を返すもの
- kill
- killpg
- nice
- setpriority
- setdomainname
- stime
そもそもコンパイル時にエラーや警告が出るもの
現時点では未実装のものがチラホラあるようです。実装する意味があるかは疑問ですが。
- ptrace
- mount
- umount
- umount2
まとめ
既存のC資産を移植するような観点でEmscriptenの実装について調べてみました。プロセス関連のシステムコールはほぼ全滅ですが、それ以外はそれなりに動きそうです。これなら移植も捗りそうですね。