V6 Interpreter (Nagoya Geek Bar 2011-05-02)
-
Upload
7shi -
Category
Technology
-
view
1.978 -
download
0
description
Transcript of V6 Interpreter (Nagoya Geek Bar 2011-05-02)
UNIX V6 インタプリタ
七誌
自己紹介
• 典型的な社内ニート(たまにVBA程度)
• プログラミングはほとんど趣味–良いネタができたら独立・・・と考えて早10年
–自然言語処理がやりたかったけど、さっぱり
• みんなで自作のおもちゃコンパイラを作って、自作のおもちゃOSを作って遊びたい!
• コンパイラを作るにはバイナリの知識が必要• そのため準備としてPE勉強会を主催
自作コンパイラ
• 4年くらい掛けて独自言語コンパイラのセルフホスティングに到達
–セルフホスティングする前はC#で書いた
• ある程度できてから、独自言語でコンパイラを書き直そうとして挫折
• 2年くらい放置した後、C#から独自言語にトランスレートすれば良いと気付いた
• こういう遊びを広めたい!
最初の失敗
• あれもこれも!• セカンドシステム症候群
独自言語
コンパイラ
のEXE
サンプル
(独自言語)
EXE
コンパイラ書き直し
(独自言語)
独自言語
コンパイラ
のソース
(C#)
C#コンパイラ
タイムスタンプ以外
完全一致!
トランスレート
独自言語
コンパイラ
のEXE
C#から独自言語へのトランスレータ
独自言語
コンパイラ
のEXE独自言語コンパイラ
のソース(独自言語)
独自言語コンパイラ
のソース(C#)C#
コンパイラ
セルフホスティング
独自言語
コンパイラ
のEXE
OS遊び
• 2年ほどFreeBSDをメインにしていたけど、巨大過ぎて内部には手が付けられなかった
• MINIXがシンプルで良いと思ったので、PEからa.outに変換するツールを作って、VC++で吐いたEXEを変換して動かしてみた– カーネルもVC++でビルドできるようにはなったけど、アセンブリをACKからMASMに書き換える際に間違えたらしく、うまく動かなかった
– カーネルハックには到達できず挫折
UNIX V6
• 1975年頃の古いUNIX– コンパイラ+カーネルのセットとしてはMINIXよりも遥かにコンパクトで手頃だと思った
• 解説書のLions本は持っていたけど、どこから読めば良いのかよく分からず放置
• そんなとき読書会が始まった!– PDP-11のアセンブリが読めなくて脱落寸前
• 慣れるため、simh(エミュレータ)でV6を動かして、ハローワールドを書いて遊んだりした
V6のファイルシステム
• ハローワールドをディスクイメージから取り出して、バイナリを分析したい
• TCP/IP実装前でネットワークはない
• 仕方ないのでカーネルのソースを見ながらディスクイメージを分析して、ファイルを取り出
すツールを作った
• VFS以前の時代で、lsがディレクトリエントリをユーザー側で読んでいるのが衝撃的
V6FS
• F#で作った自作のファイル抜き出しツール• 最初はWindows FormsのGUIアプリ• GUIアプリって気軽に試しにくいよね
–ダウンロード→展開→実行– ClickOnceではインストールされてしまう– Windows以外ではmonoで動くけど、monoはなかなか普及しない
• とりあえずブラウザで動かすためSilverlight
F#
• とにかく構文が簡潔–セミコロンやブロックのブレースが不要
• REPL標準装備
• クラスを作らずにコードをベタ書きできる– C#だと必ずクラスで囲まなければいけない
class Test { static void Main() { … } }
• モジュールをopenすれば接頭辞が不要– C#だとstaticメソッド呼び出しにクラス名が必要– VB.NETでもできるけど
Silverlight
• Webページに貼り付けるプラグイン• MS版Flashというかアプレットみたいなもの
–実は.NET 1.0の頃からアプレットは作れた–誰も使わない、MSも推奨しない
• GUI以外のコードが流用できるので、.NETアプリをWebに貼り付けるのが手軽
• サーバー側に処理を組み込まなくても、ローカルに閉じた擬似ファイル送受信が可能
–ディスクイメージ→ファイル抜き出しに使用
ツールを作ったけど
• いちいちファイルを取り出すのが面倒• V6の外でコンパイラが動けば済むのでは?
–バイナリ分析が目的なので、必ずしも実行できなくても構わない
• gccはpdp11-aoutターゲットをサポート– V6のコードはK&R以前の古いC言語でgcc非互換、アセンブラもgasとは非互換
• V6のcc/asがどうしても必要!
移植戦略
• ccを今のC言語で書き直すのは、頑張ればできると思った
• しかしasはフルアセンブラ
• さてどうしよう・・・?
1. アセンブリを解読しながら高級言語に翻訳2. 文法を真似て互換アセンブラを開発3. インタプリタを作って動かす←採用
PDP-11インタプリタ
• 初めに逆アセンブラを作成• 当初はGUIアプリとSilverlightを並行開発
–すぐに面倒になりSilverlightに一本化
• 逆汗の分岐をコピペして実行に書き換え– PDP-11はアドレッシングモードが豊富で、初めは理解が曖昧だったので苦労した
–動いた解釈が正しいというのが判断基準
–ひたすらログを目視でトレース
• 開発言語はVB.NET(ぇ
VB.NET
• ごめんなさい、ぬるい人間にF#はきつい!• 言語ではなくIDEのサポート不足が問題
–補完が微妙とかは許容範囲内– 「すべての参照の検索」 ができないのは致命的
• C#の好きじゃない点もVB.NETならクリア–セミコロンを打たなくて良い
–モジュールの接頭辞を省略できる– VB10なら次の行への継続も自動判断
• VB9までこれができないのでC#を使っていた
コマンドライン版
• Silverlight版インタプリタでcc/asが動いた
• カーネルをビルドしていじるには、結局ローカルのコマンドラインじゃないと不自由
• 当初はVB.NETのコードでコマンドライン版を作ろうと思っていたけど、Lions本読書会の参加者に.NET愛好者はいない!
• 仕方ないので読書会前日にC++で作り直し• V6カーネルのビルドができるのを確認
C++
• POSIX前提にInterix上で開発– NetBSD, FreeBSD, Mac OS Xで動作確認
• C++0xとかboostはなし–依存ライブラリなしに、OSデフォルトのコンパイラでサクっとビルドできるようにしたい
– FreeBSDはGPL3避けのためgcc-4.2系で更新を停止している(clang待ち)
• STLを使った10年くらい前のスタイルで開発– STLすら使えない環境は・・・ごめんなさい
Interix
• MSが買収して公式になったPOSIXサブシステム
• Interix上のV6インタプリタでカーネルをビルドするとsimhの5倍くらい遅い
• VMware上のNetBSDではsimhとほぼ同じ速度• InterixのオーバーヘッドはCygwinほどではないと思っていたけど、これは酷い
– Vista以降はUltimate/Enterprise縛りがあって人に薦められないので、個人的にはMSYSに移行する予定
• 仕方ないのでWin32ネイティブに移植すると、simhとほぼ同じスピードが出た
システムコール
• cc/asを動かすのに必要なものだけ実装–標準出力/ファイル入出力/fork/exec
• 標準出力のシステムコールで出力した文字をテキストボックスに表示するだけ
– トレースでV6のprintf()がデフォルトでバッファリングせずに一文字ずつ出力しているのがわかる
• Silverlight上でのファイルはRAMディスク–実態は単なるフルパスのハッシュテーブル
fork/exec (1)
• これが一番厄介だった• Silverlight、POSIX、Win32それぞれ別実装• POSIXではforkは実際にフォーク(プロセスのコピー)、execはVM内でのシミュレート
• SilverlightとWin32はネイティブプロセスには触れずに完全にVM内でのシミュレート–原理的には実装を同じにできる–そうなっていないのは、Silverlightでの実装が稚拙で、Win32を実装したとき改良したため
fork/exec (2)
• V6のforkは子プロセスはコピー後そのまま実行し、
親プロセスは命令を1つ飛ばして続行
• Lions本読書会で教えてもらった
–教えてくれた方は、この仕組みを解読するのにとて
も苦労したとのこと
_fork:_fork:_fork:_fork:
movmovmovmov r5,r5,r5,r5,----(sp)(sp)(sp)(sp)
movmovmovmov sp,r5sp,r5sp,r5sp,r5
sys forksys forksys forksys fork
brbrbrbr 1f1f1f1f
becbecbecbec 2f2f2f2f
jmpjmpjmpjmp cerrorcerrorcerrorcerror
1:1:1:1:
movmovmovmov r0,_par_uidr0,_par_uidr0,_par_uidr0,_par_uid
clrclrclrclr r0r0r0r0
2:2:2:2:
movmovmovmov (sp)+,r5(sp)+,r5(sp)+,r5(sp)+,r5
rtsrtsrtsrts pcpcpcpc
親
子
fork/exec (3)
• POSIXではホストのネイティブのforkを使ってインタプリタのプロセスを実際にfork後、親プロセス側のVMのPCをいじって対応
プロセス(親)
sys fork
PC += 2
本物のfork
プロセス(子)
VM
VM
fork/exec (4)
• Silverlightではcc/asに特化した小細工で実装
• 子はすぐexecして親はそれをwaitするパターン
• execでVMのインスタンスを作り、exit後にfork時点にロールバックして続行
• シングルスレッド実行のためwaitは素通り
sys fork
PC += 2
sys wait
sys exec
sys exit
プロセス
VM(親)
VM(子)
fork/exec (5)
• Win32にはネイティブのforkはないため、VMのインスタンスをコピーして擬
似的にforkを再現• execはVMのメモリイメージを書き換えて再現
• シングルスレッド実行のため、Silverlightと同じようにwaitは素通り
• Silverlightの改良モデル
sys fork
PC += 2
sys wait
sys exec
sys exit
プロセス
VM(親)
VM(子)
オチ
• 読書会の参加者から既存のユーザーモードシミュレータが存在すると教えてもらった
– apouthttp://puszcza.gnu.org.ua/software/apout/
• 存在を知っていたら、作らなかったと思う• せっかく作ったので、ユーザーモードとカーネルモードの特定の遷移をモデル化して抽出す
るなど、学習に特化した方向で発展させたい
最後に
• V6関係は手探りだったけど、状況がわかってかなり開けてきた感じ
• まごろくさんのV7の説明を聞いて、基本的な部分はほとんど同じだと感じた
–読書会でV6のバグじゃないかと指摘された部分がV7で直されていたりして面白い
– BSD派なのでV6からBSDを追いたいかも
• コンパイラ・OS自作にフィードバックしたい–あれ、自然言語処理はいつになったら・・・
ご清聴ありがとうございました