Linuxで利用できないように見えるメモリマッピングの目的は何ですか?

Linuxで利用できないように見えるメモリマッピングの目的は何ですか?

各プロセスには、読み取り、書き込み、または実行できない専用のメモリマッピングがあるようです(対応するフラグは「---p」です)。

grep -- --- /proc/self/maps
7f2bd9bf7000-7f2bd9df6000 ---p 001be000 fc:00 3733                       /lib/x86_64-linux-gnu/libc-2.19.so
7f2bd9e04000-7f2bda003000 ---p 00003000 fc:00 3743                       /lib/x86_64-linux-gnu/libdl-2.19.so
7f2bda042000-7f2bda241000 ---p 0003d000 fc:00 36067                      /lib/x86_64-linux-gnu/libpcre.so.3.13.1

一部の共有ライブラリのコンテンツを返し、Java(JVM)プロセスの場合は、数百メガバイトの匿名マップの数十を返します。

編集:これらのマッピングがプレースホルダの場合、保護されているイベントや他のアクティビティにはこれらの予約された場所を使用しますか?つまり、これらのプレースホルダが存在しない場合、どのようなエラー動作が発生する可能性がありますか?

2番目の編集:共有ライブラリのこれらの穴は、実際には何らかの目的でコンパイラおよび/または動的リンカに役立つことを考慮すると、JVMプロセスに表示される匿名マッピングのこれらの穴には他の目的が必要です。 Tomcat JVMプロセスの匿名マップをサイズでソートします。

 20 MB  00007FA0AAB52000-00007FA0AC000000 ---p 00000000 00:00 0
 41 MB  00007FA0B1603000-00007FA0B4000000 ---p 00000000 00:00 0
 50 MB  00007FA090D04000-00007FA094000000 ---p 00000000 00:00 0
 53 MB  00007FA0F8A40000-00007FA0FC000000 ---p 00000000 00:00 0
 61 MB  00007FA0C42C5000-00007FA0C8000000 ---p 00000000 00:00 0
 61 MB  00007FA0CC29A000-00007FA0D0000000 ---p 00000000 00:00 0
 61 MB  00007FA0D0293000-00007FA0D4000000 ---p 00000000 00:00 0
 62 MB  00007FA0D814C000-00007FA0DC000000 ---p 00000000 00:00 0
 62 MB  00007FA0E017E000-00007FA0E4000000 ---p 00000000 00:00 0
 63 MB  00007FA0B803B000-00007FA0BC000000 ---p 00000000 00:00 0
 63 MB  00007FA0BC021000-00007FA0C0000000 ---p 00000000 00:00 0
 63 MB  00007FA0C0021000-00007FA0C4000000 ---p 00000000 00:00 0
 63 MB  00007FA0D4075000-00007FA0D8000000 ---p 00000000 00:00 0
 63 MB  00007FA0DC040000-00007FA0E0000000 ---p 00000000 00:00 0
 63 MB  00007FA0E4067000-00007FA0E8000000 ---p 00000000 00:00 0
189 MB  00007FA0EC300000-00007FA0F8000000 ---p 00000000 00:00 0
1008 MB  0000000100FF5000-0000000140000000 ---p 00000000 00:00 0

ベストアンサー1

NULL権限を持つ2044KBのメモリ領域が2つあります。前述のように、ELFの「実行ビュー」は、実行可能なバイナリがメモリにロードされる方法に焦点を当てています。 ld.soが動的ライブラリをインポートするときに、LOADとマークされたセグメントを確認します(readelf -a xxx.soコマンドの「プログラムヘッダー」と「セクションからセグメントへのマッピング」を参照)。通常、2つのLOADセグメントがあり、2つのセグメントの間に「穴」があるため(これら2つのセグメントのVirtAddrとMemSizを参照)、ld.soは意図的にこの穴にアクセスできないようにします。 elf/dl-load.cでPROT_NONEを探します。 _dl_map_object_from_fdのシンボル

http://www.cs.stevens.edu/~jschauma/810/elf.html

mprotectstrace egを使用して発生した呼び出しでこの状況を確認するのも簡単ですstrace -f grep -- . /proc/self/maps 2>&1 |less

open("/lib64/libpcre.so.1", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\300\25\0\0\0\0\0\0"..., 832) = 832
fstat(3, {st_mode=S_IFREG|0755, st_size=471728, ...}) = 0
mmap(NULL, 2564360, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7f0e3ad2a000
mprotect(0x7f0e3ad9c000, 2093056, PROT_NONE) = 0
mmap(0x7f0e3af9b000, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x71000) = 0x7f0e3af9b000
close(3)                                = 0

githubにglibc repoミラーがあり、PROT_NONE検索は難しくありません...

/ *この実装は、共有オブジェクトが常にすべてのセグメントが連続するように配置されている(dl-unmap-segments.hの_dl_unmap_segmentsの対応する実装など)(またはセグメント間の間隔が小さく、好ましくはすべてのページ全体が保持されます)されることをお勧めします)。 )アドレス空間の対応する部分を他の目的に使用することを許可せずにPROT_NONEによってマッピングされた間隔内)。 */

https://github.com/bminor/glibc/blob/73dfd088936b9237599e4ab737c7ae2ea7d710e1/elf/dl-map-segments.h#L21

/ * _dl_map_segmentsは、セグメント間の間隔のすべてのページがPROT_NONEマップで埋められることを保証します。したがって、一度にフルレンジのマッピングを解除できます。 */

https://github.com/bminor/glibc/blob/73dfd088936b9237599e4ab737c7ae2ea7d710e1/elf/dl-unmap-segments.h#L25

Java

OpenJDKは... PROT_NONEマッピングを使用して、コミットされていないアドレス空間を予約します(その後、必要に応じてmprotect呼び出しを介してコミットします)。

自然な仮定は、何らかの理由で連続的なヒープメモリを持ちたいということです。

実際に必要になるまでPROT_NONEを使用してスペースを予約します。このコメントの元の文脈は、Linux VMの乱用に関する議論でした。アクセスできないマップを使用すると、カーネルが次のように設定されている場合、カーネルでコミットする必要はありません(マップが必要になりアクセス可能になるまで)。厳格なコミットモード

JVMコンテキストでこの予約がなぜ事前に必要なのか疑問に思っている場合は、リンクされたネイティブコードの使用を検討してください。JNIあるいは、mmapを使用することも可能です。

https://lwn.net/Articles/627728/

おすすめ記事