TL

システムコールとカーネル

アプリは画面やファイル、ネットワークを直接は触れない。OS の中核「カーネル」に“お願い”するための窓口がシステムコール。保護のために世界を二つに分けている。

中級システムコールカーネル特権モードOS最終更新: 2026-06-04
TL;DR要点だけ先に
  • 1.OS は世界を「ユーザー空間(アプリ)」と「カーネル空間(OS の中核)」に分け、CPU の特権モードで保護している。
  • 2.アプリはハードを直接触れない。ファイル・通信・プロセス生成などは すべて システムコールでカーネルに依頼する。
  • 3.代表例は read/write/open/close/fork/exec。普段書く printf や fopen は その下で システムコールを呼ぶライブラリ関数。

なぜ世界を2つに分けるのか:保護

もし全アプリがメモリやディスク、CPU を直接好き勝手に触れたら、たった1つのバグや悪意あるプログラムが、他のアプリや OS そのものを巻き込んで壊せてしまいます。そこで OS は CPU の機能を使い、実行環境を2つに分離します。

  • ユーザー空間(user space):アプリが動く世界。権限が制限され、ハードへの直接アクセスや他プロセスのメモリ参照はできない。
  • カーネル空間(kernel space):OS の中核(カーネル)が動く世界。すべての特権を持ち、ハードやメモリ、CPU を直接制御できる。

この境界は、CPU が持つ 特権モード(保護リング) で物理的に守られています。x86 では特権レベルを「リング0〜3」で表し、一般に カーネルがリング0、アプリがリング3 で動きます。

  • カーネルモード(特権モード / リング0):特権命令を実行でき、全メモリ・全ハードにアクセス可能。
  • ユーザーモード(非特権モード / リング3):実行できる命令もアクセスできるメモリも制限される。

ユーザーモードのアプリが特権命令を直接実行しようとすると、CPU が 例外(トラップ) を発生させ、カーネルが介入します。だからアプリは「自分でやる」のではなく「頼む」しかないのです。

“分ける”のは安定性のためでもある

分離の狙いは悪意対策だけではありません。あるアプリが暴走しても、その被害を そのプロセスの中に閉じ込め、OS や他アプリを守る——いわゆる障害の封じ込めも目的です。1つのタブがクラッシュしても OS ごと落ちないのは、この境界のおかげです。

ユーザー空間とカーネル空間

観点ユーザー空間カーネル空間
動くものアプリ(ブラウザ・エディタ等)OS の中核(カーネル)
CPU の権限ユーザーモード(非特権)カーネルモード(特権)
ハードへのアクセス直接は不可(依頼する)直接アクセスできる
できること計算・自分のメモリ操作全メモリ・全ハードの制御
他者への影響原則 自分の中だけシステム全体に及ぶ
クラッシュ時そのプロセスが落ちるシステム全体が停止(パニック)

つまりアプリは「狭い安全な部屋」で動き、ハードや他プロセスという「外」に触れたいときだけ、システムコールというドアを叩いてカーネルに頼む、という構図です。

システムコールが呼ばれる仕組み

「アプリ → カーネル」は単なる関数呼び出しではありません。特権の壁を越えるため、専用の手順を踏みます。おおまかな流れはこうです。

  1. アプリが「何をしてほしいか」を決める(例:このファイルを読む)。
  2. システムコール番号と引数を、CPU の決まった場所(レジスタなど)にセットする。
  3. 特別な命令(x86-64 なら syscall、古くは int 0x80 などの ソフトウェア割り込み / トラップ)を実行する。
  4. CPU が ユーザーモード → カーネルモードへ切り替え、実行はカーネル内の入口(ディスパッチャ)に移る。
  5. カーネルが番号を見て対応する処理を実行し、結果(戻り値・エラー) を返す。
  6. カーネルモード → ユーザーモードへ戻り、アプリは続きを実行する。
[ユーザー空間]  アプリ
     │  ①番号と引数をセット
     │  ②syscall 命令(トラップ)
     ▼ ───── 特権の壁(モード切替)─────
[カーネル空間]  ③番号で処理を選ぶ → ④実際の仕事
     │  ⑤結果を返す
     ▼ ───── 壁を戻る(モード切替)─────
[ユーザー空間]  アプリが続きを実行

ポイントは、アプリがカーネルの中の関数を直接呼んでいるわけではないこと。アプリは「番号で依頼を投げる」だけで、実際に走るコードや権限の切り替えは CPU とカーネルが担います。これがただの関数呼び出しと違い、無視できないコスト(モード切替のオーバーヘッド)を伴う理由です。

システムコールは“ただの関数”より重い

ユーザー↔カーネルのモード切替には、レジスタの退避・復元や CPU の状態変更が伴い、関数呼び出しより桁違いに高コストです。だから「1バイトずつ read を1万回」より「まとめて読む」方が速い。標準ライブラリが内部でバッファリングしてシステムコール回数を減らすのは、まさにこのためです。

代表的なシステムコール

数百ありますが、まず押さえるべきはファイル系プロセス系です。

分類システムコール役割
ファイルopenファイルを開き、ファイルディスクリプタを得る
ファイルread / write開いたファイルから読む / へ書く
ファイルcloseファイルディスクリプタを閉じる
プロセスfork自分を複製して子プロセスを作る
プロセスexec今のプロセスを別のプログラムに置き換える
プロセスwait子プロセスの終了を待つ
プロセスexitプロセスを終了する

