Presentation is loading. Please wait.

Presentation is loading. Please wait.

プログラミングの基礎 第2回 systemcall

Similar presentations


Presentation on theme: "プログラミングの基礎 第2回 systemcall"— Presentation transcript:

1 プログラミングの基礎 第2回 systemcall
workshop 資料作成委員会

2 本ワークショップの目標 システムコールの仕組みを理解する 演習 カーネルモードとユーザモード ソフトウェア割り込み
実際にシステムコールを直接呼んでみる システムコールを使ったプログラミング

3 table of contents システムコール概要 カーネルモードユーザーモード ソフトウェア割り込み システムコール実例 演習:

4 プログラミングとは? Hello! コンピュータのデバイスを操作する命令手順を書くこと メモリ ディスプレイ ディスプレイに デバイス
出力する命令手順 プログラミング

5 OSはすべてのデバイスを管理する OS OS上でプログラミングするには? OSに対してデバイスを操作する命令を発行 画面に文字を 出力する
プログラム

6 プログラム例 Hello! 画面に”Hello!”を出力するprintf プログラミング 出力命令を発行 write() 実際に制御
出力関数(OSの機能) ディスプレイ デバイス

7 書いたプログラムを動かす! リンク コンパイル hello.c a.out hello.o ソースコード オブジェクトコード 実行プログラム

8 a.outの構成 元のhello.oよりもサイズが大きくなる Cランタイムオブジェクト libCへの参照 hello.o a.out
自分で書いた部分

9 実習: a.outからCランタイムとlibcを削除する

10 前準備 11368 バイト! Hello, world! を作ってね! FreeBSD か Linux ホストでお願いします.
#include <stdio.h> #define MESSAGE “Hello, world!¥n” int main() { printf(MESSAGE); return(123); } Example program ちなみに,この時点でコードサイズは… 11368 バイト!

11 これから… 邪魔なリンクファイル (crt* Cランタイムファイル) を消そう いらないセクションを消そう
これにより、プログラムがどのように動く(動かされている)のか知ることができます。 いらないセクションを消そう

12 邪魔なリンクファイルを消そう! 先ほどの説明で,crt* ファイルがコンパイル時にリンクされていることがわかりました. リンクしないように,-nostartfiles をつけてみましょう.

13 21:55 [0] skk@aries% gcc -v hello.c
Using built-in specs. Configured with: FreeBSD/i386 system compiler Thread model: posix gcc version [FreeBSD] ・・・ /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.o GNU ld version 2.15 [FreeBSD] Supported emulations: elf_i386_fbsd

14 21:55 [0] skk@aries% gcc -v -nostartfiles hello.c
Using built-in specs. Configured with: FreeBSD/i386 system compiler Thread model: posix gcc version [FreeBSD] /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 /usr/lib/libc.so: undefined reference to `environ' /usr/lib/libc.so: undefined reference to `__progname'

15 プログラムの開始アドレスを _start じゃなく,main にしたい!
warning: cannot find entry symbol _start; defaulting to 「_start というシンボルが見つからないー.仕方ないから,.text セクションの先頭アドレスを開始アドレスにしちゃうもんね.」という意味。 _startはcrt1.o(Cランタイム)の中にある関数で、プログラム実行時に最初に呼び出される。今回はcrt1.oを丸ごと消したいので使えない。 プログラムの開始アドレスを _start じゃなく,main にしたい!

16 開始アドレスの変更 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'

17 printf() がない?? -> そうだ! write() だ! -lgcc -lc を削除したことに注目しましょう。
前者はgcc固有ライブラリ、後者はlibcライブラリをリンクするためのものです。 ですが今回はとっちゃいます。なぜでしょう? ライブラリとは ライブラリは、便利な関数を集めていつでも使えるようにしておいたファイルです。 libcにはさまざまなC言語の標準関数が含まれています。 printf,もその一つなのです。 逆に言うと、Hello World!を表示するだけのプログラムでは、printfの機能だけ使えればいいので、ライブラリ全てをリンクするのは無駄です。 そこで printfに相当する機能を自分で作ります。 -c で,何もリンクしないオブジェクトファイルを作成して,自分で実行形式を作成しているもん.Printf とリンクする時間,ないよね. -> そうだ! write() だ!

