linuxシステム呼び出しの原理と実現

4553 ワード

linuxシステム呼び出し
システムコールはlinuxカーネルがユーザーステータスプログラムに提供する主な機能インタフェースです.システム呼び出しにより、ユーザー・ステータス・プロセスを一時的にカーネル・ステータスに切り替えることができ、カーネル・ステータスがアクセスできるハードウェアとリソースを使用して特定の機能を完了します.システム呼び出しはlinuxカーネルとカーネルモジュールによって実現され、カーネルはシステム呼び出しを処理する際にシステム呼び出し要求とパラメータが正しいかどうかを確認し、特権リソースとハードウェアへのアクセスの正確性を保証します.このようにして、linuxはカーネルとハードウェアリソースアクセスインタフェースを提供すると同時に、カーネルとハードウェアリソースの使用の正確性と安全性を保証する.
本文は主にlinuxの下でシステム呼び出しの原理と実現に対して分析を行う.本明細書の分析はx 86アーキテクチャに基づいており、linuxカーネルコードのバージョンは4.17.6である.
ユーザ状態呼び出しインタフェース
ユーザー・ステータス・プロセスは、主に次の方法でシステム・コールを直接使用します.
#define _GNU_SOURCE         /* See feature_test_macros(7) */
#include 
#include    /* For SYS_xxx definitions */

int syscall(int number, ...);

