LoginSignup
166
131

More than 1 year has passed since last update.

めくるめくLinuxカーネルじゃないLinux実装の世界

Last updated at Posted at 2020-07-15

EDIT^7: blink と box86、FEX。

EDIT^6: Unikraft 。

EDIT^5: Tilck

EDIT^4: コメント。gVisor はすっかり忘れていました!Linuxを拡張するためにLinuxを実装した良い例だと思います。LINE有りましたね。。 SF.netのCVSはもう死んでしまったので除外にしました。。 OSvのバイナリ互換 はPIEであることが要求なので。。といっても世間的にはもうLinux = Debian/Ubuntu で良いですかね。。表現を調整しました。

EDIT^3: Noah忘れてた!

EDIT^2: Cygwinは 下書き段階で削ってしまった 。。 qemuを移植したとき に互換性がイマイチだったので。。特殊fdやprocfsの充実ぶりとかを考えると "かなりLinux" と言って良いとは思うけど、 mmap 等でLinuxとWindowsの挙動が衝突する場合はWindows側の挙動を採っているので何がなんでもLinuxを目指しているというわけでも無さそう。Win32との共存のために wchar_t が16bitsでLLP64だし。。

EDIT: Qiitaの関連リンク機能が cyanurus を見つけてきたので追記


LinuxがAPIのLingua francaとなりつつある。Linux以外のPOSIX環境への投資を正当化するのは今後も難しくなりつづけるのではないだろうか。

