1

ESPなんらかの奇妙な理由で、ある関数のスタックポインタが一時的にデクリメントされてから再びインクリメントされるとしましょう。

;; ... we're saving registers ...
push EAX
push EBX
push ECX
push EDX

add ESP, 4        ;; Whoops!
sub ESP, 4        ;; Ah, we're fine; we restored it... or are we?

これで、サブ命令の直前に割り込みがトリガーされる可能性があります。

私が正しく理解していれば、割り込みによってCPUがいくつかの値をスタックにプッシュします。

これは、スタックが破損することを意味しますか?または、OSはどういうわけか(どのように?)プログラムのコンテキストを格納するために別のスタック/メモリを使用しますか?それとも、CPUの特権レベルに依存しますか?(もしそうなら、どのように?)

4

4 に答える 4

3

x86を減算してから加算するのは問題ありません。これがローカル変数の処理方法です。ただし、逆の操作を行うと、割り込みが発生した場合にデータが破損する可能性があります。追加によってスペースが解放され、次にサブによってスペースが再度割り当てられます(内容が同じであることが保証されなくなります)。

于 2012-05-21T19:19:53.120 に答える
1

共有スタック(プログラムと割り込み)を使用する場合、変更したり失われたりしたくない情報をスタックポインター自体が指すようにする必要はありません。割り込みが発生し、その情報を変更する可能性があります。したがって、減算、つまりスタックポインターを重要なデータから遠ざけることは問題ありません。その新しい割り当てが終了すると、新しいデータが使用できなくなったことを理解した上でスタックポインターを返すことができます。また、スタックポインタ自体をいじるときは、整列に注意する必要があります。この場合、サブ、次に追加は問題ありません。追加、次にサブはデータの損失を引き起こす可能性があります。

于 2012-05-21T20:01:49.060 に答える
1

上記のコードがISRの先頭にあり、その割り込み記述子が「トラップゲート」ではなく「割り込みゲート」としてマークされていて、ISR内で(STIまたはを使用してPOPF)手動で割り込みを有効にしていない場合、この場合FLAGS.IF、ISRに入るときにCPUが自動的にクリアされるため、問題が発生します。

また、割り込みによって保護レベル間の遷移が発生した場合、CPUは新しいスタックにデータ(EFLAGS、リターンアドレス、古いものSS:ESP)をプッシュし、古いスタックは変更されません。

于 2012-05-22T02:08:51.363 に答える
0

この投稿は上記の回答と矛盾しているようで、これは実際には安全であると述べています:

割り込みが発生した場合、あなたは失敗しませんか?

DOSでプログラムした人は、この時点で割り込みの可能性についてうずうずしている可能性があります。通常、このようにスタックポインタを再利用することは、割り込みがいつ発生するかわからないため、非常に悪い考えです。割り込みが発生すると、CPUは現在のプログラムカウンタとフラグをスタックに忠実にプッシュします。ESPを再利用した場合、これによりランダムなデータ構造が破棄されます。この種の環境では、ESPは常に、割り込みを処理するための有効で十分なスタックスペースを指している必要があり、これが成り立たない場合は常に、割り込みを無効にする必要があります。割り込みを無効にして長時間実行すると、システムの応答性が低下し(割り込みが失われ、待ち時間が短くなります)、大きなルーチンには実用的ではありません。

ただし、ここでは保護モードで実行しています。

Win32のユーザースペースで実行している場合、割り込みはユーザースタックではなく、カーネルスタックにプッシュされます。考えてみれば、ユーザースタックを使うことはできません。スレッドのスタックスペースが不足している場合、またはスタックが無効である場合でも、CPUがEIPとEFLAGSをプッシュしようとすると、ページフォールトが発生し、割り込みハンドラーでページフォールトを実行できません。したがって、スケジューラーは、スタックなしのルーチンの実行中に任意の数のコンテキストスイッチを実行でき、ESPであると指摘されているデータ構造は影響を受けません。

于 2013-01-05T03:26:18.047 に答える