2017-07-16 2 views
3

プログラムを実行する前に、espレジスタが有効なアドレスを指すように設定されていますか? execへのコール中にまたはユーザー空間自体に?私はカーネルコードを使いこなし、どこにも見つからないようです。ユーザーモードの一つとカーネルモードのための1:espレジスタはいつlinuxに設定されますか?

答えて

4

背景

のx86 CPUは、(タスクあたり)2(実際には4つ)のスタックを持っています。

割り込みがユーザモードで発生した場合、CPUは、カーネルのスタックのアドレスにespを設定する(詳細については、「TSS」を参照)とespの元の値をプッシュする(ユーザモードのスタックの位置()にカーネルの)スタック。 eip,csおよびeflagsは、割り込みが発生すると常にスタックにプッシュされます。

割り込みから復帰するとき、iret命令は、(カーネルの)スタックからの "古い"レジスタ値をポップし、スタックポインタは再びユーザのスタックを指します。

プリエンプティブマルチタスクオペレーティングシステムは、典型的には以下のように動作します:

いくつかのタスクは、このタスクは、時間の非常に少量のCPU負荷の100%を取ることを意味して実行されています。タイマ割込みが発生すると、現在実行中のタスクのレジスタ値が(CPUによって)スタックに格納されます。 OSはpushの値を他のすべてのレジスタの値に置き換え、espの値を別のタスクのカーネルスタック(別のタイマ割り込みが発生したときに保存されたもの)に変更します。次にpopsレジスタを実行し、iretを実行するので、すべてのレジスタには別のタスクの値が含まれ、他のタスクは実行されます。

Linux(4.12.2)、x86-32では、アセンブリソース "entry_32.S"の関数__switch_to_asmによって行われます。あなたの質問

直接答え新しいタスクが作成されると2つのスタック(ユーザとカーネルスタックが)そのタスクに割り当てられると、割り込みにpopedれる初期レジスタ値が書き込まれカーネルスタック。これには、ユーザモードの初期値espが含まれます。

一部のタイマーは後で割り込みが発生します(すでに実行中のタスクが再起動されたのと同じ方法で)。

  • fork()は、単にカーネルスタックをコピーします。

    で(古いバージョン)Linuxは、新しいタスクを作成するために使用される二つのコマンドがあります。 fork()ので、すでに既存のタスクと同じでなければなりません(espを含む)すべてのレジスタ値

  • execve()新しいカーネルスタックを割り当てないであろう(新しいタスクが作成されますが、別の実行ファイルは、現在のタスクで実行されている)既存のタスクを複製します。 Execveは新しいユーザースタックを割り当て、espの値をカーネルスタックに上書きします。 (Mark Plotnickのコメントは、これが行われた位置を示しています)
関連する問題