Syscallインタフェースはglibcによって提供され、実装され、最初のパラメータnumberは呼び出す必要があるシステム呼び出し番号を表し、後続の可変パラメータはシステム呼び出しタイプに基づいて決定される.カーネルでサポートされているシステムコール番号は、に表示されます.関数呼び出しに失敗すると-1が返され、エラーの原因はerrnoに保存されます.errnoの意味は参照できます.
なお、ここでの戻り値とerrnoはglibcパッケージで提供され、カーネルのシステム呼び出し応答関数自体はerrnoを提供せず、戻り値も異なる.
実装の原理
1回のシステム呼び出しの完全な実行手順は、次のとおりです.
  • 特定の命令によりシステム呼び出し(int$80、sysenter、syscall)
  • を発行する.
  • CPUは、ユーザ状態からカーネル状態に切り替える、レジスタや環境設定
  • を行う.
  • system_を呼び出すcallカーネル関数は、システム呼び出し番号によって対応するサービスルーチン
  • を取得する.
  • システム呼び出し処理ルーチン
  • を呼び出す.
  • 特定の命令を使用してシステム呼び出しからユーザ状態(iret、sysexit、sysret)
  • に戻る.
    システムコールめいれい
    カーネルにシステム呼び出しを開始するには、特定のコマンドを使用する必要があります.Linuxでは、従来の方法では、アセンブリ命令intを使用して割り込みを開始し、0 x 80(128)番割り込みを使用してCPUをカーネル状態にし、その後、対応する割り込み応答関数system_を呼び出す.callは、システム呼び出しルーチンを実行します.
    割り込み方式でシステム呼び出しを開始する性能が悪いため、新しいCPUとカーネルはsysenterとsyscallの2つの専用命令を使用してシステム呼び出しを開始することをサポートしています.ここでsysenterは32ビットシステムで使用され、対応する終了命令はsysexitである.Syscallは64ビットシステムで使用され、対応する終了命令はsysretである.
    sysenterを例にとると、このコマンドを使用する場合、まず__を呼び出すkernel_vsyscall()関数はユーザ状態スタックを保存します.その後sysenter命令を実行してカーネル状態に切り替える.最後にsysenter_の実行を開始entry()関数はカーネル状態スタックを設定し、システム呼び出し番号に基づいて処理ルーチンを呼び出し、その後の論理とsystem_callは似ています.
    カーネル実装ロジック
    カーネル呼び出しシステム呼び出し処理ルーチンのコアデータ構造はsys_call_table、このデータ構造は以下のように定義されています.
    /* this is a lie, but it does not hurt as sys_ni_syscall just returns -EINVAL */
    extern asmlinkage long sys_ni_syscall(const struct pt_regs *);
    #define __SYSCALL_64(nr, sym, qual) extern asmlinkage long sym(const struct pt_regs *);
    #include 
    #undef __SYSCALL_64
    
    #define __SYSCALL_64(nr, sym, qual) [nr] = sym,
    
    asmlinkage const sys_call_ptr_t sys_call_table[__NR_syscall_max+1] = {
    	/*
    	 * Smells like a compiler bug -- it doesn't work
    	 * when the & below is removed.
    	 */
    	[0 ... __NR_syscall_max] = &sys_ni_syscall,
    #include 
    };
    

    sys_call_tableは、すべてのシステム呼び出し処理関数のポインタを保存する関数ポインタ配列です.system_callなどの関数はシステム呼び出し番号を下付きとしsys_call_tableで対応するシステム呼び出し関数を検索して実行します.
    sys_call_tableの初期化では、最初のステップは、すべてのポインタ配列要素をsys_に割り当てることです.ni_syscall.これは,一部のシステム呼び出し番号が使用されず,対応する処理関数が定義されていないことを避けるためである.sys_ni_Syscallはで定義され、直接-ENOSYSに戻り、システム呼び出しが存在しないことを示します.
    sys_call_tableの具体的な内容は中で提供して、内容は:_に類似しますSYSCALL_64(19, sys_readv, sys_readv).前から対_SYSCALL_64マクロの2つの定義が表示されますsyscall_64.c先将_SYSCALL_64マクロ展開関数宣言extern asmlinkage long sym(const struct pt_regs*)に展開し、配列要素初期化文[nr]=symに展開します.
    システム呼び出し番号マクロ定義を提供するヘッダファイルなどのファイルは、カーネルソースツリーには存在せず、カーネルコンパイルのプリコンパイルフェーズで自動的に生成されることに注意してください.カーネルソースでシステム呼び出し番号と処理関数を本当に定義するファイルは、次のとおりです.
    #
    # 64-bit system call numbers and entry vectors
    #
    # The format is:
    #    
    #
    # The __x64_sys_*() stubs are created on-the-fly for sys_*() system calls
    #
    # The abi is "common", "64" or "x32" for this file.
    #
    0	common	read			__x64_sys_read
    1	common	write			__x64_sys_write
    2	common	open			__x64_sys_open
    3	common	close			__x64_sys_close
    4	common	stat			__x64_sys_newstat
    5	common	fstat			__x64_sys_newfstat
    6	common	lstat			__x64_sys_newlstat
    7	common	poll			__x64_sys_poll
    8	common	lseek			__x64_sys_lseek
    9	common	mmap			__x64_sys_mmap

    カーネルプリコンパイルシステムは、このファイルに指定されたシステム呼び出し番号、システム呼び出し名、および対応する処理関数名に基づいて、対応するヘッダファイルを生成する.
    新しいシステムコールの追加
    上記の解析によれば、新しいシステム呼び出し番号と処理関数を追加する必要がある場合は、次の変更が必要です.
  • syscall_64.tblに新しいシステム呼び出し番号、名前、および処理関数名を追加します.例えば「666 common mycal__x64_sys_mycal」
  • sys_を提供mycal関数実装.関数はasmlinkage long sysとして定義する必要があります.mycall(...)
  • sys_mycal関数は独立して実現される.cファイルにはlib/パスの下のmakefileに追加するobj-yに追加する必要がある.cファイルパス
  • を使用して、独自のシステム呼び出し機能を提供します.
    注意しなければならないのはsys_call_tableデータ構造はソースコードでconst変数であるため、システム呼び出し関数ポインタの初期化が完了すると変更できません.実行中にシステム呼び出し処理関数を動的に変更または追加する必要がある場合(たとえば、カーネルモジュールをロードして処理関数を提供する)、const制限を削除し、実行中に呼び出し処理関数を切り替えることができます.