アセンブリコードを色々比較

前回(http://d.hatena.ne.jp/cocoatomo/20080720)、アセンブリで遊んでからだいぶ経つが、記号の意味なども分かったので、また遊んだ結果を色々載せる。

どんどん比較していくよ。

まず、何もしない最小限の C プログラム。

int main() {}

これを gcc -S して、アセンブリコードに変換すると、

	.text
.globl _main
_main:
	pushl	%ebp
	movl	%esp, %ebp
	subl	$8, %esp
	leave
	ret
	.subsections_via_symbols

gcc -O -S して、最適化をかけると

	.text
.globl _main
_main:
	pushl	%ebp
	movl	%esp, %ebp
	popl	%ebp
	ret
	.subsections_via_symbols

となる。

さて、一応基礎知識を確認しておく。
プログラムを実行していくと、次々とローカル変数や動的に確保されたメモリ領域を使う変数が生まれては消えていくが、これらはそれぞれ「スタック」と「ヒープ」というメモリの領域に積まれる。「領域に積まれる」というのは少し嘘があって、明確に区分けされた領域に積まれるのではなく、プッシュとポップによって伸び縮みするスタック(ヒープ領域も構造はスタック)に積まれる(プッシュされる)のだ。
そして、ebp というのは extended base pointer と言って、今実行している関数のローカル変数用に使われる領域の先頭ポインタの値を保持しておくための変数だ。esp はスタックのトップを指すポインタで、関数が呼ばれたときには ebp と同じ位置を指しているが、変数の領域を確保するたびにどんどんスタックを伸ばす方向(何故かメモリの下位番地の方向)に伸びていく。関数の最後に達したときには、ebp の値が代入され関数が呼ばれた最初の状態に戻る。
因みにこのとき ebp の値も関数が呼び出された直前の状態に戻るはずだが、その情報はどこから取っているかと言うと、

pushl %ebp

で退避しておいた呼び出される直前の ebp の値を

popl %ebp

して取っているのである。ここでポップしている対象のスタックはローカル変数をしまうのと同じスタックである。
上の方のコードでは popl 命令が見えないが、

leave

ここら辺でやっているのかなぁ。未だ勉強不足……。