Download - プログラミングの基礎 第 2 回 systemcall
![Page 1: プログラミングの基礎 第 2 回 systemcall](https://reader035.vdocuments.mx/reader035/viewer/2022081420/56814541550346895db20b1c/html5/thumbnails/1.jpg)
プログラミングの基礎 第 2 回systemcall
workshop 資料作成委員会
![Page 2: プログラミングの基礎 第 2 回 systemcall](https://reader035.vdocuments.mx/reader035/viewer/2022081420/56814541550346895db20b1c/html5/thumbnails/2.jpg)
本ワークショップの目標 システムコールの仕組みを理解する
カーネルモードとユーザモード ソフトウェア割り込み
演習 実際にシステムコールを直接呼んでみる システムコールを使ったプログラミング
![Page 3: プログラミングの基礎 第 2 回 systemcall](https://reader035.vdocuments.mx/reader035/viewer/2022081420/56814541550346895db20b1c/html5/thumbnails/3.jpg)
table of contents
1. システムコール概要2. カーネルモードユーザーモード3. ソフトウェア割り込み4. システムコール実例5. 演習:
![Page 4: プログラミングの基礎 第 2 回 systemcall](https://reader035.vdocuments.mx/reader035/viewer/2022081420/56814541550346895db20b1c/html5/thumbnails/4.jpg)
プログラミングとは? コンピュータのデバイスを操作する命令手
順を書くこと
プログラミング
メモリディスプレイに出力する命令手順
ディスプレイデバイス
Hello!
![Page 5: プログラミングの基礎 第 2 回 systemcall](https://reader035.vdocuments.mx/reader035/viewer/2022081420/56814541550346895db20b1c/html5/thumbnails/5.jpg)
OS はすべてのデバイスを管理する OS 上でプログラミングするには?
OS に対してデバイスを操作する命令を発行
OS
画面に文字を出力するプログラム
![Page 6: プログラミングの基礎 第 2 回 systemcall](https://reader035.vdocuments.mx/reader035/viewer/2022081420/56814541550346895db20b1c/html5/thumbnails/6.jpg)
プログラム例 画面に” Hello!” を出力する printf
プログラミング
ディスプレイデバイス
Hello!write()
出力関数( OS の機能 )
出力命令を発行
実際に制御
![Page 7: プログラミングの基礎 第 2 回 systemcall](https://reader035.vdocuments.mx/reader035/viewer/2022081420/56814541550346895db20b1c/html5/thumbnails/7.jpg)
書いたプログラムを動かす!
ソースコード オブジェクトコード
コンパイル リンクhello.ohello.c a.out
実行プログラム
Hello!
実行
![Page 8: プログラミングの基礎 第 2 回 systemcall](https://reader035.vdocuments.mx/reader035/viewer/2022081420/56814541550346895db20b1c/html5/thumbnails/8.jpg)
a.out の構成 元の hello.o よりもサイズが大きくなる
hello.o
a.out
C ランタイムオブジェクトlibC への参照
自分で書いた部分
![Page 9: プログラミングの基礎 第 2 回 systemcall](https://reader035.vdocuments.mx/reader035/viewer/2022081420/56814541550346895db20b1c/html5/thumbnails/9.jpg)
実習:a.out から C ランタイムと libc を削除する
![Page 10: プログラミングの基礎 第 2 回 systemcall](https://reader035.vdocuments.mx/reader035/viewer/2022081420/56814541550346895db20b1c/html5/thumbnails/10.jpg)
前準備
Hello, world! を作ってね! FreeBSD か Linux ホストでお願いします.
#include <stdio.h>#define MESSAGE “Hello, world!¥n”
int main() { printf(MESSAGE); return(123);}
Example program
ちなみに,この時点でコードサイズは…11368 バイト!
![Page 11: プログラミングの基礎 第 2 回 systemcall](https://reader035.vdocuments.mx/reader035/viewer/2022081420/56814541550346895db20b1c/html5/thumbnails/11.jpg)
これから… 邪魔なリンクファイル (crt* C ランタイ
ムファイル ) を消そう そのかわり、 C ランタイムがやってくれてい
たことは全部自分でやらなければいけません。 これにより、プログラムがどのように動く(動
かされている)のか知ることができます。 いらないセクションを消そう
![Page 12: プログラミングの基礎 第 2 回 systemcall](https://reader035.vdocuments.mx/reader035/viewer/2022081420/56814541550346895db20b1c/html5/thumbnails/12.jpg)
邪魔なリンクファイルを消そう! 先ほどの説明で, crt* ファイルがコンパ
イル時にリンクされていることがわかりました.
リンクしないように, -nostartfiles をつけてみましょう.
![Page 13: プログラミングの基礎 第 2 回 systemcall](https://reader035.vdocuments.mx/reader035/viewer/2022081420/56814541550346895db20b1c/html5/thumbnails/13.jpg)
21:55 [0] skk@aries% gcc -v hello.c Using built-in specs.Configured with: FreeBSD/i386 system compilerThread model: posixgcc version 3.4.4 [FreeBSD] 20050518 ・・・ /usr/bin/ld -V -dynamic-linker /libexec/ld-elf.so.1 /usr/lib/crt1.o /usr/lib/crti.o /usr/lib/crtbegin.o -L/usr/lib /var/tmp//ccdlOU3m.o -lgcc -lc -lgcc /usr/lib/crtend.o /usr/lib/crtn.oGNU ld version 2.15 [FreeBSD] 2004-05-23 Supported emulations: elf_i386_fbsd
![Page 14: プログラミングの基礎 第 2 回 systemcall](https://reader035.vdocuments.mx/reader035/viewer/2022081420/56814541550346895db20b1c/html5/thumbnails/14.jpg)
21:55 [0] skk@aries% gcc -v -nostartfiles hello.c Using built-in specs.Configured with: FreeBSD/i386 system compilerThread model: posixgcc version 3.4.4 [FreeBSD] 20050518 /usr/libexec/cc1 -quiet -v -D_LONGLONG hello.c -quiet -dumpbase hello.c -auxbase hello –・・・ elf_i386_fbsd/usr/bin/ld: warning: cannot find entry symbol _start; defaulting to 0000000008048200/usr/lib/libc.so: undefined reference to `environ'/usr/lib/libc.so: undefined reference to `__progname'
![Page 15: プログラミングの基礎 第 2 回 systemcall](https://reader035.vdocuments.mx/reader035/viewer/2022081420/56814541550346895db20b1c/html5/thumbnails/15.jpg)
warning: cannot find entry symbol _start; defaulting to 0000000008048200
「 _start というシンボルが見つからないー.仕方ないから, .text セクションの先頭アドレスを開始アドレスにしちゃうもんね.」という意味。 _start は crt1.o ( C ランタイム)の中にある関数で、
プログラム実行時に最初に呼び出される。今回は crt1.o を丸ごと消したいので使えない。
プログラムの開始アドレスを _start じゃなく,main にしたい!
![Page 16: プログラミングの基礎 第 2 回 systemcall](https://reader035.vdocuments.mx/reader035/viewer/2022081420/56814541550346895db20b1c/html5/thumbnails/16.jpg)
開始アドレスの変更 ld コマンドの -e オプションで変更できます! -e の後ろには,シンボル名を指定します.
% gcc -c hello.c % ld -e main -o a.out hello.o hello.o(.text+0x25): In function `main':: undefined reference to `printf'
![Page 17: プログラミングの基礎 第 2 回 systemcall](https://reader035.vdocuments.mx/reader035/viewer/2022081420/56814541550346895db20b1c/html5/thumbnails/17.jpg)
printf() がない??• -lgcc -lc を削除したことに注目しましょう。
前者は gcc 固有ライブラリ、後者は libc ライブラリをリンクするためのものです。
ですが今回はとっちゃいます。なぜでしょう? ライブラリとは
ライブラリは、便利な関数を集めていつでも使えるようにしておいたファイルです。 libc にはさまざまな C 言語の標準関数が含まれています。
printf, もその一つなのです。 逆に言うと、 Hello World! を表示するだけのプログラムでは、 printf の
機能だけ使えればいいので、ライブラリ全てをリンクするのは無駄です。
そこで printf に相当する機能を自分で作ります。
-> そうだ! write() だ!
![Page 18: プログラミングの基礎 第 2 回 systemcall](https://reader035.vdocuments.mx/reader035/viewer/2022081420/56814541550346895db20b1c/html5/thumbnails/18.jpg)
C ランタイムと LibC の役割 C ランタイム
C 言語で書かれたプログラムを動作させる環境
LibC C 言語から OS の機能を抽象化して使いやすくす
る
C ランタイム
USE
![Page 19: プログラミングの基礎 第 2 回 systemcall](https://reader035.vdocuments.mx/reader035/viewer/2022081420/56814541550346895db20b1c/html5/thumbnails/19.jpg)
LibC の役割 OS の機能を抽象化してくれる!
OS
LibC
printf は僕が持ってます
システムコール
OS とのインタフェース( 窓口 ) です
![Page 20: プログラミングの基礎 第 2 回 systemcall](https://reader035.vdocuments.mx/reader035/viewer/2022081420/56814541550346895db20b1c/html5/thumbnails/20.jpg)
C ライブラリとシステムコール C ライブラリはシステムコールのラッパー
を提供する より使いやすく可搬性を高めるため
デバイス
カーネル
プロセス プロセス プロセス
システムコールユーザモード
libc
普通は C ライブラリの中でシステムコールを呼んでく
れる
![Page 21: プログラミングの基礎 第 2 回 systemcall](https://reader035.vdocuments.mx/reader035/viewer/2022081420/56814541550346895db20b1c/html5/thumbnails/21.jpg)
システムコール概要
![Page 22: プログラミングの基礎 第 2 回 systemcall](https://reader035.vdocuments.mx/reader035/viewer/2022081420/56814541550346895db20b1c/html5/thumbnails/22.jpg)
システムコールとは? OS(OS のカーネル)の機能を呼び出すた
めに使用される機構のこと システムをカーネルに制御を移すための特別
な命令を実行し、カーネルの機能を呼ぶ
プロセス OS 資源の利用( デバイス、メモリ空間など )
システムコールの実行
![Page 23: プログラミングの基礎 第 2 回 systemcall](https://reader035.vdocuments.mx/reader035/viewer/2022081420/56814541550346895db20b1c/html5/thumbnails/23.jpg)
プロセスとかカーネルって? プロセス
アプリケーションの実行単位 カーネル
アプリケーションが動作する実行環境を提供
デバイス
カーネル
プロセス プロセス プロセス
![Page 24: プログラミングの基礎 第 2 回 systemcall](https://reader035.vdocuments.mx/reader035/viewer/2022081420/56814541550346895db20b1c/html5/thumbnails/24.jpg)
システムコールがあると何がうれしいの? システムのセキュリテが向上する
カーネルが処理を実行する前に処理要求の正当性を確認できる
プログラミングが楽になる ハードウェアに関する低水準レイヤについて
覚えなくてよくなる プログラムの可搬性が向上
カーネルが同じインタフェースを提供する限りにおいて
![Page 25: プログラミングの基礎 第 2 回 systemcall](https://reader035.vdocuments.mx/reader035/viewer/2022081420/56814541550346895db20b1c/html5/thumbnails/25.jpg)
プログラミングの基礎における意味 プログラミングする上で、 OS の存在を意
識できるようになる この API を呼ぶと、カーネルに制御が移り OS
の資源を利用できる
プロセス カーネル
制御の移り変わり
普通にプログラミングする場合、システムコールを直接呼ぶことは
しません
![Page 26: プログラミングの基礎 第 2 回 systemcall](https://reader035.vdocuments.mx/reader035/viewer/2022081420/56814541550346895db20b1c/html5/thumbnails/26.jpg)
システムコールの特徴 CPU の実行権限を切り替える 割り込みによる実行 OS とアプリケーションの中間層
詳細は、この後に解説
![Page 27: プログラミングの基礎 第 2 回 systemcall](https://reader035.vdocuments.mx/reader035/viewer/2022081420/56814541550346895db20b1c/html5/thumbnails/27.jpg)
カーネルモードとユーザーモード
![Page 28: プログラミングの基礎 第 2 回 systemcall](https://reader035.vdocuments.mx/reader035/viewer/2022081420/56814541550346895db20b1c/html5/thumbnails/28.jpg)
概要 カーネルモードとユーザモード
セキュリティと安全性のため異なる特権状態で命令を実行する
異なる CPU のランレベルを利用する Linux では特権モードと非特権モードの 2 つ
を使い分ける
![Page 29: プログラミングの基礎 第 2 回 systemcall](https://reader035.vdocuments.mx/reader035/viewer/2022081420/56814541550346895db20b1c/html5/thumbnails/29.jpg)
カーネルモード あらゆるハードウェア資源にアクセス可能 オペレーティングシステムの実行モード
デバイス
カーネル
プロセス プロセス プロセス
システムコール
ユーザモード
カーネルモード
![Page 30: プログラミングの基礎 第 2 回 systemcall](https://reader035.vdocuments.mx/reader035/viewer/2022081420/56814541550346895db20b1c/html5/thumbnails/30.jpg)
ユーザモード ハードウェア資源へのアクセスを制限・監視下でプログラムを実行
通常のプログラムの実行モード
デバイス
カーネル
プロセス プロセス プロセス
システムコール
ユーザモード
カーネルモード
![Page 31: プログラミングの基礎 第 2 回 systemcall](https://reader035.vdocuments.mx/reader035/viewer/2022081420/56814541550346895db20b1c/html5/thumbnails/31.jpg)
CPU のランレベル 多くの CPU は 2 つ以上の実行モードを保有 実行レベルを使い分けることで安全性、安定
性を向上させる Intel 80x 86 は 4 つの実行リング ( 特権の階
層 ) を持つ
ランレベル 0 をカーネルモードそれ以上をユーザモードに割り当てる
![Page 32: プログラミングの基礎 第 2 回 systemcall](https://reader035.vdocuments.mx/reader035/viewer/2022081420/56814541550346895db20b1c/html5/thumbnails/32.jpg)
CPU ランレベル移行 コールゲートによるランレベルの移行
コールゲートを解した呼び出しだけが許される 特権レベルの低いコードセグメントから特権レベルの
高いコードセグメントの呼び出し
![Page 33: プログラミングの基礎 第 2 回 systemcall](https://reader035.vdocuments.mx/reader035/viewer/2022081420/56814541550346895db20b1c/html5/thumbnails/33.jpg)
コールゲート OS がランレベルの移行をコントロールできる機
構 ゲートを経由しないと移行できない 呼び出せる特権レベルのゲートは現動作レベル以下だ
け
特権レベル3のコールゲート
移行先
![Page 34: プログラミングの基礎 第 2 回 systemcall](https://reader035.vdocuments.mx/reader035/viewer/2022081420/56814541550346895db20b1c/html5/thumbnails/34.jpg)
システムコールの本質 CPU ランレベルを切り替えて、プログラム
がデバイスを操作できるようにする仕組み
プロセス 1
システムコールハンドラ
ユーザモード
カーネルモード
システムコールデバイスを操作できる領域
![Page 35: プログラミングの基礎 第 2 回 systemcall](https://reader035.vdocuments.mx/reader035/viewer/2022081420/56814541550346895db20b1c/html5/thumbnails/35.jpg)
ランモードの切り替え方法 ソフトウェア割り込み(システムコールが
使う) タイマ割り込み デバイス割り込み 例外割り込み
プロセス 1
システムコールハンドラ
ユーザモード
カーネルモード
システムコール
スケジューラ
プロセス 1
タイマ割り込み
割り込みハンドラ
プロセス 1
デバイス割り込み
![Page 36: プログラミングの基礎 第 2 回 systemcall](https://reader035.vdocuments.mx/reader035/viewer/2022081420/56814541550346895db20b1c/html5/thumbnails/36.jpg)
ソフトウェア割り込み
![Page 37: プログラミングの基礎 第 2 回 systemcall](https://reader035.vdocuments.mx/reader035/viewer/2022081420/56814541550346895db20b1c/html5/thumbnails/37.jpg)
概要 システムコールはソフトウェア割り込み
で行 割り込みベクターは 0x80 システムコールの引数は,すべてレジスタで渡される
システムコールを実行する手順1. レジスタに必要な値を設定2. int 0x80 を実行する
![Page 38: プログラミングの基礎 第 2 回 systemcall](https://reader035.vdocuments.mx/reader035/viewer/2022081420/56814541550346895db20b1c/html5/thumbnails/38.jpg)
システムコールが利用するレジスタ
![Page 39: プログラミングの基礎 第 2 回 systemcall](https://reader035.vdocuments.mx/reader035/viewer/2022081420/56814541550346895db20b1c/html5/thumbnails/39.jpg)
システムコールの流れ Linux の場合
1. システムコール番号を eax レジスタにセット2. 必要に応じてほかの引数もレジスタにセット3. int 0x80 ソフトウェア割り込みを発行4. カーネルモードスタック上にレジスタ内容を退避
5. システムコールサービスルーチンを呼び出す6. システムコールの実処理7. ハンドラから抜ける
![Page 40: プログラミングの基礎 第 2 回 systemcall](https://reader035.vdocuments.mx/reader035/viewer/2022081420/56814541550346895db20b1c/html5/thumbnails/40.jpg)
システムコールの流れ図
system_call:・・・sys_xyz()・・・iret
sys_xyz(){・・・}
xyz(){
・・・
int 0x80
・・・
}
・ ・ ・
xyz()
・ ・ ・
アプリケーションプログラムからのシステムコール発行
libc 標準ライブラリのラッパールーチン
システムコールハンドラ
システムコールサービスルーチン
ユーザモード カーネルモード
eax 38ebx "param1"
(38: sys_xyzのシステムコール 番号とする )
システムコール番号や引数をセット
![Page 41: プログラミングの基礎 第 2 回 systemcall](https://reader035.vdocuments.mx/reader035/viewer/2022081420/56814541550346895db20b1c/html5/thumbnails/41.jpg)
C ライブラリとシステムコール C ライブラリはシステムコールのラッパー
を提供する より使いやすく可搬性を高めるため
デバイス
カーネル
プロセス プロセス プロセス
システムコールユーザモード
libc
普通は C ライブラリの中でシステムコールを呼んでく
れる
![Page 42: プログラミングの基礎 第 2 回 systemcall](https://reader035.vdocuments.mx/reader035/viewer/2022081420/56814541550346895db20b1c/html5/thumbnails/42.jpg)
システムコール実例
![Page 43: プログラミングの基礎 第 2 回 systemcall](https://reader035.vdocuments.mx/reader035/viewer/2022081420/56814541550346895db20b1c/html5/thumbnails/43.jpg)
システムコール リスト Linux
#define __NR_exit 1#define __NR_fork 2#define __NR_read 3#define __NR_write 4#define __NR_open 5#define __NR_close 6#define __NR_waitpid 7#define __NR_creat 8#define __NR_link 9#define __NR_unlink 10#define __NR_execve 11#define __NR_chdir 12#define __NR_time 13#define __NR_mknod 14#define __NR_chmod 15#define __NR_lchown 16
![Page 44: プログラミングの基礎 第 2 回 systemcall](https://reader035.vdocuments.mx/reader035/viewer/2022081420/56814541550346895db20b1c/html5/thumbnails/44.jpg)
システムコール リスト FreeBSD
#define SYS_syscall 0#define SYS_exit 1#define SYS_fork 2#define SYS_read 3#define SYS_write 4#define SYS_open 5#define SYS_close 6#define SYS_wait4 7/* 8 is old creat */#define SYS_link 9#define SYS_unlink 10
/* 11 is obsolete execv */#define SYS_chdir 12#define SYS_fchdir 13#define SYS_mknod 14#define SYS_chmod 15#define SYS_chown 16#define SYS_break 17 /* 18 is old getfsstat *//* 19 is old lseek */#define SYS_getpid 20#define SYS_mount 21
![Page 45: プログラミングの基礎 第 2 回 systemcall](https://reader035.vdocuments.mx/reader035/viewer/2022081420/56814541550346895db20b1c/html5/thumbnails/45.jpg)
strate でシステムコールをトレースする strace って?
システムコールのトレースを行ってくれる! strace の仕組み
システムコールの enter と exit をフックして引数と返り値を出力する OS のデバック用インタフェースを用いる
システムコールユーザモード
カーネルモード
Strace
フック フック
![Page 46: プログラミングの基礎 第 2 回 systemcall](https://reader035.vdocuments.mx/reader035/viewer/2022081420/56814541550346895db20b1c/html5/thumbnails/46.jpg)
strace: emacs on linux の一部出力
execve("/usr/bin/emacs", ["emacs"], [/* 21 vars */]) = 0uname({sys="Linux", node="einstein", ...}) = 0brk(0) = 0x8424000old_mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x40017000access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory)open("/etc/ld.so.preload", O_RDONLY) = -1 ENOENT (No such file or directory)close(3) = 0read(3, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0\220\342"..., 512) = 512
![Page 47: プログラミングの基礎 第 2 回 systemcall](https://reader035.vdocuments.mx/reader035/viewer/2022081420/56814541550346895db20b1c/html5/thumbnails/47.jpg)
演習:直接システムコールを呼ぼう
システムコールを使った helloworld 出力(前回既にできた人は必要なし )
![Page 48: プログラミングの基礎 第 2 回 systemcall](https://reader035.vdocuments.mx/reader035/viewer/2022081420/56814541550346895db20b1c/html5/thumbnails/48.jpg)
システムコールを呼ぼう システムコールには,番号がついていま
す. Linux: /usr/include/asm/unistd.h FreeBSD: /usr/include/sys/syscall.h
#define SYS_syscall 0#define SYS_exit 1#define SYS_fork 2#define SYS_read 3#define SYS_write 4#define SYS_open 5#define SYS_close 6#define SYS_wait4 7
$FreeBSD: src/sys/sys/syscall.h,v 1.178.2.1 2005/11/21 01:36:27 csjp Exp $
![Page 49: プログラミングの基礎 第 2 回 systemcall](https://reader035.vdocuments.mx/reader035/viewer/2022081420/56814541550346895db20b1c/html5/thumbnails/49.jpg)
システムコール〜引数の渡し方〜 Linux FreeBSD
EAX レジスタ システムコール番号EBX レジスタ 第一引数ECX レジスタ 第二引数EDX レジスタ 第三引数ESI レジスタ 第四引数EDI レジスタ 第五引数
引数の順番と逆にスタックに積んでいく
mov $4, %eaxmov $1, %ebxmov buf, %ecxmov length, %edxint 0x80
push lengthpush bufpush $1push $4int 0x80
![Page 50: プログラミングの基礎 第 2 回 systemcall](https://reader035.vdocuments.mx/reader035/viewer/2022081420/56814541550346895db20b1c/html5/thumbnails/50.jpg)
Linux FreeBSDconst char message[] = "hello world¥n";int writes(const char *buf, int len) { int ret; asm( "int $0x80" : "=a" (ret) : "a" (4), "b" (1), "c" (buf), "d" (len) ); return(ret);}int main() { int ret; ret = writes(message, sizeof(message)); return(ret);}
const char message[] = "hello world¥n";int writes(const char *buf, int len) { int ret; asm("nop" :: "b"(len)); asm ("pushl %ebx"); asm("nop" :: "c"(buf)); asm("pushl %ecx"); asm("pushl $1"); asm("movl $0x4, %eax"); asm("pushl %eax"); asm("int $0x80"); asm("addl $12, %esp"); return(ret);}int main() { int ret; ret = writes(message, sizeof(message)); return(ret);}
システムコールで helloworld
![Page 51: プログラミングの基礎 第 2 回 systemcall](https://reader035.vdocuments.mx/reader035/viewer/2022081420/56814541550346895db20b1c/html5/thumbnails/51.jpg)
コンパイル&実行!
% gcc -o helloworld helloworld% ./helloworld
hello world