web-dev-qa-db-ja.com

Linuxのシステムコールはどのように実装されていますか?

ユーザーモードでシステムコールを呼び出すと、OSでどのように処理されましたか?

それはいくつかの実行可能なバイナリまたはいくつかの標準ライブラリを呼び出しますか?

はいの場合、通話を完了するためにどのようなことが必要ですか。

41
MainID

this をご覧ください。

バージョン2.5以降、LinuxカーネルはPentium II +プロセッサに新しいシステムコールエントリメカニズムを導入しました。既存のソフトウェア割り込みメソッドを備えたPentium IVプロセッサのパフォーマンスの問題のため、Pentium II +プロセッサで利用可能なSYSENTER/SYSEXIT命令を使用して、代替システムコールエントリメカニズムが実装されました。この記事では、この新しいメカニズムについて説明します。議論はx86アーキテクチャに限定されており、すべてのソースコードリストはLinuxカーネル2.6.15.6に基づいています。

  1. システムコールとは?

    システムコールは、カーネルからサービスを要求する方法をユーザーランドプロセスに提供します。どんなサービス?ストレージ、メモリ、ネットワーク、プロセス管理などのオペレーティングシステムによって管理されるサービス。たとえば、ユーザープロセスがファイルを読み取りたい場合、「オープン」および「読み取り」システムコールを実行する必要があります。通常、システムコールはプロセスから直接呼び出されることはありません。 Cライブラリは、すべてのシステムコールへのインターフェイスを提供します。

  2. システムコールで何が起こりますか?

    カーネルコードスニペットは、ユーザープロセスの要求に応じて実行されます。このコードは、x86アーキテクチャで最高レベルの特権であるリング0(現在の特権レベル-CPL-0)で実行されます。すべてのユーザープロセスはリング3(CPL 3)で実行されます。

    したがって、システムコールメカニズムを実装するために必要なのは

    1)リング3からリング0コードを呼び出す方法。

    2)リクエストを処理するカーネルコード。

  3. 古き良き方法

    少し前まで、Linuxは、ソフトウェア割り込みを使用してすべてのx86プラットフォームにシステムコールを実装していた。システムコールを実行するには、ユーザープロセスが目的のシステムコール番号を%eaxにコピーし、「int 0x80」を実行します。これにより、割り込み0x80が生成され、割り込みサービスルーチンが呼び出されます。割り込み0x80の場合、このルーチンは「すべてのシステムコール処理」ルーチンです。このルーチンはリング0で実行されます。ファイル/usr/src/linux/Arch/i386/kernel/entry.Sで定義されているこのルーチンは、現在の状態を保存し、%の値に基づいて適切なシステムコールハンドラーを呼び出します。 eax。

  4. 新しい光沢のある方法

    このソフトウェア割り込みメソッドは、Pentium IVプロセッサでははるかに遅いことがわかりました。この問題を解決するために、LinusはすべてのPentium II +プロセッサが提供するSYSENTER/SYSEXIT命令を利用する代替システムコールメカニズムを実装しました。この新しい方法で先に進む前に、これらの手順に慣れておきましょう。

38
GregD

システムコールの意味によって異なります。 Cライブラリ呼び出し(glibcを介した)または実際のシステム呼び出しを意味しますか? Cライブラリの呼び出しは、常に最終的にシステムコールを使用して終了します。

システムコールを行う従来の方法は、ソフトウェア割り込み、つまりint命令によるものでした。 Windowsにはint 0x2e Linuxはint 0x80。 OSは、割り込み記述子テーブル(IDT)で0x2eまたは0x80の割り込みハンドラーを設定します。このハンドラは、システムコールを実行します。引数をユーザーモードからカーネルモードにコピーします(これはOS固有の規則によって制御されます)。 Linuxでは、引数はebxecxedxesi、およびediを使用して渡されます。 Windowsでは、引数はスタックからコピーされます。次に、ハンドラーは(関数のアドレスを見つけるために)ある種の検索を実行し、システムコールを実行します。システムコールが完了すると、iret命令はユーザーモードに戻ります。

新しい方法はsysentersysexitです。これらの2つの命令は、基本的にすべての登録作業を行います。 OSは、Model Specific Registers(MSR)を通じて命令を設定します。その後は、実質的にintを使用するのと同じです。

11
wj32

それはglibcを通過します。glibcは、レジスタにパラメーターを入力した後に0x80割り込みを発行します。カーネルの割り込みハンドラは、syscallテーブルでsyscallを検索し、関連するsys _ *()関数を呼び出します。

かなり簡略化されていますが、予約されたメモリアドレスにアクセスしようとすると、割り込みが発生します。割り込みは、コンテキストをカーネルモードに切り替え、ユーザーに代わってカーネルコード(実際のシステムコール)を実行します。呼び出しが完了すると、制御がユーザーコードに戻ります。

3
tvanfosson

アセンブリのint Xは、システムコール番号nに変換されます。
ex read syscallには番号4が与えられる場合があります。
システムの起動時に、OSは割り込み記述子テーブル(IDT)と呼ばれるポインターのテーブルを作成します。IDTには、システムコールのアドレスのリストと、それらを実行するために必要な特権が含まれています。
現在の特権レベル(CPL)は、CSレジスタのビットの1つ(技術的にはx86では2ビット)に保存されます。
これは、int命令が続くステップです。
•IDTからn番目の記述子をフェッチします。nはintの引数です。
•%csのCPLが<= DPLであることを確認します。DPLは記述子の特権レベルです。
•そうでない場合、ユーザーにはこれを実行するための十分な権限がなく、int 13命令(一般保護違反)が実行されます(ユーザーには十分な権限がありませんでした)
•「はい」の場合、ユーザーコードにはこのシステムコールを実行するための十分な特権があります。現在カーネルモードに切り替えているため、現在の実行コンテキスト(レジスタなど)が保存されます。
システムコールが終了すると、実行を継続したいため、レジスターやフラグが情報に含まれます。 •システムコールはカーネルモードで実行されるため、システムコールのパラメーターはカーネルスタックに保存されます。

VSYSCALL(FAST SYSTEM CALL)
ユーザーがシステムコールを実行するたびに、Osはマシンの現在の状態(レジスタ、スタックポインターなど)を保存し、実行のためにカーネルモードに切り替えます。一部のシステムコールでは、すべてのレジスタを保存する必要はありません。 ex gettime of dayシステムコールは現在時刻を読み取り、システムコールが戻ります。したがって、一部のシステムコールは、vsyscallsと呼ばれるものを介して実装されます。ここでシステムコールが行われると、カーネルに切り替えずにユーザー空間自体で実行されます。したがって、時間が節約されます。
vsyscallの詳細については、こちらをご覧ください http://www.trilithium.com/johan/2005/08/linux-gate/
そしてここ 誰でもgettimeofdayの仕組みを理解できますか?

1
Deepthought

Syscallは、特別なトラップ命令、syscall番号、および引数で構成されています。

  1. 特別なトラップ命令は、ユーザーモードから無制限の特権を持つカーネルモードに切り替えるために使用されます。
  2. Syscall番号と引数は、レジスターによって渡されます。
0
Chris Tsui