私は組み立てを始めたばかりで、これらの指示と同様の指示がコードのいたるところにありました。
sub esp , something
mov esp, dword ptr [esp + something]
なぜこれを行うのでしょうか?スタックフレームの初期化についてだと聞きました。それについて説明するか、私が探すキーワードを指摘してもらえますか?
すべての C ( inline
C 関数だけでなく、一部の関数を除く) 関数には、開始と終了があります。通常、冒頭は次のようになります。
push ebp
mov ebp, esp
sub esp, x
最初の行は、古いスタック フレームをプッシュします。プログラムの実行中に多くの関数が呼び出されるため、関数は別の関数を呼び出すときにスタック フレームをスタックに保存できます。スタック フレーム (通常はEBP
レジスタに格納されます) は、すべてのローカル変数のアドレス指定のベースとなるものです。このコードがあるとしましょう:
int main() {
__volatile int localVariable = 0x10;
printf("%d");
}
変数localVariable
はどこかに静的に格納できますが (たとえば address 0x410000
)、main
再度呼び出された場合、そのアドレスの値は上書きされます。したがって、動的割り当てのようなものが必要です。それがスタックフレームの用途です。前のスタック フレームを保存し、ローカル変数の場所をスタック ポインターの実際の位置に相対的に「割り当て」ます。この場合、localVariable
は常にオンの位置にある必要がありますEBP-sizeof(int)
。
2 行目と 3 行目は、実際には「新しい」メモリを割り当てるコードです。3行目はESP
(スタックが下に成長する)からいくつかの値を減算します->これが、関数が変数を上書きしない理由です。すべての機能には独自の場所があります。2 行目は古いスタック ポインターを保存するため、呼び出された関数がそのスタック フレームから戻ると、前の関数のポインターをスタックします。
関数の標準的な終了は
mov esp, ebp
pop ebp
ret
leave
関数が前の関数の実行に戻ることが非常に多いため、2 番目の例のret を残すこと
は、最初の例の最初の 2 行の代わりになります。
通常、アドレス指定EBP - something
は、呼び出された (現在の) 関数のローカル変数にアクセスすることを意味します。
通常、アドレッシングEBP + someting
とは、関数に渡される引数にアクセスすることを意味します。
EBP
格納されているアドレスは実際には引数を指しているのではなく、関数をcall
呼び出すときに命令によってプッシュされた関数のアドレスを返すことに注意する必要があります。格納された値は、最後の変数 (変数カウントの引数を処理する Java に典型的 -新しい配列を作成し、への参照のみを渡すことによって) と同じEBP + 4
ように、最初に (古い慣例、たとえば のような可変数の引数を持つ関数に使用されます) にすることができます。それ)。printf
Object... values
一見、Intel x86 に見えます。これがアセンブリ サブルーチンの先頭にある場合、「何か」は通常、すべてのローカル (スタック割り当て) 変数の合計の長さになります。スタックは下向きに、つまり下位アドレスに向かって成長するため、これによりスペースが確保されます。2行目はあなたが書いたものと同じですか?esp は既に空き領域を指しているため、ルーチンが自身を再帰的に呼び出すか、別の関数を呼び出す前に、パラメーターをローカルの下のスタックにプッシュできます。ネストされた関数がある場合の Pascal のように、(次の) 呼び出し先が呼び出し元のスタック フレームにアクセスできるようにするために使用されない限り、ローカル変数に対応するように調整された直後に何かを esp にロードするポイントがわかりません。