ユーザーとカーネル仮想アドレスの関係は、以前のいくつかの質問(下のリンク)で説明されていますが、私が理解している限り、ユーザープロセスはできないカーネルアドレスを読み書きします。
だから、どのようにユーザープロセスはカーネルでデータを共有して受信しますか?
記憶を通してであるか。それでは、メモリレイアウトはどこにありますか?たぶんCPUレジスタですか?
関連質問:
答え1
たとえば、見てみましょう。シンプルx86こんにちは世界メッセージを印刷しstdout
て終了するLinuxプログラム。複数のデータ項目をカーネルに渡す必要があります。
- 出力するテキスト文字列、
- 終了コード。
FASMでコンパイルされたアセンブリコードは次のとおりです。
format ELF executable
segment readable executable
; system call numbers
SYS_EXIT=1
SYS_WRITE=4
; file descriptors
STDOUT=1
entry $
start:
mov eax, SYS_WRITE
mov ebx, STDOUT
mov ecx, message
mov edx, messageLength
int 0x80
mov eax, SYS_EXIT
xor ebx, ebx ; exit code 0
int 0x80
message:
db "Hello, world!",0xa
messageLength=$-message
このプログラムが主な目標(メッセージ出力)を達成するために実行するすべてのタスクは次のとおりです。
sys_write
stdout
システムコール番号(syscall用)、ファイル記述子()、メッセージアドレス、およびメッセージ長を示す値で適切なCPUレジスタを設定します。- この場合、ソフトウェア割り込み0x80を介してシステムコールを実行します。
シャットダウンにも同様の順序があります。レジスタをシステムコール番号と終了コードに設定し、システムコールを実行します。
どのレジスタがどの値に設定されるかは、システムコールによって定義されます。呼び出しルール。
カーネルがシステムコールハンドラの実行を開始した後、ハンドラはアプリケーションのコンテキストからレジスタ値を読み込み、コールルールに従って解釈します。特に、システムコールを見ると、sys_write
メッセージの長さとアドレスを取得し、それを使用してユーザー空間メモリから読み込みます。その後、このデータ(ファイル記述子とともに)が実際の操作を実行するドライバに渡されます。
答え2
ユーザープロセスがカーネルアドレスを読み書きできません。
いいえ。ただし、カーネルは必要に応じてユーザーアドレスを読み書きできます。 Linuxシステムコールは、CPUレジスタのシステムコール番号とパラメータを渡します。 (「Linuxシステムコールの呼び出し規則」のようなものを探してください。)
これらの引数の一部はポインタである可能性があります。この場合、カーネルはユーザーアドレス空間の指定された場所でデータを見つける方法を知っています。私が理解したところ、カーネルはデータを使用する前に実際にデータをカーネル空間にコピーします。 (そうでなければ、他のユーザースペーススレッドはシステムコール中にデータを変更できます。)ただし、データの場所はプログラムの要件に応じてユーザーのアドレススペースの任意の場所に存在する可能性があります。