18 CランタイムとLibCの役割 Cランタイム C言語で書かれたプログラムを動作させる環境 LibC
C言語からOSの機能を抽象化して使いやすくする USE Cランタイム

19 LibCの役割 OSの機能を抽象化してくれる! printfは僕が持ってます LibC OSとのインタフェース (窓口)です システムコール

20 普通はCライブラリの中でシステムコールを呼んでくれる
より使いやすく可搬性を高めるため 普通はCライブラリの中でシステムコールを呼んでくれる プロセス プロセス プロセス libc ユーザモード システムコール カーネル デバイス

21 システムコール概要

22 システムコールとは? OS(OSのカーネル)の機能を呼び出すために使用される機構のこと
システムをカーネルに制御を移すための特別な命令を実行し、カーネルの機能を呼ぶ OS資源の利用 (デバイス、メモリ空間など) システムコールの実行 プロセス

23 プロセスとかカーネルって? プロセス カーネル アプリケーションの実行単位 アプリケーションが動作する実行環境を提供 プロセス プロセス
デバイス

24 システムコールがあると何がうれしいの? システムのセキュリテが向上する プログラミングが楽になる プログラムの可搬性が向上
カーネルが処理を実行する前に処理要求の正当性を確認できる プログラミングが楽になる ハードウェアに関する低水準レイヤについて覚えなくてよくなる プログラムの可搬性が向上 カーネルが同じインタフェースを提供する限りにおいて

25 普通にプログラミングする場合、システムコールを直接呼ぶことはしません
プログラミングの基礎における意味 プログラミングする上で、OSの存在を意識できるようになる このAPIを呼ぶと、カーネルに制御が移りOSの資源を利用できる プロセス カーネル 制御の移り変わり 普通にプログラミングする場合、システムコールを直接呼ぶことはしません

26 システムコールの特徴 CPUの実行権限を切り替える 割り込みによる実行 OSとアプリケーションの中間層 詳細は、この後に解説

27 カーネルモードとユーザーモード

28 概要 カーネルモードとユーザモード 異なるCPUのランレベルを利用する セキュリティと安全性のため異なる特権状態で命令を実行する
Linuxでは特権モードと非特権モードの2つを使い分ける

29 カーネルモード あらゆるハードウェア資源にアクセス可能 オペレーティングシステムの実行モード プロセス プロセス プロセス ユーザモード
システムコール カーネル カーネルモード デバイス

30 ユーザモード ハードウェア資源へのアクセスを制限・監視下でプログラムを実行 通常のプログラムの実行モード プロセス プロセス プロセス
システムコール カーネル カーネルモード デバイス

31 CPUのランレベル 多くのCPUは2つ以上の実行モードを保有 実行レベルを使い分けることで安全性、安定性を向上させる
Intel 80x86は4つの実行リング(特権の階層)を持つ ランレベル0をカーネルモード それ以上をユーザモードに割り当てる

32 CPUランレベル移行 コールゲートによるランレベルの移行 コールゲートを解した呼び出しだけが許される
特権レベルの低いコードセグメントから特権レベルの高いコードセグメントの呼び出し

33 コールゲート OSがランレベルの移行をコントロールできる機構 ゲートを経由しないと移行できない
呼び出せる特権レベルのゲートは現動作レベル以下だけ 移行先 特権レベル3の コールゲート

34 システムコールの本質 CPUランレベルを切り替えて、プログラムがデバイスを操作できるようにする仕組み デバイスを操作 できる領域 プロセス1
ユーザモード カーネルモード デバイスを操作 できる領域 システムコール システムコール ハンドラ

35 ランモードの切り替え方法 ソフトウェア割り込み(システムコールが使う) タイマ割り込み デバイス割り込み 例外割り込み プロセス1
ユーザモード カーネルモード システムコール タイマ割り込み デバイス割り込み システムコール ハンドラ スケジューラ 割り込みハンドラ

36 ソフトウェア割り込み

37 概要 システムコールはソフトウェア割り込みで行 システムコールを実行する手順 割り込みベクターは 0x80
システムコールの引数は,すべてレジスタで渡される システムコールを実行する手順 レジスタに必要な値を設定 int 0x80 を実行する

