2

数か月間、私は「自作」のオペレーティング システムに取り組んできました。現在、起動して 32 ビット保護モードに入ります。割り込みテーブルをロードしましたが、ページネーションを設定していません (まだ)。

例外ルーチンを作成しているときに、命令が例外をスローすると、例外ルーチンが実行されますが、CPU は例外をスローした命令にジャンプして戻ることに気付きました。これはすべての例外に適用されるわけではありません (たとえば、div by zero 例外は、除算命令の後に命令に戻ります)、次の一般的な保護例外を考えてみましょう。

MOV EAX, 0x8
MOV CS, EAX

私のルーチンは単純です。赤いエラー メッセージを表示する関数を呼び出します。

結果: MOV CS、EAX が失敗します -> エラー メッセージが表示されます -> CPU が MOV CS に戻ります -> エラー メッセージをスパムする無限ループ。

この問題について、オペレーティング システムと UNIX セキュリティの教師と話しました。彼は、Linux にはそれを回避する方法があることは知っているが、どの方法があるかはわからないと私に言いました。

単純な解決策は、その命令の長さを取得するために、ルーチン内からスロー命令を解析することです。その解決策はかなり複雑で、影響を受けるすべての例外ルーチンで比較的重い関数への呼び出しを追加するのは少し不快に感じます...

したがって、問題を回避する別の方法があるかどうか疑問に思っていました。この動作を変更できるビットを含む「魔法の」レジスタがあるのではないでしょうか?

--

提案/情報をお寄せいただきありがとうございます。

--

編集:なぜ問題のある命令をスキップして通常の実行を再開したいのか疑問に思う人が多いようです。

これには 2 つの理由があります。

  1. まず第一に、プロセスを強制終了することは可能な解決策ですが、クリーンな解決策ではありません。これは、Linux で行われる方法ではありません。たとえば、(AFAIK) カーネルがシグナル (SIGSEGV だと思います) を送信しますが、すぐに実行を中断しません。アプリケーションはシグナルをブロックまたは無視して、独自の実行を再開できるため、これは理にかなっています。これは、何か間違った IMO を実行したことをアプリケーションに伝える非常にエレガントな方法です。

  2. 別の理由: カーネル自体が不正な操作を実行した場合はどうなるでしょうか? バグが原因である可能性がありますが、カーネル拡張が原因である可能性もあります。コメントで述べたように、その場合はどうすればよいですか? カーネルを強制終了して、スマイリー付きの素敵なブルー スクリーンを表示しますか?

だからこそ、命令を飛び越えられるようになりたい。命令のサイズを「推測」することは明らかにオプションではなく、命令の解析はかなり複雑に思えます (そのようなルーチンの実装を気にしているわけではありませんが、より良い方法がないことを確認する必要があります)。

4

4 に答える 4

3

異なる例外には異なる原因があります。一部の例外は正常であり、例外は、ソフトウェアの実行を継続できるようにする前に何をする必要があるかをカーネルに通知するだけです。この例としては、スワップ空間からデータをロードする必要があることをカーネルに伝えるページ フォールト、CPU がサポートしていない命令をエミュレートする必要があることをカーネルに伝える未定義の命令例外、またはカーネルにそれを伝えるデバッグ/ブレークポイント例外が含まれます。デバッガーに通知する必要があります。これらの場合、カーネルが問題を修正して静かに続行するのは正常です。

一部の例外は、異常な状態 (ソフトウェアのクラッシュなど) を示します。この種の例外を適切に処理する唯一の方法は、ソフトウェアの実行を停止することです。情報を保存したり (コア ダンプなど)、情報を表示したり (「死のブルー スクリーン」など) してデバッグに役立てることができますが、最終的にはソフトウェアが停止します (プロセスが終了するか、カーネルが「何もしないまで」状態になります)。ユーザーはコンピュータをリセットします」状態)。

異常な状態を無視すると、何が悪かったのかを理解するのが難しくなります。たとえば、トイレに行くための指示を想像してください。

  • バスルームに入る
  • パンツを脱ぐ
  • 座る
  • 出力の生成を開始する

ここで、ショート パンツを履いているためにステップ 2 が失敗したとします (「パンツが見つからない」という例外)。その時点で停止しますか (分かりやすいエラー メッセージか何かで)、それとも、そのステップを無視して、有用な診断情報がすべてなくなった後で何が問題だったのかを突き止めようとしますか?

于 2012-02-08T13:59:21.840 に答える
2

私が正しく理解していれば、例外の原因となった命令(eg mov cs, eax)をスキップして、次の命令でプログラムの実行を続行する必要があります。

なぜあなたはこれをしたいのですか?通常、プログラムの残りの部分は、その命令が正常に実行された効果に依存するべきではありませんか?

一般的に、例外処理には3つのアプローチがあります。

  • 例外を修復不可能な状態として扱い、プロセスを強制終了します。たとえば、ゼロによる除算は通常、この方法で処理されます。

  • 環境を修復してから、命令を再実行してください。たとえば、ページフォールトはこの方法で処理されることがあります。

  • ソフトウェアを使用して命令をエミュレートし、命令ストリームでスキップします。たとえば、複雑な算術命令はこのように処理されることがあります。

于 2012-02-05T18:15:41.700 に答える
2

あなたが見ているのは、一般保護例外の特徴です。インテル システム プログラミング ガイドには、(6.15 Exception and Interrupt Reference / Interrupt 13 - General Protection Exception (#GP)) と明確に記載されています。

Saved Instruction Pointer
The saved contents of CS and EIP registers point to the instruction that generated the
exception.

したがって、その命令をスキップする例外ハンドラーを作成するか (これは奇妙なことです)、単に "General Protection Exception at $SAVED_EIP" または同様のメッセージで問題のあるプロセスを強制終了する必要があります。

于 2012-02-05T18:32:45.950 に答える
0

失敗した命令を解析し、その操作をエミュレートし、その後命令に戻ることによって、GPFに応答したいいくつかの状況を想像することができます。通常のパターンは、命令が再試行された場合に成功するように設定することですが、たとえば、アドレス0x000A0000-0x000AFFFFのハードウェアにアクセスすることを期待し、そのようなハードウェアがないマシンで実行したいコードがある場合があります。 。このような状況では、すべてのアクセスをトラップして個別に処理する必要があるため、そのスペースの「実際の」メモリに保存したくない場合があります。一部の仮想PCプログラムがそれをかなりうまく管理しているように見えることは知っていますが、そのメモリにアクセスしようとしている命令をデコードせずにそれを処理する方法があるかどうかはわかりません。

それ以外の場合は、システムがGPFに遭遇したときに使用する必要があるジャンプベクトルをスレッドごとに用意することをお勧めします。通常、そのベクトルはスレッド終了ルーチンを指す必要がありますが、ポインターを使用して「疑わしい」ことを実行しようとしたコードは、そのコードに適したエラーハンドラーに設定することができます(コードは、領域を離れるときにベクトルの設定を解除する必要がありますエラーハンドラは適切だったでしょう)。

命令を実行せずにエミュレートしたい場合や、エラーハンドラルーチンに制御を移したい場合は想像できますが、単に命令をスキップしたい場合は想像できません。 GPFを引き起こしたでしょう。

于 2012-02-06T02:50:12.007 に答える