11月毎日投稿企画1日目です! 学んだ内容を自分なりに少しでも噛み砕けたら勝ち。そんなメモです。
プログラムとプロセスの違い
プログラムとは コンピュータ上で動作する一連の命令、およびデータをひとまとめにしたもの。ソースコードやコンパイルした実行ファイルがこれにあたる。
プロセスとは 起動後に動作中のプログラムのこと。今後はこの定義で語っていこう。
カーネルって簡単に言えばなんだろう
やばい命令、壊れる可能性のある危険な命令を行うプログラムという認識。
私たちが書いているソースコードも、カーネルも同じプログラムであることは変わりない。ただし、そのプログラムが使用できる機能が制限されているか、全ての機能が使えるかが、カーネルか否かを分ける。
モードによる違い
CPUには「モード」という機能がある:
- ユーザモード: ユーザーランドで実行。危険な命令は実行できない
- カーネルモード: 全ての命令が実行できる
疑問点
- OSはカーネルの上に乗っている感じなのだろうか
- OSもプログラム、つまりソースコードや実行ファイルの集まりなのだろうか
- OSの中にカーネルモードのプログラムとユーザモードのプログラムがあるという解釈でいいのか
システムコールって簡単に言えばなんだろう
システムコールとは プロセスがカーネルに処理を依頼するための方法。
ユーザランドで動いているプロセスが、カーネルモードで動くカーネルでしかできない処理をお願いすること。カーネルは正当なものなのか判断し、正当でないならエラーを返す。
疑問点
プログラムはプログラムごとにユーザモードとかカーネルモードが決まっているのではなく、処理中に変えることができたりするのか? つまり、カーネルもユーザも同じプログラム上に共存することはできるのか?
システムコールを可視化する
straceコマンド (Linux)
Linuxではstraceコマンドで可視化できる:
bash
strace -o hello.log ./hello
-oオプションで出力先を指定できる。
Macでの代替手段
Macではstraceが使えない。代わりにdtrussコマンドがあるが、SIP (System Integrity Protection) の制限により完全には動作しない。
試した結果:
sudo dtruss ./a.out
# → SIPの制限で一部機能が使えない
sudo fs_usage -w -f filesystem ./a.out
# → うまく動作せず
結論: Ubuntu環境やVPSで実験することにする。
システムコールの出力例
c
write(1, "hello world\n", 12) = 12
このようにwriteというシステムコールが呼ばれていることが確認できる。
sarコマンドでCPUの様子を観察する
Linuxの場合
sar -P 0 1 1
CPUコア0を1秒ごとに採取、それを1回だけ取り出す。
Macの場合
sarコマンドは存在しない。代わりにtopコマンドを使用:
```bash
top -l 1 -n 0
```
出力が複雑で解釈が難しい。こちらもUbuntu環境で再実験予定。
ライブラリ
多くの人が使うであろうプログラムは、OSがライブラリとして提供している。
標準Cライブラリ
C言語には、ISO (国際標準化機構) によって定められた標準ライブラリがある。通常はGNUプロジェクトが提供するglibcを標準Cライブラリとして使用する。
プログラムがどのライブラリをリンクしているかはlddコマンドで確認できる (Macでは使用不可)。
Python、Go、bashコマンドでさえも標準Cライブラリを使っている。つまり、これらは全てC言語のプログラムを使っているということ。
C言語の高速化はこの世の高速化と言っても過言ではないかもしれない
システムコールのラッパー関数としてのlibc
システムコールは通常、アーキテクチャ依存のアセンブリプログラム上でしか呼び出せない。それをC言語でラップしたものをlibcとして提供している。
もしlibcがなければ、どの高級言語を使うときも、システムコール周りは一回アセンブリコードを書いてそれを呼び出すという工程が挟まる。非常に面倒だし、高級ではなくなる。
libcありがたや
静的ライブラリと共有ライブラリ
静的ライブラリ リンク時にライブラリ内の関数をプログラムに組み込む。ファイルサイズが大きくなるが、どこでも同じように動く。
共有ライブラリ リンク時には「このライブラリのこの関数を呼び出す」という情報だけを実行ファイルに埋め込む。プログラムの起動時、あるいは実行中に、ライブラリをメモリ上にロードして実行する。
共有ライブラリが主流だったが、最近はGoが静的リンクを使うなど、静的ライブラリが復権している。
今後調べたいこと
- 「メモリに載せる」という概念の正確な理解
- clangなどのコンパイラの歴史と種類
- モード切り替えの詳細な仕組み