もちろんエスペラント語のごとく何か中立的な環境を定義してそちらに寄せるというアイデアもある。CloudABI( https://cloudabi.org/ )が正にそれで、これのWebAssembly版としてWASI( https://wasi.dev/ )が出発していることを考えるとまぁ悪くないアイデアではあるのだけど、 https://github.com/WebAssembly/WASI/issues/294 で Ed Schouten (CloudABIの開発者でFreeBSD/LLVMのコントリビュータでもある) が書いているようにCloudABIはあまり関心を引けなかった。

WSL2でWindowsがLinuxカーネルをWindowsコンポーネントの一部として取り込んでしまったことからもわかるように、 LinuxはOSの多様性を駆逐しつつあり 、経済的な合理性からこの流れを変えるのは難しいだろう。逆に、今後もシステムソフトウェアやソフトウェアプラットフォームの研究を継続するならば、実用性の面からはLinuxを意識せざるを得ないのではないだろうか。

というわけで、LinuxカーネルじゃないLinux実装特集。

カーネル/マイクロカーネル/ライブラリOS

もっともよくあるパターンはカーネルにLinuxの各種syscallを実装してLinux向けのアプリケーションを実行しようというもの。要するにLinux互換OSを作ることになる。

互換のレベルは API互換 (ソースコードをリビルドすれば実行できる) と バイナリ互換 (リビルド不要でそのまま動作する) に大別できる。いわゆる互換OSとして通常イメージされるのはWindowsのWSL1のような バイナリ互換 戦略と言える。

API互換

既存のOSに後付けでLinux機能を実装するのではなく、Linux向けのアプリケーションを動作させることを目的としたLinux互換実装。通常の意味でのバイナリ互換を実現しているのはHermiTuxのみで、OSvは中間的な実装、managarmはAPI互換実装となっている。

managarm

managarm は、64bit PCプラットフォームで動作するマイクロカーネルで、Linuxを意識したsyscall実装を提供しアプリケーションの移植性に配慮している。

実装しているsyscallは数十に留まり、完全な互換の実現には距離があるがそれでもCoreutilsやBashのようなアプリケーションが移植されて動作しているのは興味深い。

いわゆるホビーOSの枠でPOSIXを目指すものはSerenityOS( https://github.com/SerenityOS/serenity )などいくつかあるが、明示的にLinuxを目指すのは珍しい気がする。

HermiTux

ヤドカリがペンギンを挟んでいる可愛らしいロゴが印象的なHermiTuxはLinuxバイナリ互換を目指したUnikernelで、HermitCoreの上に構築されている。このHermitCoreがヤドカリをキャラクターにしている。

同じUnikernelであるOSvとの違いとして、HermiTuxはバイナリ互換であることを推している。カーネル自体を通常ユーザーランドで使用される下位側のアドレスに配置することで、アプリケーションのメモリ配置を保ったままUnikernel化を行っている。

論文では特化カーネルの構築に言及していて、そのためのバイナリ解析ツール syscall-identification も公開されている。このツールはDyninst( https://www.dyninst.org/ )でバイナリの実行領域とsyscall命令の位置、RAXレジスタの内容を検出してそれを列挙するとしている。

OSv

EDIT: 現状のバージョン はバイナリ互換としていて JREのDockerイメージから本体を抜き出して実行する デモもある。

OSvはLinuxバイナリ互換を目指したUnikernelとしては初期のもので、実行ファイルが動的executableであることを前提に直接ELFをロードして実行するデザインとなっている。このデザインを取ることで、OpenJDKのような大きなバイナリも動作させている。

OSvのLinux互換は相当な完成度で、glibcのsyscall界面やif制御等をそれなりに実装している。しかし、HermiTuxの論文で触れられているように完全なバイナリ互換を提供するものではなく、単にlibcをライブラリOSに置き換えるものと言える。このため、syscallテーブルは存在せず、ダイナミックリンカが直接executableからのAPI呼び出しをOSにリンクすることになる。

個人的にはOSvのようなデザイン(syscallレベルではなくC APIレベルのバイナリ互換)は他にも出てきて良いと思うんだけど、後述のようなアプリケーションレベル実装の方が可能性はありそうかなという気もする。

Cyanurus

UNIX/Linux互換OSをゼロから作った話 で紹介されている Cyanurus はARM32用のLinux互換カーネルのようだ。

実装範囲は非常に限定的なものの、この規模の実装でCoreutils動くのかと感動した。

Tilck

i686向けのLinux互換カーネル、実装しているsyscallは多くないもののvim等を動作させている。

Linuxでビルドすることを前提に、 ホストのsyscallテーブルを直接 #include する 割と独特なデザインになっている。まぁ互換だし良いか。

Kerla と Resea

KerlaはRust製でHNで話題に。自前のTCPスタック。

Unikraft

NEC Labs出身のunikernelでベアメタル動作がなくXenまたはKVM+QEMUと、(特徴的な)Linuxユーザランドでのエミュレーションがある。ページでは高速性を主張しているが、これを書いている時点ではSMPサポートが無く、ファイルシステムもramfsか9p程度しかない。TCP/IPスタックはpluggableで標準はlwIP。Linux userlandでの動作を実現していることからわかるように、実装手法自体はsyscallエミュレーションに近い。

syscallエミュレーション

WSL1の登場で一躍有名になったカーネルレベルでのLinuxエミュレーションは、もっとも歴史と伝統のあるLinux互換環境の実現方法と言える。

FreeBSD

WSL1の登場以前に最も著名だったのはFreeBSDのLinuxulatorではないかと思うが、最新のLinuxカーネルにはあまり良く追従していない印象がある。

syscall命令によって処理されるカーネル内のサブルーチンを差し替えることでLinuxバイナリ互換を実現している。

NetBSD

NetBSDにもLinux互換インターフェースが存在する。FreeBSDとは独立した実装となっている。

実装方法はFreeBSDと同じくsyscall tableの差し替えによって実装している。

Solaris / SmartOS

OpenSolarisのLinuxエミュレーション環境であるLxはJoyent(node.jsの開発元として知られる)が中心となって近年復活している。

Lxが独特なのは完全なカーネル実装としてLinuxエミュレーションを提供するのではなく、一部のsyscallについてはユーザ側にそのまま引き戻してライブラリレベルでのエミュレーションを行う点と言える。 inotifyfutex のような一部機能は相当機能をカーネル側に実装しそれを利用している。

Windows(WSL1)

WSL1(Windows Subsystem for Linux)はモバイル向Windowsが一時期Android互換を目指していた時期の副産物で、結局MSはモバイル市場から降りる形で放棄される形となった。

現在はVMベースで通常のLinuxカーネルを使用するWSL2が推奨されている。対して、WSL1はFreeBSDやNetBSDの実装のような完全なLinux syscallエミュレータで、これらのカーネルが実現しているsyscall tableの差し替えやABIの適合をPicoProcessと呼んでいる抽象化で実装している。

アプリケーションレベル実装

OSとしてのLinux全体ではなく、既存のLinuxアプリケーションを単発で動作させることを目的としたエミュレータ / API互換実装がいくつかある。

バイナリ互換

amd64なLinuxバイナリをWindowsで動かすというのはあまり自明なことではなく、単にAPIをエミュレーションするだけでなくスタックの使用方法を合わせるなど追加の考察が必要である種のバイナリ変換かWSL1のような特殊プロセスの導入は避けられない。この点がLinux上でWindowsバイナリを動作させるWineとの違いと言える。

Boxedwine

BoxedwineはWine専用のx86 Linuxエミュレータで、WindowsだけではなくLinuxやemscriptenにも移植されている。特にemscripten移植は最近かなりの進捗が見られ、Web上でWindowsゲームが遊べる環境として話題になるのは時間の問題だろう。

Wineをそれなりに利用可能な形で動作させるために、オーディオやOpenGLのシリアライズ等も実装している。

qemu-user

qemuにはユーザランドバイナリのエミュレーション機能があり、ARM Linuxバイナリをx86 Linuxで動作させるといったことが可能になっている。

例えば、Dockerを使ってARM Linuxを動作させるといったテクニックで使用される。qemu-userは基本的にsyscallのプロトコル変換機能なので、LinuxバイナリをLinuxで動作させる方向にしか使用できない。(比較して、ここで挙げているUsercornを除く他のプロジェクトは全てLinuxアプリをWindowsで動作させるのを目指している)

blink

blinkはコンパクトなx86-64インタプリタ/Direct-threadなJITCにCで書かれたLinux syscallエミュレータを組み合わせたもので、現状では静的リンクされたLinuxバイナリを動作させられる。同作者の"ユニバーサルlibc"である https://github.com/jart/cosmopolitan が著名だろう。blinkもこの流れで、本物のWrite Once Run Anywhereを目指している。

box86 / box64

box86やbox64はLinuxアプリケーションを動作させることを目的としたARM用のx86/x86-64 JITCエミュレータで、ユーザランドの動的ライブラリをwrapしてネイティブ側のものを無理矢理使うというなかなかのテクニックを実現している。

FEX

ランタイムアセンブラには vixl https://github.com/Linaro/vixl を採用している(ただ、自前のemitterに置き換えつつあるようだ)。syscall引数のうち未使用のものはIRレベルで除去するなどかなり気合の入った最適化が入っているが気合の割には..という印象を受ける。

Foreign Linux

Foreign Linuxは(CPUエミュレーションを伴わない)動的バイナリ変換でLinuxバイナリをWindows上で動作させることを目指すもので、残念ながらWSL1の登場以降開発が止まってしまっているようだ。

Usercorn

UsercornはqemuをベースとしたCPUエミュレータフレームワークであるUnicorn( https://www.unicorn-engine.org/ )上に構築されたカーネルエミュレータライブラリで、Linux以外にDarwinやMS-DOS( ! )まで実装している。

qemu-userと同じく完全なCPUエミュレーションを行うが、qemuとは違い Go でLinuxのAPIを再実装しているため、Linux以外でもLinuxバイナリを動作させることが可能になっている。

実装範囲はかなり限定的に見える。

Atratus

詳細不明。

LBW

InterixをWindows上のPOSIXレイヤとして使用していた。というわけでもう動作しない。

CheerpX for Flash

As a first technical application of CheerpX, we are currently focusing on Linux binaries and in particular on virtualizing the Flash binary plugin,

商用。Flash互換実装のLightspark( http://lightspark.github.io/ )の作者によるCheerpX for Flashは、Flashのx86 Linuxバイナリを実行するために自社のWebAssembly上に実装されたx86エミュレータを使用していると主張している。

同社によるLLVM backendとしてのWebAssemblyコンパイラはオープンソース提供されていて( https://www.leaningtech.com/pages/cheerp.html )、ランタイムライブラリはGPL2と商用ライセンスを提供している。

かんそう

LinuxはDockerなりなんなりの形でABIの資産価値が高まってしまっているため、ABIが今後大きく変化することは考えずらい。このため、Linuxある種の安定期を迎えていると考えることができ、Linuxを実装したい向きにはチャンスなのではないかと思う。

もっとも、今後自分が共通I/Fを実装することになるとしたらWASIを選ぶかな。。Linuxアプリをちゃんと動かすためには /proc とか ioctl なりなんなりも実装する必要があり、割と面倒なのではないだろうか。

Linux自体をアプリケーションにする試みとしては 以前USB/IPのために使ってみた LKL ( https://github.com/lkl/linux ) があるが、これにはsyscall shimもあり既存のバイナリを実行するための考察もある。なのでLKLをLinux互換レイヤのベースにするのは良いかもしれない。

今さらカーネルとか実装してどうすんのというのは有るかもしれないが、プロセスのチェックポイントやマイグレーション、再最適化のような、"Linuxを改造するよりもLinux風OSを作った方が早い" 領域があるかもしれない。Linux風環境の知見を研究することで、real worldアプリケーションと研究の距離を縮められるのではないだろうか。

166
131
4

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
166
131