関数呼び出し時のスタック操作

大雑把なメモ。

大事なレジスタがip、sp、bp。(GDBではrip、rsp、rbpになっている。)

ip(インストラクションポインタ)は次に実行する命令列のアドレスを格納している。
sp(スタックポインタ)は今のスタックフレームの上のほうを指している。(多分。)
bp(フレームポインタ)は今のスタックフレームの始まりっぽい位置を指している。

  • 関数を呼ぶ前に今から呼ぶ関数に渡す引数を今の関数のスタックフレームの上の方に準備する。
  • 関数を呼ぶ(call)と今のスタックフレームの上に関数から戻った後に実行する命令列のアドレスを格納。
  • ipを呼び出し先の関数の先頭命令アドレスに書き換え。
  • 呼び出し先の関数では、まず、戻り先命令アドレスの上にbpの値を格納(push bp)、フレームポインタの退避。
  • そしてbpの値をspの値で上書き(mov bp sp)。
  • 必要に応じて、spを上にずらす(sub sp 0x20)。

図で書くと下のようになる。

-------------- <--- sp
......
--------------
作業領域
-------------- <--- bp
退避されたFP
--------------
戻り先アドレス
--------------
引数1
--------------
引数2
--------------

bpは退避されたFP(フレームポインタ)が格納されているアドレスを指すようになっているようだ。(多分。)
あと、引数は必ずしもスタック領域を通じて渡されるわけでもなさそうだ。
簡単なプログラムを書いて確かめてみると、レジスタ経由で渡されている。

スタックポインタの位置とかずらし方とかがよくわからない。 呼び出し元に戻るときの詳しい処理もよくわからない。

Debug Hacks -デバッグを極めるテクニック&ツール

Debug Hacks -デバッグを極めるテクニック&ツール