余分なスペースにはいくつかの理由があります。1つは、変数の整列用です。2つ目は、スタックをチェックするためのパディングを導入することです(通常、スペースのリリースビルドではなくデバッグビルド)。3つ目は、レジスターまたはコンパイラーによって生成された一時変数を一時的に保管するための追加のスペースを確保することです。
C呼び出しシーケンスでは、通常行われる方法は、引数をスタックにプッシュする一連のプッシュ命令があり、呼び出し命令を使用して関数を呼び出すことです。呼び出し命令は、リターンアドレスをスタックにプッシュします。
関数が戻ると、呼び出し元の関数はプッシュされた引数を削除します。たとえば、関数(これはC++プログラムを備えたVisualStudio 2005)の呼び出しは次のようになります。
push OFFSET ?pHead@@3VPerson@@A ; pHead
call ?exterminateStartingFrom@@YAXPAVPerson@@@Z ; exterminateStartingFrom
add esp, 4
これは、変数のアドレスをスタックにプッシュし、関数を呼び出し(関数名はC ++ごとにマングルされます)、呼び出された関数が戻った後、スタックポインターに使用されるバイト数を追加して、スタックを再調整します。住所。
以下は、呼び出された関数のエントリ部分です。これは、ローカル変数用にスタックにスペースを割り当てることです。エントリ環境を設定した後、スタックから関数の引数を取得することに注意してください。
push ebp
mov ebp, esp
sub esp, 232 ; 000000e8H
push ebx
push esi
push edi
lea edi, DWORD PTR [ebp-232]
関数が戻ると、基本的にスタックを関数が呼び出されたときの位置に戻します。各関数は、スタックが戻る前に、スタックに加えた変更をクリーンアップする責任があります。
pop edi
pop esi
pop ebx
add esp, 232 ; 000000e8H
pop ebp
ret 0
差出人住所を変更しようとしているとのことです。これらの例からわかるのは、リターンアドレスがスタックにプッシュされた最後の引数の後にあることです。
これは、関数呼び出しの規則に関する簡単な説明です。Intelアセンブラ命令に関するこのドキュメントも参照してください。
Visual Studio 2005でいくつかの例の作業を行うと、次のコードを実行すると、この例の関数の戻り値にアクセスできるようになります。
void MyFunct (unsigned short arg) {
unsigned char *retAddress = (unsigned char *)&arg;
retAddress -=4;
printf ("Return address is 0x%2.2x%2.2x%2.2x%2.2x\n", retAddress[3], retAddress[2], retAddress[1], retAddress[0]);
}
このWindows32ビットアドレス指定のコールアセンブラ命令は、リターンアドレスが下位バイトから上位バイトに格納されるバイト順序でリターンアドレスを配置しているように見えることに注意してください。