38 システムコールが利用するレジスタ

39 システムコールの流れ Linuxの場合 システムコール番号をeaxレジスタにセット 必要に応じてほかの引数もレジスタにセット
int 0x80ソフトウェア割り込みを発行 カーネルモードスタック上にレジスタ内容を退避 システムコールサービスルーチンを呼び出す システムコールの実処理 ハンドラから抜ける

40 システムコールの流れ図 (38: sys_xyzのシステムコール 番号とする) システムコール番号 や引数をセット カーネルモード
ユーザモード system_call: ・・・ sys_xyz() iret ・・・ xyz() xyz(){ ・・・ int 0x80 } sys_xyz(){ ・・・ } システムコール ハンドラ システムコール サービスルーチン アプリケーション プログラムからの システムコール発行 libc標準ライブラリ のラッパールーチン

41 普通はCライブラリの中でシステムコールを呼んでくれる
より使いやすく可搬性を高めるため 普通はCライブラリの中でシステムコールを呼んでくれる プロセス プロセス プロセス libc ユーザモード システムコール カーネル デバイス

42 システムコール実例

43 システムコール リスト Linux #define __NR_exit 1 #define __NR_fork 2
システムコール リスト Linux #define __NR_exit #define __NR_fork #define __NR_read #define __NR_write #define __NR_open #define __NR_close #define __NR_waitpid #define __NR_creat #define __NR_link #define __NR_unlink #define __NR_execve #define __NR_chdir #define __NR_time #define __NR_mknod #define __NR_chmod #define __NR_lchown

44 システムコール リスト FreeBSD /* 11 is obsolete execv */ #define SYS_syscall 0
システムコール リスト FreeBSD /* 11 is obsolete execv */ #define SYS_chdir #define SYS_fchdir #define SYS_mknod #define SYS_chmod #define SYS_chown #define SYS_break /* 18 is old getfsstat */ /* 19 is old lseek */ #define SYS_getpid #define SYS_mount #define SYS_syscall 0 #define SYS_exit #define SYS_fork #define SYS_read #define SYS_write #define SYS_open #define SYS_close #define SYS_wait /* 8 is old creat */ #define SYS_link #define SYS_unlink

45 strateでシステムコールをトレースする
straceって? システムコールのトレースを行ってくれる! straceの仕組み システムコールのenterとexitをフックして引数と返り値を出力する OSのデバック用インタフェースを用いる Strace フック フック ユーザモード システムコール カーネルモード

46 strace: emacs on linuxの一部出力
execve("/usr/bin/emacs", ["emacs"], [/* 21 vars */]) = 0 uname({sys="Linux", node="einstein", ...}) = 0 brk(0) = 0x old_mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0 x access("/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) = 0 read(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

47 演習:直接システムコールを呼ぼう システムコールを使ったhelloworld出力 (前回既にできた人は必要なし)

48 システムコールを呼ぼう システムコールには,番号がついています. Linux: /usr/include/asm/unistd.h
FreeBSD: /usr/include/sys/syscall.h #define SYS_syscall 0 #define SYS_exit #define SYS_fork #define SYS_read #define SYS_write #define SYS_open #define SYS_close #define SYS_wait $FreeBSD: src/sys/sys/syscall.h,v /11/21 01:36:27 csjp Exp $

49 システムコール〜引数の渡し方〜 Linux FreeBSD 引数の順番と逆にスタックに積んでいく mov $4, %eax
EBX レジスタ 第一引数 ECX レジスタ 第二引数 EDX レジスタ 第三引数 ESI レジスタ 第四引数 EDI レジスタ 第五引数 引数の順番と逆にスタックに積んでいく mov $4, %eax mov $1, %ebx mov buf, %ecx mov length, %edx int 0x80 push length push buf push $1 push $4 int 0x80

50 システムコールでhelloworld Linux FreeBSD
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() { ret = writes(message, sizeof(message)); const 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() { ret = writes(message, sizeof(message));

51 コンパイル&実行! % gcc -o helloworld helloworld % ./helloworld hello world


Download ppt "プログラミングの基礎 第2回 systemcall"

Similar presentations


Ads by Google