#author("2020-10-07T13:49:19+09:00","default:honma","honma")
#author("2020-10-07T14:01:30+09:00","default:honma","honma")
* 4Gを超えるメモリアクセス [#g0e12570]

32bitアプリで4GB以上のメモリ空間をアクセスする方法。~
ARMなどの組込み系で、4GBを超えるメモリ空間にアクセスすることになったので備忘録。~
ちなみに確認環境にRaspberry PIを使っているのは守秘義務のためw~

** 動作環境の確認 [#q572fd77]

 pi@raspberrypi:~ $ uname -a
 Linux raspberrypi 4.14.114-v7+ #1 SMP Fri Jun 28 15:47:58 JST 2019 armv7l GNU/Linux

** mmap() [#j31b366a]

日本語の[[Man page of MMAP:http://linuxjm.osdn.jp/html/LDP_man-pages/man2/mmap.2.html]]を参考に。~
mmap()の第4引数 off_t が 32bitなのか64bitなのかが肝。

 void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);

サンプルコードはこちら
#highlight(c){{
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>

#define PHYSICAL_ADDR 0x100000000

int main(void)
{
	int fd;
	char *addr;

	printf("sizeof(off_t) = %d\n", sizeof(off_t));

	fd = open("/dev/mem", O_RDWR|O_SYNC);
	addr = mmap(NULL, 512, PROT_WRITE|PROT_READ, MAP_SHARED, fd, PHYSICAL_ADDR);
	munmap(addr, 512);
	close(fd);

	return 0;
}
}}

実行結果

 pi@raspberrypi:~ $ gcc m.c
 pi@raspberrypi:~ $ ./a.out
 sizeof(off_t) = 4
 pi@raspberrypi:~ $ gcc m.c -D_FILE_OFFSET_BITS=64
 pi@raspberrypi:~ $ ./a.out
 sizeof(off_t) = 8

コンパイラオプションに -D_FILE_OFFSET_BITS=64 を指定することで64bitアクセスが可能。~
ちなみにソースコードの先頭行を下記のようにすることでも対応可能。

#highlight(c){{
#define _FILE_OFFSET_BITS 64
#include <stdio.h>
 :
}}

 pi@raspberrypi:~ $ gcc m.c
 pi@raspberrypi:~ $ ./a.out
 sizeof(off_t) = 8

** mmap64() [#d0e89e06]

日本語のMan pageサイトは存在しない。~
Debianのサイト[[mmap64(3) — manpages-ja-dev:https://manpages.debian.org/testing/manpages-ja-dev/mmap64.3.ja.html]]を参考にするか、~
Libcの本家のサイト[[mmap64(3) — Linux manual page:https://man7.org/linux/man-pages/man3/mmap64.3.html]]を参考にする。~
~
ただ、第4引数が off_t だと32bitでは?と思い、ヘッダファイルを確認。~
ファイルの所在は /usr/include/arm-linux-gnueabihf/sys/mman.h~

#highlight(c){{
/* Map addresses starting near ADDR and extending for LEN bytes.  0from
   OFFSET into the file FD describes according to PROT and FLAGS.  If ADDR
   is nonzero, it is the desired mapping address.  If the MAP_FIXED bit is
   set in FLAGS, the mapping will be at ADDR exactly (which must be
   page-aligned); otherwise the system chooses a convenient nearby address.
   The return value is the actual mapping address chosen or MAP_FAILED
   for errors (in which case `errno' is set).  A successful `mmap' call
   deallocates any previous mapping for the affected region.  */

#ifndef __USE_FILE_OFFSET64
extern void *mmap (void *__addr, size_t __len, int __prot,
		   int __flags, int __fd, __off_t __offset) __THROW;
#else
# ifdef __REDIRECT_NTH
extern void * __REDIRECT_NTH (mmap,
			      (void *__addr, size_t __len, int __prot,
			       int __flags, int __fd, __off64_t __offset),
			      mmap64);
# else
#  define mmap mmap64
# endif
#endif
#ifdef __USE_LARGEFILE64
extern void *mmap64 (void *__addr, size_t __len, int __prot,
		     int __flags, int __fd, __off64_t __offset) __THROW;
#endif
}}

ということで、__off64_t が実体らしい。~

サンプルコードはこちら

#highlight(c){{
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>

#define PHYSICAL_ADDR 0x100000000

int main(void)
{
	int fd;
	char *addr;

	printf("sizeof(off64_t) = %d\n", sizeof(off64_t));

	fd = open("/dev/mem", O_RDWR|O_SYNC);
	addr = mmap64(NULL, 512, PROT_WRITE|PROT_READ, MAP_SHARED, fd, PHYSICAL_ADDR);
	munmap(addr, 512);
	close(fd);

	return 0;
}
}}
#highlight(end)

実行結果

 pi@raspberrypi:~ $ gcc m.c
 m.c: In function ‘main’:
 m.c:19:9: warning: implicit declaration of function ‘mmap64’ [-Wimplicit-function-declaration]
   addr = mmap64(NULL, 512, PROT_WRITE|PROT_READ, MAP_SHARED, fd, PHYSICAL_ADDR);
          ^~~~~~
 m.c:19:7: warning: assignment makes pointer from integer without a cast [-Wint-conversion]
   addr = mmap64(NULL, 512, PROT_WRITE|PROT_READ, MAP_SHARED, fd, PHYSICAL_ADDR);
        ^
 pi@raspberrypi:~ $ ./a.out
 sizeof(__off64_t) = 8

警告が出るので対応としては、コンパイルオプションに -D_LARGEFILE64_SOURCE=1 を指定する。

 pi@raspberrypi:~ $ gcc m.c -D_LARGEFILE64_SOURCE=1
 pi@raspberrypi:~ $ ./a.out
 sizeof(__off64_t) = 8

もしくはソースコードの先頭行を下記のようにすることでも対応可能。

#highlight(c){{
#define _LARGEFILE64_SOURCE 1
#include <stdio.h>
 :
}}
#highlight(end)

 pi@raspberrypi:~ $ gcc m.c
 pi@raspberrypi:~ $ ./a.out
 sizeof(__off64_t) = 8

#htmlinsert(amazon_pc.html);

トップ   編集 差分 履歴 添付 複製 名前変更 リロード   新規 一覧 検索 最終更新   ヘルプ   最終更新のRSS