CPUに「You」を入れる
(cpu.land)- コンピュータでプログラムを実行すると、実際に何が起きているのかを最後まで理解しようとする個人学習プロジェクトの導入部
- 中心となる問いは、プログラムがCPUで直接実行されるのか、システムコールがどのように動作するのか、複数のプログラムが同時に実行される仕組みへとつながっていく
- 大学の講義の外では包括的なシステム資料を見つけにくく、品質の異なる資料や食い違う情報を自分で取捨選択する必要があった
- 数週間にわたって調査し、ほぼ40ページ分のノートを作る中で、コンピュータが起動してからプログラム実行に至るまでの過程をより深く理解できるようになった
- すでに知っていると感じる読者にも新しく学べることがあるかもしれないとし、時間がなければまず第3章を読むことを勧めている
プログラム実行を理解するための出発点
- コンピュータでプログラムを実行するとき、正確に何が起きるのかがこの記事の出発点である
- 低レベルの知識はある程度あったものの、ばらばらの断片をひとつの流れとして結びつけるのに苦労していた
- 問いは3つの方向へと広がっていく
- プログラムは本当にCPU上で直接実行されるのか
- システムコールとは何で、実際にはどのように動作するのか
- 複数のプログラムはどのように同時に実行されるのか
調査の過程と読む順序
- 包括的なシステム資料があまりなく、複数の情報源を自分で調べる必要があり、資料ごとに品質や内容が異なっていた
- 数週間の調査とほぼ40ページのノートを通じて、起動プロセスからプログラム実行までのコンピュータの動作をよりよく理解できるようになった
- 目標は、自分自身が見つけたかったような、ひとつのしっかりした解説記事を自分で作ることだった
- すでに内容を知っていると感じる読者や時間のない読者には、まず第3章を読むことを勧めている
- 次の記事は第1章: The “Basics”へと続く
1件のコメント
Hacker Newsの意見
これを作った本人です。読んでくれて、Hacker Newsらしくいろいろ修正点を教えてくれてありがとう。Putting the "You" in CPUはまだ鋭意作業中で、本来はもう少し磨き込み、内容を追加してから来週あたりにHNへ投稿するつもりでした
17歳で、1年前に高校を辞め、Hack Club(https://hackclub.com/)でフルタイムで働き始めました。覚えている限りずっとプログラミングをしてきて、約6年前からはプログラミングや他の関心事にもっと集中するためにホームスクーリングを始めました
すべて独学なので、大学のシステム系の授業を受けたことがなく、「何かを実行すると何が起きるのか」に対する自分の答えに納得がいきませんでした。そこでかなりの時間をかけて、できるだけ深く学び、その過程でオペレーティングシステムとハードウェアは学ぶのが本当に楽しい一方、このテーマのオンライン資料はひどいものが多いことに気づきました
調べていると、2014年の講義スライドPDFや、実際には間違っているか過度に単純化されたStackOverflowの回答に行き着くことがよくありました。そこで、この分野を独学しようとする人にとってよりよい資料になればと思い、Putting the "You" in CPUを書きました。まだSMPについて数段落追加する必要があるので完璧ではありませんが、私が見た大半の資料よりはずっと良いと思います。図や模式図も初めて作ったのですが、後ろの章に進むほど良くなり、後半のいくつかの図にはかなり自信があります
全体はGitHubでオープンソースとして公開しています: https://github.com/hackclub/putting-the-you-in-cpu
たまにRedditのスレッドで答えを見つけますが、たいていノイズが混ざっていて、知識を保存する場所としてRedditが信頼できるのかも疑わしいです。StackOverflowは特定の作業を解決する質問が中心なので、回答も必然的に短く、特に役に立ちません
一般的な知識については、今ではGoogleの壊れた検索を飛ばして直接Wikipediaへ行きますが、Wikipediaにも技術的なトピックをどの深さまで扱うかには限界があります。コンピュータ内部構造の詳細を包括的に集めたWikiが必要なのではないかと思います。散らばった資料はたくさんありますが、1か所にまとまると本当に良いでしょう
その文書は、今の世界がどうなっているかよりも、どうなり得るかをはるかに多く教えてくれます。OSDEVをやると、32ビットプロセッサがPAEで36ビットアドレッシングをしていた方法や、64ビットプロセッサがさらに稼ぐために52ビットアドレッシングをしていた方法など、面白いこともたくさん学べます
コンピュータが16ビットモードで起動してlong modeへ到達するには、システムレベルのアセンブリの曲芸が必要になる理由や、なぜ8ビットモードが残っているのかなども分かります。バイナリローディングを学ぶのが楽しかったなら、まだまだ驚くことは多いです。例えば64ビットモードにもメモリセグメンテーションは残っていますが、long modeではフラットマッピングに強制されます
こういう資料が好きです。最近RISC-Vの世界に足を踏み入れているのですが、自由・オープンソースソフトウェアを前に進めようとする人たちが、新しく出てくるさまざまなシングルボードコンピュータでソフトウェアをうまく動かすには、こうした知識が必要だというのは明らかに思えます
私の場合、コンピュータがどう動作するかを学ぶ過程で、命令セットアーキテクチャを定義し、シミュレータとアセンブラを実装し、アセンブリを自分で書くことはよくありました。もっと熱心な人はFPGAで実装したり、LLVMバックエンドを書いたりもします
オペレーティングシステムのほうも同じです。自分でカーネルを実装して学ぶ、あるいは少なくとも既存のカーネルを修正するのは、かなり一般的な過程です
コンピュータが非常に基礎的なレベルでどのように動作するのかをもっと知りたいなら、Charles Petzoldの本Codeを本当におすすめします。第一原理から始めて、かなり高いレベルまで進みます
この資料がうまくやっている点の1つは、情報を集める過程での予想と実際の学習結果を指摘していることです。「yのためにxだと予想したが、実際にはbのためにaだった!」というような形です
誤解を取り除くことは、新しい知識を形成するうえで重要な段階であることが多く、読み手が情報を処理しながら自分の誤解を乗り越えなければならない、という点を筆者が認めてくれると助けになります。「これが正解で、違う考えをしていたなら愚か者」という態度より、はるかに読者に優しいです
第6章にはfork()の戻り値の説明に誤りがあります。書かれている内容とは逆に、親では子のPIDが返り、子では0が返るはずです。この部分についてプルリクエストを作りました
add eax, 512が05 00 02 00 00に変換されるという説明で、最初のバイト05は EAX レジスタに16ビットの数値を加算する opcode で、残りのバイトがリトルエンディアンの 512(0x200)だとされているしかし、この説明では5バイト命令のうち先頭3バイトしか説明していない。残りの
00は何なのか気になる。おそらく opcode が EAX に32ビットの数値を加算するものだと書くつもりだったのではないかaxと呼ぶ良い記事だ。独学のWeb開発者として、こういう資料は非常に価値があると感じる。さまざまな抽象化から離れて、実際に物事がどう動いているのかをより具体的に理解する助けになる
良い資料に見えるし、かなり早く核心に入り、少し面白さもある。予想していたよりは「モナドチュートリアル」っぽくない。もっと読んでみるつもり
良い資料だ。ただ、カーネルについて一つ疑問が残る。[0] では shebang はカーネルで処理され、ファイル全体をロードせず
bufから取得するため、常にbufの長さで切り詰められると説明している4年前、カーネルが128文字を超えるパスを切り詰めることにいら立った誰かが、バッファサイズを2倍にして切り詰め位置も2倍にしたという。だから現在の Linux では shebang 行が256文字を超えると、256文字以降は完全に消える
なぜ誰かのファイルパスを黙って切り詰めるのか分からない。ほかでもないカーネルがそんなことをすべきではない。256バイトのファイルパスはおかしいかもしれないが、256バイトのパス+引数文字列はいずれほぼ確実に出てくる。スクリプトを黙って壊すのは間違っている
[0]: https://cpu.land/how-to-run-a-program
数年前、誰かが長すぎる shebang では少なくとも黙って失敗するのではなく、明確に失敗するようカーネルにパッチを当てようとした。ところが NixOS で問題が起きた。Nix らしく、長い nix-store パスを多用する過度に長い shebang をすでに使っていたからだ。以前は黙って切り詰められていたが、それでも動作していたのに、突然そうしたスクリプトがすべて失敗するようになり、後方互換性が壊れた。そのためパッチは戻さざるを得ず、その後同様の変更は出てこられなかった
詳細は https://lwn.net/Articles/779997/ を参照
shebang はそれ自体では引数を1つ以上まともに扱うこともできない。
#!/bin/program -args somescriptと書くと['/bin/program','-args somescript']に分割されるが、ほとんどの場合これは望んだ結果ではない。これは Linux 限定であり、shebang がすべての Unix で普遍的に移植可能なわけでもない複雑なことをしたいなら
#!/bin/shにしておき、現在のファイル内で必要な引数を付けてexecするほうがよいリンクで抜けている点が一つあり、
envを使えば現在のパスからインタプリタを探せる。たとえば#!/usr/bin/env python3は、ユーザーが使っているpython3を、その場所を知らなくても見つけてくれるこれは Python インタプリタへの
PATHを上書きして動作する仮想環境で実行するスクリプトに役立つことがある。ただし、インストールされるプログラムでこうすべきではない。インストール済みプログラムがユーザーにどのインタプリタを使うかを制御させてはならないため、絶対パスを使うべきだenvには-Sオプションがあり、この制限に対処するため単一文字列からコマンドラインをパースできる。それでも、長年 shebang 行で小細工を避けてきた立場からすると、せいぜい疑わしい慣行に見える