スタックフレーム続き
とりあえず gcc -S してみた。
まずはmain部をretするまで。
main: leal 4(%esp), %ecx andl $-16, %esp pushl -4(%ecx) pushl %ebp movl %esp, %ebp pushl %ecx subl $20, %esp movl $printf, 8(%esp) movl $main, 4(%esp) movl $.LC1, (%esp) call printf movl $4, 12(%esp) movl $3, 8(%esp) movl $2, 4(%esp) movl $1, (%esp) call func addl $20, %esp popl %ecx popl %ebp leal -4(%ecx), %esp ret
呼び出される側の、printfのための準備の直前までとprintf呼出後retまで。
func: pushl %ebp movl %esp, %ebp pushl %edi pushl %esi pushl %ebx subl $124, %esp # 中略 call printf movl -20(%ebp), %eax addl $124, %esp popl %ebx popl %esi popl %edi popl %ebp ret
いくつか興味深いことが分かる。*1
- 関数を呼ぶ前にスタックポインタは次のスタック位置まで延ばしてある。subl $20 %espがそれ
- 呼んだあとは addl $20 %esp と元に戻してる。お行儀良い
- 二回連続で呼ぶときのスタックポインタの動きは一回分で済ませてる
- 呼んだあとは addl $20 %esp と元に戻してる。お行儀良い
- よくわからなかった値の部分は、どうやら%edi、%esi、%ebxという名の何からしい
- %edi、%esiはデータ転送命令に使われるアドレスらしい
- %ebxはアドレスを保持するレジスタらしい
- 現在のアドレスを入れる命令は書かれていない
- 恐らくcallすると現在のpcがpushされるのではないかと
しかしまあ、スタックってのは良くできてますね。たったこれだけの作業で関数手続き(どっちだよ)を作ってしまうんだからびっくりだ。
とりあえず、%ebxって戻り値じゃね?と思って実験してみたけど、どうやら全然違うらしい。やっぱよくわからないな、これ。
戻り値を使う場合のfuncの後半部分を載せるよ。
call printf movl -16(%ebp), %eax addl $92, %esp popl %ebx popl %esi popl %edi popl %ebp ret
これによると、戻り値を格納する場合は %eax に格納しているみたい。
むむ。