こんにちは、 @kz_morita です。
今回は、プログラムはなぜ動くのかという本を読んだので、その感想を書いていきます。
プログラムはなぜ動くのか 第2版 知っておきたいプログラムの基礎知識全体的な概要
この本は、普段書いているプログラムが PC 上でどのような原理で動作するのか?といったことが書かれている本になります。
プログラムを 命令
と データ
にわけ、CPU がどのように命令を解釈するのか?や、データはどうメモリに配置されるのか?などが平易な文章で書かれているので Computer Science にぴったりな本だと思いました。
第 1 章では、プログラムにおける演算や、条件分岐、繰り返しなどがどのように CPU で解釈されるかや、演算に使われるレジスタの紹介などが書かれています。
第 2 章、第 3 章, 第 4 章ではデータをコンピュータ上でどう表現するかが書かれています。データの 2 進数での表現や 2 の補数や、算術演算、論理演算について知ることができます。不動小数点についてもこの章で学ぶことができます。 メモリ上でのデータの表現として、スタック、キュー、ポインタ、リスト、2 分探索木などのデータ構造の紹介もされています。
第 5 章、第 6 章ではメモリとディスクの関係性について書かれています。プログラムが実行時にディスクからメモリにロードされることや、ディスクキャッシュ、仮想メモリ、ページイン、ページアウトなどについても概要を知ることができます。
ディスクについてはその物理構造であるセクタ、クラスタなどの紹介がされています。
また、メモリを節約するという文脈で、Dynamic Link,や Static Link や、データの圧縮法(ランレングス符号化、ハフマン符号化)が簡潔に紹介されています。
第 7 章、第 8 章では、プログラムの動作環境としての、OS とハードウェアや、ソースコードを実行ファイルになるまでのコンパイラや、リンカについて説明がなされています。
プログラムを実行するために、ディスクからメモリにロードし、変数の領域、関数の領域、スタック領域と、ヒープ領域が確保され、再配置情報から実行時のメモリアドレスが決まることについて書かれています。
第 9 章、第 10 章、第 11 章では、アプリケーションがどのように OS 上で動き、また、ハードウェアを制御したりするかが書かれています。
OS がアプリケーションに API を提供し、ハードウェアが抽象化されていることや、高級言語がどのようにアセンブリコードに変換されるかや、CPU からハードウェアをどのように制御しハードウェアからの割り込み要求を CPU がどう扱うかなどの外観を掴むことができます。
第 12 章では、コンピュータに思考させることについての概要とそれに関連する擬似乱数についてなどが書かれています。
感想
まず読み終わってはじめに思ったのは、大学時代に読んでおきたかったなぁというものでした。読んでいて楽しかったです。
本自体は CS を専攻していない方でも読みやすいように工夫されて書かれているという印象を受けました。 書いてある内容としては、二進数やデータの表現方法などから、CPU、レジスタ、メモリ、ディスク、OS などを広く浅く取り扱っていました。
特に自分は、10 章の「アセンブリ言語からプログラムの本当の姿を知る」がとても面白かったです。
その際に手元でいろいろ試して、アセンブリを眺めてたらいろんな知見がありました。 その時のツイートを載せておきます。
gcc でビルドしたアセンブリの pushq みたいな q がつくやつは、64bit 演算なのか。
— kz_morita 𓆏 (@kz_morita) January 13, 2020
movl みたいな、 xxl が着くのは 32bit 演算。
ふむふむ
お、これか?
— kz_morita 𓆏 (@kz_morita) January 13, 2020
b = byte (8 bit).
s = single (32-bit floating point).
w = word (16 bit).
l = long (32 bit integer or 64-bit floating point).
q = quad (64 bit).
t = ten bytes (80-bit floating point).https://t.co/LYa0BnnNmM
関数の先頭にある
— kz_morita 𓆏 (@kz_morita) January 13, 2020
pushq%rbp
movq%rsp, %rbp
で、スタックポインタの位置にベースポインタを設定しておくのか。
そんでもって関数の終わりにあるやつ
popq%rbp
retq
で関数のスコープ抜けるときに、ベースポインタ元に戻してるっぽい。なるほど。
あぁ、関数のスコープ内のローカル変数への代入が、movl 数値 -8(%rbp) みたいな構文なのか!
— kz_morita 𓆏 (@kz_morita) January 13, 2020
関数の中で、
int a = 123;
って書いたら、
movl $123 -8(%rbp)
ってなったからどうやらそれっぽい。
-8は int が 8byte (64bit) として解釈されてるからか。。
あぁ、これ push, popを movl で実装してるのか!
— kz_morita 𓆏 (@kz_morita) January 13, 2020
ふに落ちたわ https://t.co/9ehXvSdl5S
実際に、簡単な C 言語のソースコードを書いて、アセンブリを表示してみて眺めてたのですが高級言語の演算がアセンブリでどのように表現されているのかいろいろ試しながら確認できたのはとてもよかったです。 普段何気なく動いているアプリケーションの裏側を覗いてみるのは個人的にとても楽しい娯楽で良い体験でした。
低レイヤーへと足を踏み入れる際の第一歩として良さそうなこの本を読み、低レイヤーについてもっと深く知りたいと思ったので、引き続きいろいろ頑張っていこうと思います。