8 ポイント 投稿者 GN⁺ 2023-07-24 | 1件のコメント | WhatsAppで共有
  • コンピュータでプログラムを実行すると、実際に何が起きているのかを最後まで理解しようとする個人学習プロジェクトの導入部
  • 中心となる問いは、プログラムがCPUで直接実行されるのか、システムコールがどのように動作するのか、複数のプログラムが同時に実行される仕組みへとつながっていく
  • 大学の講義の外では包括的なシステム資料を見つけにくく、品質の異なる資料や食い違う情報を自分で取捨選択する必要があった
  • 数週間にわたって調査し、ほぼ40ページ分のノートを作る中で、コンピュータが起動してからプログラム実行に至るまでの過程をより深く理解できるようになった
  • すでに知っていると感じる読者にも新しく学べることがあるかもしれないとし、時間がなければまず第3章を読むことを勧めている

プログラム実行を理解するための出発点

  • コンピュータでプログラムを実行するとき、正確に何が起きるのかがこの記事の出発点である
  • 低レベルの知識はある程度あったものの、ばらばらの断片をひとつの流れとして結びつけるのに苦労していた
  • 問いは3つの方向へと広がっていく
    • プログラムは本当にCPU上で直接実行されるのか
    • システムコールとは何で、実際にはどのように動作するのか
    • 複数のプログラムはどのように同時に実行されるのか

調査の過程と読む順序

  • 包括的なシステム資料があまりなく、複数の情報源を自分で調べる必要があり、資料ごとに品質や内容が異なっていた
  • 数週間の調査とほぼ40ページのノートを通じて、起動プロセスからプログラム実行までのコンピュータの動作をよりよく理解できるようになった
  • 目標は、自分自身が見つけたかったような、ひとつのしっかりした解説記事を自分で作ることだった
  • すでに内容を知っていると感じる読者や時間のない読者には、まず第3章を読むことを勧めている
  • 次の記事は第1章: The “Basics”へと続く

