プロローグ/エピローグ コードの記述に関する考慮事項
Microsoft 固有の仕様 →
独自のプロローグとエピローグのコード シーケンスを記述する前に、スタック フレームがどのように配置されるかを理解することが重要です。 __LOCAL_SIZE シンボルの使用方法も知っておくと役立ちます。
スタック フレームのレイアウト
この例は、32 ビット関数で使用される標準プロローグ コードを示しています。
push ebp ; Save ebp
mov ebp, esp ; Set stack frame pointer
sub esp, localbytes ; Allocate space for locals
push <registers> ; Save registers
localbytes 変数は、ローカル変数のスタックで必要なバイト数を表します。また、<registers> 変数は、スタックに格納されるレジスタの一覧を表すプレースホルダーです。 レジスタをプッシュした後、スタックに他の適切なデータを配置できます。 対応するエピローグ コードは次のとおりです。
pop <registers> ; Restore registers
mov esp, ebp ; Restore stack pointer
pop ebp ; Restore ebp
ret ; Return from function
スタックは、常に下に (上位メモリ アドレスから下位メモリ アドレスに) 向かって大きくなります。 基本ポインター (ebp) は、プッシュされた ebp の値を指します。 ローカル領域は ebp-4 で始まります。 ローカル変数にアクセスするには、ebp からのオフセットを計算します。そのためには、ebp から適切な値を減算します。
__LOCAL_SIZE
コンパイラには、関数プロローグ コードのインライン アセンブラー ブロックで使用できる __LOCAL_SIZE シンボルが用意されています。 カスタム プロローグ コードで、スタック フレームにローカル変数の領域を割り当てるときに、このシンボルを使用します。
__LOCAL_SIZE の値は、コンパイラによって決定されます。 その値は、すべてのユーザー定義のローカル変数とコンパイラにより生成された一時変数の合計バイト数です。 __LOCAL_SIZE は、イミディエイト (即値) オペランドとしてのみ使用できます。式では使用できません。 このシンボルの値は、変更することも再定義することもできません。 次に例を示します。
mov eax, __LOCAL_SIZE ;Immediate operand--Okay
mov eax, [ebp - __LOCAL_SIZE] ;Error
以下は、プロローグとエピローグのカスタム シーケンスを含む naked 関数の例です。ここでは、プロローグ シーケンスで __LOCAL_SIZE シンボルを使用しています。
// the__local_size_symbol.cpp
// processor: x86
__declspec ( naked ) int main() {
int i;
int j;
__asm { /* prolog */
push ebp
mov ebp, esp
sub esp, __LOCAL_SIZE
}
/* Function body */
__asm { /* epilog */
mov esp, ebp
pop ebp
ret
}
}