ファイル I/O:open → read/write → close

UNIX 系では「すべてはファイル」という思想があり、通常ファイルだけでなく、端末・パイプ・ソケット(ネットワーク通信)まで、同じ read/write で扱えます。open が返す ファイルディスクリプタ(fd=小さな整数) を、以降の操作で「どの対象か」を指す取っ手として使います。標準入力=0、標準出力=1、標準エラー=2 は、起動時から開いている fd です。

// ファイルを開いて中身を読む最小例(エラー処理は省略)
int fd = open("data.txt", O_RDONLY);   // ← システムコール
char buf[256];
ssize_t n = read(fd, buf, sizeof buf); // ← システムコール
close(fd);                             // ← システムコール

プロセス生成:fork と exec

UNIX で新しいプログラムを起動する定番は、fork で自分を複製し、その子で exec して別プログラムに化けるという二段構えです。シェルがコマンドを実行する仕組みもこれです。

親プロセス ──fork()──┬─ 親:そのまま続行(必要なら wait で子を待つ)
                     └─ 子:exec("/bin/ls") で ls に置き換わって実行
fork と exec が“別々”な理由

「複製」と「置き換え」を分けるのは一見まわりくどいですが、その隙間で子プロセスだけを細工できる強みがあります。たとえば子側で標準出力を別のファイルやパイプに付け替えてから exec すれば、リダイレクト(ls > out.txt)やパイプ(a | b)が自然に実現できます。分かれているからこそ柔軟なのです。

ライブラリ関数との関係

「じゃあ普段書く printffopen はシステムコール?」——いいえ、それらは 標準ライブラリ(C なら libc)の関数で、システムコールそのものではありません。多くのライブラリ関数が、内部でシステムコールを呼んでいるという関係です。

あなたのコード
   │  printf("hello")          ← ライブラリ関数(libc)
   ▼
標準ライブラリ(バッファリング・書式整形などを担当)
   │  write(1, ...)            ← システムコール(依頼)
   ▼
カーネル → 実際に端末やファイルへ出力
観点システムコールライブラリ関数
誰が実行カーネル(OS 側)アプリ側で動く(一部は内部で syscall)
read / write / open / forkprintf / fread / malloc / strlen
特権の壁越える(モード切替あり)基本は越えない
移植性OS ごとに異なる規格(POSIX/C 標準)で揃いやすい
主な役割ハード・資源への“依頼”整形・バッファ・利便性の提供

ライブラリ関数を挟む利点は2つ。1つは 移植性——OS ごとに違うシステムコールの差を吸収し、printf のような共通インターフェースを提供します。もう1つは 効率——前述のバッファリングでシステムコール回数を減らし、重いモード切替を節約します。malloc も同様に、必要なときだけ brk/mmap をまとめて呼び、細かな確保はライブラリ内で捌いています。

strlen はシステムコールではない

よくある誤解が「ライブラリ関数=システムコール」。strlenmemcpy、四則演算のような純粋な計算は、メモリ上で完結するのでカーネルに頼む必要がなく、システムコールは発生しません。システムコールが必要なのは、ハード・I/O・他プロセス・資源管理など「自分の権限では手が届かない領域」に触れるときだけ。これを取り違えると、性能の見積もり(どこが重いか)を大きく外します。

まとめ

まとめ

OS は保護のため世界を ユーザー空間とカーネル空間に分け、CPU の 特権モードで境界を守ります。アプリはハードや他プロセスに直接触れず、システムコールという窓口でカーネルに依頼する——read/write/open/close でファイルや通信を、fork/exec でプロセスを扱うのが基本形です。普段使う printffopen は、その下でシステムコールを呼ぶライブラリ関数にすぎません。この「依頼する仕組み」が腑に落ちると、プロセスとスレッド割り込みと I/Oメモリ管理といった OS の他テーマもぐっと見通しが良くなります。

OS Article

システムコールとカーネルを実務で読む

TL;DRは入口です。実際に選ぶ・使う段階では、何を解決するか、何と比較するか、導入後にどこで詰まるかまで見る必要があります。

解決すること

システムコール

比較で見る軸

難易度: intermediate / カテゴリ: OS / タグ数: 4

導入後に効く点

アプリはハードを直接触れない。ファイル・通信・プロセス生成などは すべて システムコールでカーネルに依頼する。

先に潰すリスク

用語だけ覚えても、設計・実装・運用でどこに効くかを確認しないと判断を誤る。

数字・仕様の読み方
難易度
intermediate
カテゴリ
OS
タグ数
4

判断チェックリスト

  • 自社の用途が「システムコール / カーネル」に近いか確認する。
  • 強みである「OS は世界を「ユーザー空間(アプリ)」と「カーネル空間(OS の中核)」に分け、CPU の特権モードで保護している。」が本当に評価軸になるか確認する。
  • 注意点の「用語だけ覚えても、設計・実装・運用でどこに効くかを確認しないと判断を誤る。」を運用で吸収できるか確認する。
  • 公開値や仕様値は、対象プラン・対象機種・対象リージョンまで確認する。
  • 既存システム、ID、ネットワーク、監視、バックアップとの接続方法を先に洗い出す。
  • 小さく試してから、本番移行、権限設計、障害時手順、コスト監視を決める。

次に確認する観点

システムコールカーネル特権モードOSシステムコールカーネル特権モードOS
参考: 公式情報