screw-witted

なんであれ、ご指摘いただけると幸いです。

ハロー"Hello, World" 第1章 - 読書メモ

gcc オプション

$ gcc hello.c -o hello -Wall -g -O0 -static

-o : 実行ファイル名
-Wall: 警告をすべて表示する
-g: デバッグ情報を表示する
-O0: 最適化しない(gdbでデバッグするため、-O1:最適化を行う、-O2:更に最適化を行う)
-static: スタティックリンクでコンパイルする(この方が解析が楽になるらしい)

スタティックリンクってなに?

www.atmarkit.co.jp

実行ファイルを実行する際に、共有ライブラリ(.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
    カウンタレジスタ
    シフトローテート命令(?)とループ命令に使用される

  • EBP
    スタックベースレジスタ
    スタックのベースを指し示すのに使用され

  • ESP
    スタックポインターレジスタ
    スタックのトップを指し示すポインタ

アセンブリ言語を読んでみる

レジスタの使い方

%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

なんとなく、わかったような気がするだけで、全然わかってない気がする。

トレース慣れるまで苦労しそう・・・まだ第一章・・・ついていけるのだろうか。

詳しく(かつ正しく)は本に載ってる。