Binary2.0勉強会 7

二週間も間があきました。びっくり!
夏バテです。より正確には熱くてバテてるというより冷房が寒くて凍えてます。


関数を呼び出した際のスタックの動きをおさらい。
呼んだ時。

  1. ebp をスタックに退避
  2. ebp を esp に
  3. esp を必要な分だけ sub

帰る時。

  1. esp を ebp
  2. ebp をスタックから復元

でした。ということで main を見直して見ましょう。

int main(){
   0:	8d 4c 24 04          	lea    0x4(%esp),%ecx
   4:	83 e4 f0             	and    $0xfffffff0,%esp
   7:	ff 71 fc             	pushl  -0x4(%ecx)
   a:	55                   	push   %ebp
   b:	89 e5                	mov    %esp,%ebp
   d:	51                   	push   %ecx
  return 0;
   e:	b8 00 00 00 00       	mov    $0x0,%eax
}
  13:	59                   	pop    %ecx
  14:	5d                   	pop    %ebp
  15:	8d 61 fc             	lea    -0x4(%ecx),%esp
  18:	c3                   	ret    

このうち、

   a:	55                   	push   %ebp
   b:	89 e5                	mov    %esp,%ebp

  14:	5d                   	pop    %ebp

この三行が上にまとめた部分に相当するわけですが、何か他にも色々してますね。
まず、

   4:	83 e4 f0             	and    $0xfffffff0,%esp

これは esp を 16byte でアラインメント整えてますね。
アラインメント整えると値が変わってしまうので、 main 関数抜ける時には esp を元の値に戻さないといけません。どうやら ecx を使って復元しているようなのですが…何かアドレスをわざわざ +4 してますね。なんでだろー。
と思ってたのですが、よくよく考えれば main も普通に引数取るじゃん引数じゃんということに気がついた。

00000000 <main>:
int main(int argc, char *argv[]){
   0:	8d 4c 24 04          	lea    0x4(%esp),%ecx
   4:	83 e4 f0             	and    $0xfffffff0,%esp
   7:	ff 71 fc             	pushl  -0x4(%ecx)
   a:	55                   	push   %ebp
   b:	89 e5                	mov    %esp,%ebp
   d:	51                   	push   %ecx
  return argc;
   e:	8b 01                	mov    (%ecx),%eax
}
  10:	59                   	pop    %ecx
  11:	5d                   	pop    %ebp
  12:	8d 61 fc             	lea    -0x4(%ecx),%esp
  15:	c3                   	ret    

なるほど ecx は普通に第一引数指すのに使っているようです。
ということは ecx は引数のアドレスを指しつつ、ついでにその値を esp の復元にも利用している、ような感じなのかな、と。
で、これそもそも push と pop の対応が余裕で取れてないですね。なんでやねん。 esp 復元してるんで esp がずれるといった問題はないんですが、一番最初の「pushl -0x4(%ecx)」の意味が全然ないような…本来なら最後の「lea -0x4(%ecx),%esp」は「pop %esp」とされるべきだと思うのですが、どうなんだろう。スタック触るよりレジスタ間で値渡した方が早いからとか?それなら push そもそもするなよ…これだけ結局分かりませんでした。誰か偉いひと教えてください。最適化オプションつけても消えないということは必要なんだとは思うのですが…


ということで随分とかかりましたが、 0 返すだけの main をようやくアセンブラレベルで理解できましたね!わからないところあるじゃんとか言わない!
次回からは配列とか構造体とかほげろうと思います。