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

Slides:



Advertisements
Similar presentations
プログラミング演習II 2004年11月 30日(第6回) 理学部数学科・木村巌.
Advertisements

オペレーティングシステム i386アーキテクチャ(3)
コンパイラの解析 (1) プログラムのリンクと実行.
榮樂 英樹 LilyVM と仮想化技術 榮樂 英樹
情報基礎演習B 後半第5回 担当 岩村 TA 谷本君.
1.1 C/C++言語 Hello.ccを作りコンパイルしてa.outを作り出し実行する
システムプログラミング 第6回、7回 main関数の引数 usageメッセージ システムコールのエラーメッセージ ファイル
数理情報工学演習第一C プログラミング演習 (第3回 ) 2014/04/21
リダイレクト パイプ 標準入出力プログラム コマンド行引数 関数 system()
システムプログラミング 第5回 情報工学科 篠埜 功 ヒアドキュメント レポート課題 main関数の引数 usageメッセージ
システムプログラミング 第11回 シグナル 情報工学科  篠埜 功.
OSとコマンド OS:コンピュータを使うための基本プログラム コマンド:OS上で使用できる命令 OS本体であるカーネルの内部コマンド
オペレーティングシステム (OSの機能と構造)
App. A アセンブラ、リンカ、 SPIMシミュレータ
第8回 プログラミングⅡ 第8回
担当:青木義満 情報工学科 3年生対象 専門科目 システムプログラミング システムプログラミング プロセス間通信(パイプ) 担当:青木義満
2006/10/19 山下 諒蔵 佐藤 春旗 前田 俊行 大山 恵弘 佐藤 秀明 住井英二郎
プログラムはなぜ動くのか.
Ibaraki Univ. Dept of Electrical & Electronic Eng.
担当:青木義満、篠埜 功 情報工学科 3年生対象 専門科目 システムプログラミング 第8回、第9回 シグナル処理 担当:青木義満、篠埜 功
プログラミング演習Ⅰ 課題2 10進数と2進数 2回目.
第3回 CPUの管理と例外処理 OSによるハードウェアの管理 CPUの構成、動作 CPUの管理 例外処理、割り込み処理 コンテキストスイッチ
Linuxカーネルについて 2014/01.
第5回 CPUの役割と仕組み3 割り込み、パイプライン、並列処理
オペレーティングシステム i386アーキテクチャ(2)
システムプログラミング 第11回 シグナル 情報工学科  篠埜 功.
シグナル通信 普通の割込みとソフトウェア割込み ソフトウェア割込みとシグナル キーボードからのシグナル 例外 (exception)
コンパイラの解析 (2) GCJのデータ構造 - 1.
情報工学科 3年生対象 専門科目 システムプログラミング 第5回、第6回 ヒアドキュメント レポート課題 情報工学科 篠埜 功.
型付きアセンブリ言語を用いた安全なカーネル拡張
ネットワークプログラミング 中村 修.
Linux Device Driver 輪講 2. モジュールの作成と実行
FlexとBison+アルファ -実習編-
セキュリティ(3) 05A2013 大川内 斉.
OSの仕組みとその機能 1E16M001-1 秋田 梨紗 1E16M010-2 梅山 桃香 1E16M013-3 大津 智紗子
プログラミング 4 記憶の割り付け.
リダイレクト パイプ 標準入出力プログラム コマンド行引数 関数 system()
オペレーティングシステム イントロダクション
第7回 プログラミングⅡ 第7回
全体ミーティング 6月6日 島本 大輔(M2) 2006年6月6日(火).
オペレーティングシステム 第2回 割り込みとOSの構成
演習1の解答例の解説 2006年11月8日 海谷 治彦.
コンパイラ資料 実行時環境.
担当:青木義満 情報工学科 3年生対象 専門科目 システムプログラミング 第6回 システムプログラミング概要 プロセスの生成 担当:青木義満
地域情報学 C言語プログラミング 第1回 導入、変数、型変換、printf関数 2016年11月11日
オペレーティングシステムJ/K 2004年11月18日
オペレーティングシステムJ/K 2004年11月15日2時限目
先週の復習: CPU が働く仕組み コンピュータの構造 pp 制御装置+演算装置+レジスタ 制御装置がなければ電卓と同様
C言語 はじめに 2016年 吉田研究室.
第5回 メモリ管理(2) オーバレイ方式 論理アドレスとプログラムの再配置 静的再配置と動的再配置 仮想記憶とメモリ階層 セグメンテーション
オペレーティングシステム (OSの機能と構造)
プログラミング演習I 2003年4月30日(第3回) 木村巌.
実装について 前田俊行.
計算機プログラミングI 木曜日 1時限・5時限 担当: 増原英彦 第1回 2002年10月10日(木)
システムプログラミング 第6回 システムコールのエラーメッセージ ファイルシステム 情報工学科 篠埜 功.
オペレーティングシステムJ/K 2004年10月4日
オペレーティングシステムJ/K (システムプログラミング)
ネットワーク・プログラミング デバイスドライバと環境変数.
ネットワーク・プログラミング Linuxシステムとソフトウェア開発.
オペレーティングシステム 作成 T21R003 荏原 寛太.
プログラミング言語論 第九回 理工学部 情報システム工学科 新田直也.
プログラミング演習I 2003年6月11日(第9回) 木村巌.
システムプログラミング 第11回 シグナル 情報工学科  篠埜 功.
オブジェクト指向言語論 第七回 知能情報学部 新田直也.
プログラミング言語論 第九回 理工学部 情報システム工学科 新田直也.
オブジェクト指向言語論 第七回 知能情報学部 新田直也.
岩村雅一 知能情報工学演習I 第7回(後半第1回) 岩村雅一
第1章 文字の表示と計算 printfと演算子をやります 第1章 文字の表示と計算.
プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機言語演習Ⅰ, 情報処理言語Ⅰ(実習を含む。)
第1章 文字の表示と計算 printfと演算子をやります.
Presentation transcript:

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

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

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

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

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

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

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

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

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

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

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

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

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

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 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'

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

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

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

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

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

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

システムコール概要

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

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

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

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

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

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

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

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

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

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

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

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

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

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

ソフトウェア割り込み

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

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

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

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

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

システムコール実例

システムコール リスト Linux #define __NR_exit 1 #define __NR_fork 2 システムコール リスト 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

システムコール リスト FreeBSD /* 11 is obsolete execv */ #define SYS_syscall 0 システムコール リスト FreeBSD /* 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 #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

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

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

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

システムコールを呼ぼう システムコールには,番号がついています. 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 $

システムコール〜引数の渡し方〜 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

システムコールで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));

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