ハロー"Hello, World" 第1章 - 読書メモ
gcc オプション
$ gcc hello.c -o hello -Wall -g -O0 -static -o : 実行ファイル名 -Wall: 警告をすべて表示する -g: デバッグ情報を表示する -O0: 最適化しない(gdbでデバッグするため、-O1:最適化を行う、-O2:更に最適化を行う) -static: スタティックリンクでコンパイルする(この方が解析が楽になるらしい)
スタティックリンクってなに?
実行ファイルを実行する際に、共有ライブラリ(.so: shared object file, .dll: dynamic link library)がなくても動くようにするためのオプション。
アセンブリ言語ってなに
こんなの
〜前略〜 080482bc <main>: 80482bc: 55 push %ebp 80482bd: 89 e5 mov %esp,%ebp 80482bf: 83 e4 f0 and $0xfffffff0,%esp 80482c2: 83 ec 10 sub $0x10,%esp 80482c5: 8b 45 0c mov 0xc(%ebp),%eax 80482c8: 8b 10 mov (%eax),%edx 80482ca: b8 0c 36 0b 08 mov $0x80b360c,%eax 80482cf: 89 54 24 08 mov %edx,0x8(%esp) 80482d3: 8b 55 08 mov 0x8(%ebp),%edx 80482d6: 89 54 24 04 mov %edx,0x4(%esp) 80482da: 89 04 24 mov %eax,(%esp) 80482dd: e8 7e 10 00 00 call 8049360 <_IO_printf> 80482e2: b8 00 00 00 00 mov $0x0,%eax 80482e7: c9 leave 80482e8: c3 ret 80482e9: 90 nop 80482ea: 90 nop 80482eb: 90 nop 80482ec: 90 nop 80482ed: 90 nop 80482ee: 90 nop 80482ef: 90 nop 〜後略〜
・・・これを読むのか、パーになりそうだ。
レジスタってなに
CPUに備えられてる(グローバル?)変数の様なもの。
x86には下記のレジスタがある。
X86アセンブラ/x86アーキテクチャ - Wikibooks
EAX
アキュムレータレジスタ
算術演算操作の結果が格納されるEBX
データレジスタ
算術演算操作とI/O操作に使用されるECX
カウンタレジスタ
シフトローテート命令(?)とループ命令に使用される
アセンブリ言語を読んでみる
↓レジスタの使い方
%eax レジスタが保持する値 (%eax) レジスタが保持する値(アドレス)が指すメモリに格納された値 0xc(%ebp) EBPレジスタが保持する値に 0xc(12) を加算した結果をアドレスとして扱い、 そのアドレスに対応するメモリ上の値
↓アセンブラ読解
push %ebp EBP(スタックベースレジスタ)に値を積む 具体的にはスタックポインタを 4 だけ減算(スタックを 4byte 拡張)して スタックポインタのさす先のメモリ上にスタックベースレジスタの値を書き込む mov %esp,%ebp スタックポインタの値をスタックベースレジスタに代入 and $0xffffff0,%esp ESP(スタックポインタ)の値に 0xFFFFFFF0 を論理積を掛け、ESPに代入する スタックポインタを16バイト境界に(16の倍数に)そろえている sub $0x10,%esp スタックポインタの値から 0x10 を減算し、スタックポインタに格納する (16byteのスタックフレームを獲得している: ESP値 - 10 = 16byte 確保?減算する値はESPの値に応じて変わる?) mov 0xc(%ebp),%eax スタックベースポインタの値に 12 を加算したアドレスの値 (一区切り目の末尾1byte:関数(printf?)からの戻り先アドレス)をアキュムレーターに代入する mov (%eax),%edx 関数からの戻り先アドレスを データレジスタに代入する mov $0x80b360c,%eax アキュムレータに $0x80b360c という値を代入する mov %edx,0x8(%esp) スタックポインタが持つ値に 8 を加算したアドレスに データレジスタが持つ値を代入する mov 0x8(%ebp),%edx スタックポインタが持つ値に 8 を加算したアドレスが持つ値を データレジスタに代入 mov %edx,0x4(%esp) データレジスタが持つ値を スタックポインタが持つ値に 4 を加算したアドレスに代入する mov %eax,(%esp) アキュムレータが持つ値($0x80b360c)を スタックポインタが持つアドレスに代入する call 8049360 <_IO_printf> 関数呼び出し 〜前略〜 08049360 <_IO_printf>: レジスタの値でなんかやってる 〜後略〜 leave 関数のexit 的な何か(?) ret return nop なにもしないなにか
メモリのイメージ(2命令目以降)
合っているのか不安です
関数戻り値(第一引数のアドレス) | 第三引数 | 第二引数 | 第一引数 |
---|---|---|---|
スタック(4byte) | スタック(4byte) | スタック(4byte) | スタック(4byte) |
esp +12 | +8 | +4 | +0 |
なんとなく、わかったような気がするだけで、全然わかってない気がする。
トレース慣れるまで苦労しそう・・・まだ第一章・・・ついていけるのだろうか。
詳しく(かつ正しく)は本に載ってる。