1件のコメント

 
GN⁺ 2023-07-24
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

    • 最近、自分も「こういうオンライン資料はひどすぎる」とよく思います。Linuxカーネルの詳しいブロック図、ページテーブルの動作方式、プラットフォーム別の関数呼び出しABIの比較、低レベルのネットワークプロトコルの詳細、予約済みのLinux PID番号のようなものを探すときは特にそうです
      たまにRedditのスレッドで答えを見つけますが、たいていノイズが混ざっていて、知識を保存する場所としてRedditが信頼できるのかも疑わしいです。StackOverflowは特定の作業を解決する質問が中心なので、回答も必然的に短く、特に役に立ちません
      一般的な知識については、今ではGoogleの壊れた検索を飛ばして直接Wikipediaへ行きますが、Wikipediaにも技術的なトピックをどの深さまで扱うかには限界があります。コンピュータ内部構造の詳細を包括的に集めたWikiが必要なのではないかと思います。散らばった資料はたくさんありますが、1か所にまとまると本当に良いでしょう
    • 自分もその年齢くらいで似たような疑問を持ち、Linuxのソースコードから興味深い答えをたくさん見つけました。もちろん当時はずっと単純でした。特にosdevコミュニティとIntelのシステムアーキテクチャ文書が大きなきっかけになり、記憶では3aか3bのパートに有用な情報が多かったです
      その文書は、今の世界がどうなっているかよりも、どうなり得るかをはるかに多く教えてくれます。OSDEVをやると、32ビットプロセッサがPAEで36ビットアドレッシングをしていた方法や、64ビットプロセッサがさらに稼ぐために52ビットアドレッシングをしていた方法など、面白いこともたくさん学べます
      コンピュータが16ビットモードで起動してlong modeへ到達するには、システムレベルのアセンブリの曲芸が必要になる理由や、なぜ8ビットモードが残っているのかなども分かります。バイナリローディングを学ぶのが楽しかったなら、まだまだ驚くことは多いです。例えば64ビットモードにもメモリセグメンテーションは残っていますが、long modeではフラットマッピングに強制されます
    • 素晴らしい仕事です。オペレーティングシステム開発に入門するのに良い資料で、ディテールは多いものの消化しやすいです。第2章の注釈#2の終わりの部分は少し直すとよさそうです。一部のプログラミング言語の非同期パラダイムは協調的マルチタスクである、という点を反映すべきです。プロセス内部では協調的マルチタスクを使うのは通常安全だと考えられますが、それが望ましいかどうかは別問題です。Erlangは堅牢性のためにプリエンプティブであり続けていると理解しています
  • こういう資料が好きです。最近RISC-Vの世界に足を踏み入れているのですが、自由・オープンソースソフトウェアを前に進めようとする人たちが、新しく出てくるさまざまなシングルボードコンピュータでソフトウェアをうまく動かすには、こうした知識が必要だというのは明らかに思えます

    • ちなみにRISC-Vの命令エンコーディングは、Thumb-2あたりを除けば、探究できるものの中でもかなり奇妙な部類です。そう作られたのにはもっともな理由がありましたが、ヘックスダンプを読むつもりなら、RISC-Vは手加減してくれません。他のほとんどの観点では単純だとしてもです
    • 学士以上で学んだなら、プログラマーならたいていこういう内容はすでに知っているのではないかと思います。少なくともコンピュータアーキテクチャオペレーティングシステムの授業を飛ばしていなければ
      私の場合、コンピュータがどう動作するかを学ぶ過程で、命令セットアーキテクチャを定義し、シミュレータとアセンブラを実装し、アセンブリを自分で書くことはよくありました。もっと熱心な人はFPGAで実装したり、LLVMバックエンドを書いたりもします
      オペレーティングシステムのほうも同じです。自分でカーネルを実装して学ぶ、あるいは少なくとも既存のカーネルを修正するのは、かなり一般的な過程です
  • コンピュータが非常に基礎的なレベルでどのように動作するのかをもっと知りたいなら、Charles Petzoldの本Codeを本当におすすめします。第一原理から始めて、かなり高いレベルまで進みます

    • 手を動かして作りながら学ぶほうが好みなら、Nandgame https://nandgame.comも良いです
  • この資料がうまくやっている点の1つは、情報を集める過程での予想と実際の学習結果を指摘していることです。「yのためにxだと予想したが、実際にはbのためにaだった!」というような形です
    誤解を取り除くことは、新しい知識を形成するうえで重要な段階であることが多く、読み手が情報を処理しながら自分の誤解を乗り越えなければならない、という点を筆者が認めてくれると助けになります。「これが正解で、違う考えをしていたなら愚か者」という態度より、はるかに読者に優しいです

  • 第6章にはfork()の戻り値の説明に誤りがあります。書かれている内容とは逆に、親では子のPIDが返り、子では0が返るはずです。この部分についてプルリクエストを作りました

    • 本当にありがとう、ミスでした。コード例を修正してマージしました
  • add eax, 51205 00 02 00 00 に変換されるという説明で、最初のバイト 05 は EAX レジスタに16ビットの数値を加算する opcode で、残りのバイトがリトルエンディアンの 512(0x200)だとされている
    しかし、この説明では5バイト命令のうち先頭3バイトしか説明していない。残りの 00 は何なのか気になる。おそらく opcode が EAX に32ビットの数値を加算するものだと書くつもりだったのではないか

    • 「he」ではなく「she」で、その通り。その部分は32ビットと書くべきだったようだ。よく気づいてくれた
    • x86 の話ならその通り。eax レジスタは32ビット幅で、同じレジスタの下位16ビットは 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 の制限を理解するためにカーネルの実行ロジックまで知る必要があってはならない。これは愚かな設計で、その点をもっと強調すべきだったと思う
      数年前、誰かが長すぎる shebang では少なくとも黙って失敗するのではなく、明確に失敗するようカーネルにパッチを当てようとした。ところが NixOS で問題が起きた。Nix らしく、長い nix-store パスを多用する過度に長い shebang をすでに使っていたからだ。以前は黙って切り詰められていたが、それでも動作していたのに、突然そうしたスクリプトがすべて失敗するようになり、後方互換性が壊れた。そのためパッチは戻さざるを得ず、その後同様の変更は出てこられなかった
      詳細は https://lwn.net/Articles/779997/ を参照
    • shebang に複雑な引数を入れるべきではない。shebang は現在のファイルのインタプリタの場所を示すためのものだ
      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 行で小細工を避けてきた立場からすると、せいぜい疑わしい慣行に見える
    • バッファがディスクのブロックサイズと同じに設定されていない点のほうが驚きだ。通常は512バイトだが、常にそうとは限らない