これは、gdbでプロセスの仮想メモリを調べた結果です。これに関していくつか質問があります:
仮想メモリの一部が繰り返されるのはなぜですか?たとえば、プログラム(stack6)とlibcライブラリは4回繰り返されます。彼らがそれらを異なる部分に分割しているのなら、なぜですか?それらをすべてまとめてみませんか?
トップパス(/ opt/pro ...)は仮想メモリの命令セクション(テキストセクション)であり、命令のみが含まれていますか?
4つのlibcのサイズが異なるのはなぜですか?オフセットとの関係は何ですか、すでにサイズと開始アドレスがある場合、オフセットの目的は何ですか?
データ、bss、カーネル、ヒープのセクションはどこにありますか、そして上記の画像の一部にそれらに関する情報がないのはなぜですか?実際にすべての部分を表示するgdbのより良いオプションはありますか?
プロセスの仮想メモリの部分をはるかによく示すgdbよりも優れたプログラムはありますか?実際の仮想メモリをよく視覚化したいだけです。デバッグプログラムが最良の結果をもたらします。
私が言及したセクション:
gdb
の出力から欠落している重要な情報が1つあります。それは、ページの権限です。 (これらは SolarisおよびFreeBSDの場合 と表示されますが、Linuxの場合は表示されません。)/proc/<pid>/maps
を見ると、これらを確認できます。 Protostarサンプルショーのマップ
$ cat /proc/.../maps
08048000-08049000 r-xp 00000000 00:0f 2925 /opt/protostar/bin/stack6
08049000-0804a000 rwxp 00000000 00:0f 2925 /opt/protostar/bin/stack6
b7e96000-b7e97000 rwxp 00000000 00:00 0
b7e97000-b7fd5000 r-xp 00000000 00:0f 759 /lib/libc-2.11.2.so
b7fd5000-b7fd6000 ---p 0013e000 00:0f 759 /lib/libc-2.11.2.so
b7fd6000-b7fd8000 r-xp 0013e000 00:0f 759 /lib/libc-2.11.2.so
b7fd8000-b7fd9000 rwxp 00140000 00:0f 759 /lib/libc-2.11.2.so
b7fd9000-b7fdc000 rwxp 00000000 00:00 0
b7fe0000-b7fe2000 rwxp 00000000 00:00 0
b7fe2000-b7fe3000 r-xp 00000000 00:00 0 [vdso]
b7fe3000-b7ffe000 r-xp 00000000 00:0f 741 /lib/ld-2.11.2.so
b7ffe000-b7fff000 r-xp 0001a000 00:0f 741 /lib/ld-2.11.2.so
b7fff000-b8000000 rwxp 0001b000 00:0f 741 /lib/ld-2.11.2.so
bffeb000-c0000000 rwxp 00000000 00:0f 0 [stack]
(Protostarの例はVMで実行されます。これはハッキングが簡単で、おそらく演習を扱いやすくするためです。NX保護も、ASLRもありません。)
上記のように、gdb
で繰り返しマッピングが行われているように見えるのは、実際にはさまざまな権限を持つさまざまなマッピングに対応しています。テキストセグメントは読み取り専用で実行可能にマップされます。データセグメントは読み取り専用でマップされます。 BSSとヒープは読み取り/書き込みでマップされます。理想的には、データセグメント、BSS、およびヒープは実行可能ではありませんが、この例ではNXサポートがないため、実行可能です。各共有ライブラリは、テキストセグメント、データセグメント、およびBSSに対して独自のマッピングを取得します。 4番目のマッピングは、通常、バッファオーバーフローを防ぐために使用される、読み取り、書き込み、実行不可能なセグメントです(ただし、ここで使用されるカーネルとCライブラリの古さを考えると、これは何か異なる場合があります)。
オフセットは、指定されている場合、ファイル内のデータのオフセットを示します。これは、アドレス空間でのデータの位置とは必ずしも関係ありません。ロードされると、これは配置の制約を受けます。たとえば、libc-2.11.2.so
のプログラムヘッダーは、2つの「LOAD」ヘッダーを指定します。
Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
LOAD 0x000000 0x00000000 0x00000000 0x13d2f4 0x13d2f4 R E 0x1000
LOAD 0x13e1cc 0x0013f1cc 0x0013f1cc 0x027b0 0x0577c RW 0x1000
(これを確認するには、readelf -l
を使用してください。)
これらにより、セグメントにマップされたセクションの保護フラグが異なる場合、同じオフセットで複数のマッピングが行われ、仮想アドレスが異なる可能性があります。 stack6
の場合:
Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
LOAD 0x000000 0x08048000 0x08048000 0x00604 0x00604 R E 0x1000
LOAD 0x000604 0x08049604 0x08049604 0x00114 0x00128 RW 0x1000
(これは、proc info mappings
のstack6
で示される小さいサイズも説明します。各ヘッダーは4KiB未満を要求し、4KiBアライメントであるため、異なるアドレスで同じオフセットを持つ2つの4KiBマッピングを取得します。)
空白のマッピングは匿名のマッピングに対応します。詳細については、 man 5 proc
を参照してください。 mmap
のgdb
で中断して、それらが何に対応するかを判断する必要があります。
カーネルマッピングは、プロセスの観点からは重要ではないため(アクセスできないため)、(一部のアーキテクチャのレガシーvsyscall
を除いて)表示できません。
より良いgdb
オプションを知りません。常に/proc/$$/maps
を使用します。
カーネルによって読み取られるELF形式の詳細、およびメモリ割り当てへのマッピング方法については、 プログラムの実行方法:ELFバイナリ を参照してください。より多くの参考資料へのポインタがあります。