Open Source Web Development Tutorials - Dev Shed
LinuxのMMAPシステムコール
(2009/03/17公開)
LinuxのMMAPシステムコール
これは全7回でLinux I/Oファイルのシステムコールを解説する連載の第3回です。今回は、ファイル操作の柔軟性を向上するmmap()システムコールの使い方を学習しましょう。内容は、ロバート・ラブ著『Linux System Programming: Talking Directly to the Kernel and C Library(Linuxシステムプログラミング-カーネルおよびCライブラリへ直接話しかける:仮題)』第4章からの抜粋です。(原著はオライリーより2007年に出版、ISBN: 0596009585(Copyright 2007 O'Reilly Media, Inc.))禁無断転載。出版社の許可を得て使用しています。書店あるいはオライリーメディアから直接購入できます。
ファイルをメモリへマッピングする
標準ファイルI/Oに代わる方法として、カーネルはファイルをメモリにマッピングするインターフェースを提供します。つまり、メモリアドレスとファイル中の語の間に1対1対応が存在するわけです。したがって、任意のメモリ常駐データのチャンクにアクセスする場合とまったく同様に、メモリーを介して直接ファイルにアクセスすることができます。そればかりか、メモリ領域へ書き込みを行い、ディスク上のファイルへ透過的に逆マッピングすることさえ可能です。
オブジェクトをメモリにマッピングするmmap()システムコールは、POSIX.1で標準化 -そして、Linuxで実装-されています。本節では、ファイルをメモリへマッピングしてI/Oを実行するmmap()について解説します。mmap()のそのほかの利用方法は、第8章で取り上げます。
mmap( )
mmap()のコールは、カーネルに対して、ファイル記述子fdが表すオブジェクトのlenバイトをメモリへマッピングするように指示します。マッピングはファイルのoffsetバイトから開始します。addrが含まれている場合は、その開始メモリアドレスを優先的に使用する指示を与えます。アクセス許可はprotで命令し、そのほかの動作はflagsで指示します。以下のとおりです。
#include <sys/mman.h>
void * mmap (void *addr,
size_t len,
int prot,
int flags,
int fd,
off_t offset);
addrパラメータは、カーネルに対して、ファイルのマッピングに最適な個所を提示します。しかし、これは単なる手掛かりに過ぎず、ほとんどの場合、ユーザーはゼロを渡します。コールは、マッピングが開始するメモリの実アドレスを戻します。
Protパラメータは、マッピングに関して要求するメモリ保護を記述します。選択は、マッピングするページへのアクセスを禁止する(ほとんど無意味です!)PROT_NONE、または、以下に列挙したフラグの1つあるいは複数のビット単位ORです。
PROT_READ
ページの読み込みを許可します。
PROT_WRITE
ページへの書き込みを許可します。
PROT_EXEC
ページの実行を許可します。
要求するメモリ保護がファイルのオープン形式と矛盾してはなりません。例えば、読み出し専用のファイルを開くとき、protがPROT_WRITEを指示してはなりません。
________________________________________
■保護フラグ、アーキテクチャ、セキュリティー
POSIXは4種類の保護ビット(読み出し、書き込み、実行、遮断)を定義していますが、これらのサブセットしかサポートしないアーキテクチャもあります。例えば、「読み出し」アクションと「実行」アクションを区別しないプロセッサーも珍しくありません。そのようなプロセッサーでは"read"フラグしか存在しない場合もありえます。それらのシステムでは、PROT_READがPROT_EXECを意味するのです。最近まで、x86アーキテクチャもそのようなシステムの1つでした。
このような動作に依存していたのでは、当然、移植は不可能です。マッピングでコードを実行するつもりなら、移植プログラムは常にPROT_EXECを設定する必要があります。
逆の状況が、バッファーオーバーフロー攻撃が流行している理由の1つです。マッピングが実行許可を指示していなくても、プロセッサーが実行を許可してしまう可能性があるためです。
最近のx86プロセッサーには、NX(非実行)ビットが導入されています。このため、読み出しはできるが実行はできないマッピングが可能になりました。このような新しいシステムでは、もはや、PROT_READがPROT_EXECを意味することはありません。
________________________________________
flags引数は、マッピングの種類と動作の諸要素を指示します。flags引数は、以下の値のビット単位ORです。
MAP_FIXED
mmap()に対して、addrを手掛かりではなく要件として扱うように指示します。カーネルが指示されたアドレスにマッピングを行えない場合、コールは失敗します。アドレスと長さのパラメータが既存のマッピングと重複する場合、重複するページは廃棄され、新規のマッピングが置き換わります。このオプションにはプロセスのアドレス空間を熟知していることが必要であり、移植性がなく、利用を控えることが推奨されます。
MAP_PRIVATE
マッピングの共有を拒否します。ファイルは「コピーオンライト(CoW)」でマッピングされ、このプロセスによってメモリに行われた変更は、実ファイルあるいはとほかのプロセスのマッピングに反映されません。
MAP_SHARED
マッピングを、同一ファイルのマッピングを行うほかのすべてのプロセスと共有します。マッピングへの書き込みはファイルへの書き込みを意味します。マッピングからの読み出しには、ほかのプロセスによる書き込みが反映されます。
MAP_SHAREDあるいはMAP_PRIVATEの一方を指示しなくてはなりません。両方を指示することはできません。そのほかの高度なフラグは第8章で解説します。
ファイル記述子をマッピングするとき、ファイルの参照カウントはインクリメントされます。したがって、ファイルをマッピングした後にファイル記述子を閉じても、引き続きアクセスが可能です。ファイルをアンマッピング(マッピング削除)するとき、あるいは、プロセスが終了するとき、ファイルの参照カウントはインクリメントに対応してデクリメントされます。
一例を挙げましょう。以下のスニペットでは、ファイル記述子fd のファイルの読み出し専用マッピングを行っています。マッピングは最初のバイトから開始し、lenバイトにわたって継続します。
void *p;
p = mmap (0, len, PROT_READ, MAP_SHARED, fd, 0);
if (p == MAP_FAILED)
perror ("mmap");
下図は、mmap()で与えるパラメータが、ファイルからプロセスのアドレス空間へのマッピングに実現する結果を示しています。
Copyright © 2008 Ziff Davis Enterprise, Inc.
Originally appearing in the U.S. Edition of Dev Shed. All Rights Reserved.









