<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>ものぐさ備忘録 &#187; mmap</title>
	<atom:link href="http://www.ginriki.net/wd/category/mmap/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.ginriki.net/wd</link>
	<description>ソフトウェア関係の話を中心とした備忘録的日記</description>
	<lastBuildDate>Sun, 16 Jan 2011 20:07:53 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.8.5</generator>
	<language>ja</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>ゼロ番地を先頭とするページにマップする</title>
		<link>http://www.ginriki.net/wd/2007/06/28/21/</link>
		<comments>http://www.ginriki.net/wd/2007/06/28/21/#comments</comments>
		<pubDate>Thu, 28 Jun 2007 07:47:07 +0000</pubDate>
		<dc:creator>ginriki</dc:creator>
				<category><![CDATA[C言語]]></category>
		<category><![CDATA[linux]]></category>
		<category><![CDATA[mmap]]></category>
		<category><![CDATA[メモリ]]></category>

		<guid isPermaLink="false">http://www.gikogeek.net/wd/?p=21</guid>
		<description><![CDATA[
mmapのflags引数にMAP_FIXEDフラグを指定することで、OSの実装によってはゼロ番地を先頭とするページにマップできます*1
たとえば、i386以降のCPU, Vine Linux 4.0, gcc-4.1. [...]]]></description>
			<content:encoded><![CDATA[<div class="section">
<p>mmapのflags引数にMAP_FIXEDフラグを指定することで、OSの実装によってはゼロ番地を先頭とするページにマップできます<span class="footnote"><a href="/gikogeek/#f1" name="fn1" title="SUSv3では、「MAP_FIXEDフラグを指定した場合、start引数はマップされるページのヒントとなるアドレスではなく、マップさせたいページのアドレスを意味するようになり、マップに失敗した場合はエラーを返す」としか書いてありません。よって、startに0を指定した場合は必ず失敗するようにmmapを実装しても仕様を満たします。">*1</a></span></p>
<p>たとえば、i386以降のCPU, Vine Linux 4.0, gcc-4.1.1を使った環境で以下のコードをコンパイルして実行するとゼロ番地にアクセスできます。</p>
<pre class="syntax-highlight">
<span class="synPreProc">#include </span><span class="synConstant">&#60;sys/mman.h&#62;</span>
<span class="synPreProc">#include </span><span class="synConstant">&#60;unistd.h&#62;</span>
<span class="synPreProc">#include </span><span class="synConstant">&#60;stdio.h&#62;</span>

<span class="synType">int</span> main(){
<span class="synType">int</span>* p = (<span class="synType">int</span>*)mmap(<span class="synConstant">0</span>, getpagesize(), PROT_READ | PROT_WRITE,
MAP_ANONYMOUS | MAP_PRIVATE | MAP_FIXED, <span class="synConstant">0</span>, <span class="synConstant">0</span>);
*p = <span class="synConstant">1</span>;

printf(<span class="synConstant">&#34;*(int*)</span><span class="synSpecial">%d</span><span class="synConstant"> = </span><span class="synSpecial">%d\n</span><span class="synConstant">&#34;</span>, (<span class="synType">int</span>)p, *(<span class="synType">int</span>*)<span class="synConstant">0</span>);
<span class="synStatement">return</span> <span class="synConstant">0</span>;
}
</pre>
<p>実行すると以下のようになります。</p>
<pre class="syntax-highlight">
$ gcc main.c
$ ./a.out
*<span class="synStatement">(</span>int*<span class="synStatement">)</span><span class="synConstant">0</span> <span class="synStatement">=</span> <span class="synConstant">1</span>
$
</pre>
<p>以下、注意点。</p>
<p>Cの仕様上では、start引数に0を指定しても数値の0を指すとは限りません。なぜなら、start引数の型はvoid*であり、Cの仕様ではポインタを書くべきところに書かれた0は、コンパイル時にヌル・ポインタに変換されることが保証されているからです<span class="footnote"><a href="/gikogeek/#f2" name="fn2" title="http://www.kouno.jp/home/c_faq/c5.html 5.2項">*2</a></span>（コンパイラがポインタ型の式だと判断できる場合のみ）。</p>
<p>なお、C++でもほとんど同様のようです<span class="footnote"><a href="/gikogeek/#f3" name="fn3" title="注解 C++ リファレンスマニュアル 4.6: ISBN 4901280392   といっても、これ古い仕様みたいですけど・・・">*3</a></span>。自分には、CとC++の違いは、C言語の場合、#define NULL (void*)0 か　#define NULL 0 どちらでもありうるが、C++だと #define NULL (void*)0 がありえないということしかわかりませんでした。</p>
<p>よって、ハードウェア, OS, C/C++のコンパイラによっては、start引数で渡す値がコンパイル時に0ではない値に変換されているかもしれないので、ソースコードでstart引数に0を指定したからといって、実行時にmmapでマップされたページが必ずしもゼロ番地ではないかも知れないことに注意です。</p>
<p></p>
<p>以上、何の役に立つかわからないけど面白かったのでメモっときます。</p>
<p>ちなみにWindowsの場合、ゼロ番地から64KB分<span class="footnote"><a href="/gikogeek/#f4" name="fn4" title="Windows2000の場合。Windows98だと4KB分">*4</a></span>のアドレスをユーザプログラムのプログラマがVirtualAlloc APIで確保(予約)することはできません。これは、ヌル・ポインタが指すアドレス先に値を代入しようとしたときに、必ずメモリアクセス違反が発生するようにするために、意図的にそう決まっています<span class="footnote"><a href="/gikogeek/#f5" name="fn5" title="Advanced Windows 13.2 :ISBN 4-7561-3805-5">*5</a></span></p>
<p>ということは、Windowsが動くような環境において、ヌル・ポインタが0と一致する（させる）のは当然だとMicrosoftは考えているのでしょうね。</p>
</div>
<div class="footnote">
<p class="footnote"><a href="/gikogeek/#fn1" name="f1">*1</a>：SUSv3では、「MAP_FIXEDフラグを指定した場合、start引数はマップされるページのヒントとなるアドレスではなく、マップさせたいページのアドレスを意味するようになり、マップに失敗した場合はエラーを返す」としか書いてありません。よって、startに0を指定した場合は必ず失敗するようにmmapを実装しても仕様を満たします。</p>
<p class="footnote"><a href="/gikogeek/#fn2" name="f2">*2</a>：<a href="http://www.kouno.jp/home/c_faq/c5.html" target="_blank">http://www.kouno.jp/home/c_faq/c5.html</a> 5.2項</p>
<p class="footnote"><a href="/gikogeek/#fn3" name="f3">*3</a>：注解 C++ リファレンスマニュアル 4.6: ISBN 4901280392   といっても、これ古い仕様みたいですけど・・・</p>
<p class="footnote"><a href="/gikogeek/#fn4" name="f4">*4</a>：Windows2000の場合。Windows98だと4KB分</p>
<p class="footnote"><a href="/gikogeek/#fn5" name="f5">*5</a>：Advanced Windows 13.2 :ISBN 4-7561-3805-5</p>
</div>
]]></content:encoded>
			<wfw:commentRss>http://www.ginriki.net/wd/2007/06/28/21/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

