EBP
一般に、 の値を に移動する前に、 の現在の値をスタックにESP
プッシュする必要がありますEBP
。 EBP
は、32 ビット プラットフォームの「callee-save」レジスタです。つまり、関数内で変更する場合は、最初に保存する必要があります。
関数がスタックが指している場所 (または関数呼び出しの後に戻る場所) の値を返すようにしたい場合、最善の方法は次のとおりです。
void* get_stack_addr()
{
void* stack_ptr = NULL;
//on 32-bit systems
//EBP is pointing at top of stack frame
//EBP + 4 is the return instruction address
//EBP + 8 is the value that was in ESP before function call for a function with no arguments
__asm__
(
"movl %%ebp, %0\n\t"
"addl $8, %0\n\t"
: "=r" (stack_ptr)
);
return stack_ptr;
}
その方法EAX
は、呼び出しが行われる前にスタックが指していた値のアドレスを保持していますget_stack_addr()
。関数での値を返しただけでは、ESP
実際にはどこを指しているのかわかりません。これは、適切なスタック アライメントを維持するために、コンパイラが C/C++ 関数のスタックをパディングすることがよくあるためです。また、多くの場合、すべてのローカル変数用にスタックにスペースを確保しますが、これもスタックの計算を中断します。スタック フレームの先頭を指す を使用EBP
することで、関数呼び出し前のスタックの値を 32 ビット プラットフォームで正確に計算できます。最後にEAX
、C/C++ のほとんどの OS アプリケーション バイナリ インターフェイスでEAX
は、 ではなく関数の戻り値を保持するため、戻り値を に配置しますEBP
。
もう1つ... を呼び出す実際の関数のスタック上のパラメーターの開始が必要な場合はget_stack_addr()
、に変更movl %%ebp, %0\n\t
しmovl (%%ebp), %0)\n\t
ます。そうすれば、以前のスタック フレーム ベース ポインター (つまり、呼び出し元のスタック フレーム ベース ポインター) を取得でき、そのアドレスに +8 の値を追加することで、格納されているパラメーターの先頭のいずれかを取得できます。または、現在の関数の呼び出し元のスタック フレーム (つまり、前のスタック フレーム) を指しているアドレスを見ています。
拡張機能として、次のもの"leal 8(%%ebp), %0\n\t"
を置き換えることができます。
"movl %%ebp, %0\n\t"
"addl $8, %0\n\t"
このleal
命令は、EBPの値に 8 を加算し、結果を出力オペランドに格納します。