4Gを超えるメモリアクセス

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

動作環境の確認

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

mmap()

日本語のMan page of MMAPを参考に。
mmap()の第4引数 off_t が 32bitなのか64bitなのかが肝。

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

サンプルコードはこちら

  1. #include <stdio.h>  
  2. #include <stdlib.h>  
  3. #include <sys/types.h>  
  4. #include <sys/stat.h>  
  5. #include <fcntl.h>  
  6. #include <unistd.h>  
  7. #include <sys/mman.h>  
  8.   
  9. #define PHYSICAL_ADDR 0x100000000  
  10.   
  11. int main(void)  
  12. {  
  13.     int fd;  
  14.     char *addr;  
  15.   
  16.     printf("sizeof(off_t) = %d\n"sizeof(off_t));  
  17.   
  18.     fd = open("/dev/mem", O_RDWR|O_SYNC);  
  19.     addr = mmap(NULL, 512, PROT_WRITE|PROT_READ, MAP_SHARED, fd, PHYSICAL_ADDR);  
  20.     munmap(addr, 512);  
  21.     close(fd);  
  22.   
  23.     return 0;  
  24. }  

実行結果

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アクセスが可能。
ちなみにソースコードの先頭行を下記のようにすることでも対応可能。

  1. #define _FILE_OFFSET_BITS 64  
  2. #include <stdio.h>  
  3.  :  
pi@raspberrypi:~ $ gcc m.c
pi@raspberrypi:~ $ ./a.out
sizeof(off_t) = 8

mmap64()

日本語のMan pageサイトは存在しない。
Debianのサイトmmap64(3) — manpages-ja-devを参考にするか、
Libcの本家のサイトmmap64(3) — Linux manual pageを参考にする。

ただ、第4引数が off_t だと32bitでは?と思い、ヘッダファイルを確認。
ファイルの所在は /usr/include/arm-linux-gnueabihf/sys/mman.h

  1. /* Map addresses starting near ADDR and extending for LEN bytes.  0from 
  2.    OFFSET into the file FD describes according to PROT and FLAGS.  If ADDR 
  3.    is nonzero, it is the desired mapping address.  If the MAP_FIXED bit is 
  4.    set in FLAGS, the mapping will be at ADDR exactly (which must be 
  5.    page-aligned); otherwise the system chooses a convenient nearby address. 
  6.    The return value is the actual mapping address chosen or MAP_FAILED 
  7.    for errors (in which case `errno' is set).  A successful `mmap' call 
  8.    deallocates any previous mapping for the affected region.  */  
  9.   
  10. #ifndef __USE_FILE_OFFSET64  
  11. extern void *mmap (void *__addr, size_t __len, int __prot,  
  12.            int __flags, int __fd, __off_t __offset) __THROW;  
  13. #else  
  14. # ifdef __REDIRECT_NTH  
  15. extern void * __REDIRECT_NTH (mmap,  
  16.                   (void *__addr, size_t __len, int __prot,  
  17.                    int __flags, int __fd, __off64_t __offset),  
  18.                   mmap64);  
  19. # else  
  20. #  define mmap mmap64  
  21. # endif  
  22. #endif  
  23. #ifdef __USE_LARGEFILE64  
  24. extern void *mmap64 (void *__addr, size_t __len, int __prot,  
  25.              int __flags, int __fd, __off64_t __offset) __THROW;  
  26. #endif  

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

サンプルコードはこちら

  1. #include <stdio.h>  
  2. #include <stdlib.h>  
  3. #include <sys/types.h>  
  4. #include <sys/stat.h>  
  5. #include <fcntl.h>  
  6. #include <unistd.h>  
  7. #include <sys/mman.h>  
  8.   
  9. #define PHYSICAL_ADDR 0x100000000  
  10.   
  11. int main(void)  
  12. {  
  13.     int fd;  
  14.     char *addr;  
  15.   
  16.     printf("sizeof(off64_t) = %d\n"sizeof(off64_t));  
  17.   
  18.     fd = open("/dev/mem", O_RDWR|O_SYNC);  
  19.     addr = mmap64(NULL, 512, PROT_WRITE|PROT_READ, MAP_SHARED, fd, PHYSICAL_ADDR);  
  20.     munmap(addr, 512);  
  21.     close(fd);  
  22.   
  23.     return 0;  
  24. }  

実行結果

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

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

  1. #define _LARGEFILE64_SOURCE 1  
  2. #include <stdio.h>  
  3.  :  
pi@raspberrypi:~ $ gcc m.c
pi@raspberrypi:~ $ ./a.out
sizeof(__off64_t) = 8

トップ   新規 一覧 検索 最終更新   ヘルプ   最終更新のRSS