「システムコール」という用語を理解したいと思います。ユーザースペースアプリケーションからカーネルサービスを取得するためにシステムコールが使用されることは知っています。
説明が必要な部分は、「システムコール」と「システムコールのC実装」の違いです。
ここに私を混乱させる引用があります:
Unixライクなシステムでは、そのAPIは通常、glibcなどのCライブラリ(libc)の実装の一部であり、システムコールにラッパー関数を提供します。
「彼らが呼ぶシステムコール」とは何ですか?彼らの出所はどこですか?それらをコードに直接含めることはできますか?
一般的な意味での「システムコール」は単なるPOSIX定義のインターフェイスですが、実際に実装を確認するには、Cソースを調べて、実際のユーザー空間からカーネルへの通信が実際にどのように行われるかを確認できます。
背景のメモ:最終的に、各c関数が/dev
。
システムコールそれ自体は概念です。これらは、プロセスがカーネルに実行を要求できるアクションを表します。
これらのシステムコールは、UNIXライクなシステムのカーネルに実装されています。この実装(Cで記述され、小さな部品の場合はasmで記述)は、実際にシステムでアクションを実行します。
次に、プロセスはインターフェイスを使用して、システムにシステムコールの実行を要求します。このインターフェイスはPOSIXで指定されています。これは、C標準ライブラリの関数のセットです。これらは実際にはラッパーであり、いくつかのチェックを実行してから、カーネル内のシステム固有の関数を呼び出し、システムコールで必要なアクションを実行するように指示します。そして、秘訣は、インターフェイスであるそれらの関数がシステムコール自体と同じ名前であり、しばしば「システムコール」と直接呼ばれることです。
システム固有のメカニズムを介して直接システムコールを実行するカーネルの関数を呼び出すことができます。問題は、コードが完全に移植不可能になることです。
したがって、システムコールは次のとおりです。
システムコールは、オペレーティングシステム(カーネル)にプログラムに代わって何らかの操作を実行するように依頼する方法です。プログラム自体では実行できません(または単に不便です)。一部の操作を実行できない理由は、通常、ランダムプログラムがそれらを実行できるようにすると、I/O(RAMに直接、何かを上書きする)を行うなど、システムの整合性が損なわれる可能性があるためです。
POSIXは、プログラム(プログラムが呼び出すことができる特定の関数)のインターフェースを定義します。それらのいくつかは、多かれ少なかれ直接システムコールに変換されますが、他のものはより詳細なものを必要とします。それはあなたの言語のランタイムです。 POSIXインターフェースを提供し、引数をパッケージ化して結果を受け取り、呼び出し元に渡すCライブラリ。
Unixyシステムは、システムコールとして多かれ少なかれ直接POSIXインターフェースを提供します。通常、システムコールを直接呼び出す方法があります。Linuxでこの機能を使用する方法の詳細については、syscall(2)
を探してください。
確かに、どのように多くの方向を実行できますか?事。
実際のシステムコールは、ビルドされたプログラムでは、カーネルモードへの特権昇格をトリガーする機械語命令であり、カーネル自体では、命令が呼び出すコードです。 libcコード(およびすべての言語ランタイム)は、カーネルコードがそれらを見つけることを期待しているマシンレジスターとストレージ内パラメーターをセットアップします。これらは、そのマシン命令の制約のために明らかに奇妙な場所になる可能性があります。
OSコード自体に入ると、ユーザーランドランタイムが実行したマシン固有のもののミラーイメージの巻き戻しがあり、次に完全に通常のサブルーチン呼び出しがあります。
これが実際のOSでどのように機能するかを正確に確認したい場合は、カーネルソース(git clone https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/
)そして、例えばgit grep -i system\ call
。 glibcソースをプルして、同様に行います。
Linuxでは、少なくともシステムコールメカニズムは、特定の形式のデータ(通常はある種のc構造体)をいくつかのレジスタまたは事前定義されたメモリアドレスに配置することにより、ほとんどのアーキテクチャで機能します。
ただし、問題は実際にCPUにカーネルスペースへの切り替えを強制することで発生します。これにより、特権カーネルコードを実行して呼び出しを処理できるようになります。これは、何らかの障害(0で除算される障害、未定義のオーバーフロー、またはsegfaultなど)を強制することで実行されます。これにより、カーネルは強制的に実行を引き継いで障害を処理します。
通常、カーネルは、原因となっているプロセスを強制終了するか、ユーザー指定のハンドラーを実行することにより、障害を処理します。ただし、syscallの場合は、代わりに事前定義されたレジスタとメモリの場所をチェックし、syscall要求が含まれている場合は、メモリ内構造体のユーザープロセスによって提供されたデータを使用して実行します。これは通常、特別に手作りされたアセンブリで実行する必要があり、システムのCライブラリが関数としてラップする必要があるユーザーがsyscallを簡単に使用できるようにする必要があります。下位レベルのインターフェースについては、 http://man7.org/linux/man-pages/man2/syscall.2.html を参照して、syscallがどのように機能するか、およびそれを使用せずに呼び出す方法についての情報を確認してくださいCラッパー。
これは過度に単純化されているため、すべてのアーキテクチャ(mipsに特別なsyscall命令がある)には当てはまりません。また、必ずしもすべてのOSで同じように機能するとは限りません。それでも、コメントや質問がある場合は質問してください。
修正:/ dev /に関するコメントについては、これは実際にはカーネルへのより高いレベルのインターフェースであり、より低いインターフェースではありません。これらのデバイスは、実際にはその下で(約)4つのシステムコールを使用します。それらへの書き込みは、書き込みsyscallと同じであり、読み取りsyscallを読み取り、openおよびclose syscallsと同等に開閉し、ioctlを実行すると、それ自体がシステムの多くのioctlの1つにアクセスするためのインターフェースである特別なioctl syscallを引き起こします。呼び出し(特別な、通常はデバイス固有の呼び出しで、使用方法が狭すぎてシステムコール全体を記述できない)。
すべてのシステムコールには整数が関連付けられています。この整数は、システムコールの戻り値、システムコールへの引数の数、および引数のタイプの関数です。このシステムコール番号は、グローバルシステムコールベクトルへのオフセットにすぎません。特権モードでのみアクセス可能なこのベクトルには、適切なハンドラへのポインタが含まれています。システムコールを呼び出す際のプロセスでは、ソフトウェア割り込み(トラップ割り込み)が生成されるため、どのシステムコールを呼び出すかを決定するトラップハンドラーが実行されます。次に、カーネルは、スタック上にあるユーザーから渡されたシステムコールの引数をプロセッサレジスタにコピーし、要求されたサービスが完了すると、プロセッサレジスタからスタックにデータがコピーされます。これは、引数がプロセッサレジスタにコピーされ、プロセッサのレジスタが限られているため、システムコールの引数が限られている理由の1つです。