LoginSignup
7
6

More than 5 years have passed since last update.

x86-64 アセンブリ読んでみる -O0

Posted at

Cのコード

  void f(){
    printf("a\n");
  }

  int main(){
    f();
    return 0;
  }

アセンブリコード
コンパイラはicc 14.0.3
コンパイラオプションは -O0 -g

  0000000000400514 <f>:
  400594:       55                      push   %rbp
  400595:       48 89 e5                mov    %rsp,%rbp
  400598:       48 83 ec 10             sub    $0x10,%rsp
  40059c:       b8 3c 08 40 00          mov    $0x40083c,%eax
  4005a1:       48 89 c7                mov    %rax,%rdi
  4005a4:       b8 00 00 00 00          mov    $0x0,%eax
  4005a9:       e8 ba fe ff ff          callq  400468 <printf@plt>
  4005ae:       89 45 f0                mov    %eax,-0x10(%rbp)
  4005b1:       c9                      leaveq
  4005b2:       c3                      retq
  4005b3:       90                      nop
  0000000000400554 <main>:
  400554:       55                      push   %rbp
  400555:       48 89 e5                mov    %rsp,%rbp
  400558:       b8 00 00 00 00          mov    $0x0,%eax
  40055d:       e8 b2 ff ff ff          callq  400514 <f>
  400562:       b8 00 00 00 00          mov    $0x0,%eax
  400567:       c9                      leaveq
  400568:       c3                      retq

動作を理解していく。
まずmainから

  400558:       b8 00 00 00 00          mov    $0x0,%eax
  40055d:       e8 b2 ff ff ff          callq  400514 <f>

eaxレジスタは戻り値を渡すのに使われるらしい。
でも400558で初期化するのは無駄な気もする。
そして、callqで400514 fに飛ぶ

  400514:       55                      push   %rbp
  400515:       48 89 e5                mov    %rsp,%rbp
  400518:       48 83 ec 10             sub    $0x10,%rsp

callerのベースポインタを退避して、callerのスタックの若いほうにcalleeのスタックを積む

  40059c:       b8 3c 08 40 00          mov    $0x40083c,%eax
  4005a1:       48 89 c7                mov    %rax,%rdi
  4005a4:       b8 00 00 00 00          mov    $0x0,%eax

.rodataセクションに埋め込んである"a\n\0"のアドレスをeaxに入れる。
raxを引数用レジスタrdiに入れる。
引数渡し用のレジスタはrdi/rsi/rdx/rcx/r8/r9の順に使われる。
これも直接rdiにアドレスを書き込めば良いような気がする。
やはりeaxを初期化する。

  4005a9:       e8 ba fe ff ff          callq  400468 <printf@plt>
  4005ae:       89 45 f0                mov    %eax,-0x10(%rbp)

printfを読んで返り値をレジスタに入れる。

  4005b1:       c9                      leaveq
  4005b2:       c3                      retq

rbp,rspをcallee側で戻して返る。
-O2を付けたら、かなり大胆に変わったので、次はそれを読む。

7
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
6