web-dev-qa-db-ja.com

いくつかのライブラリと他のパーツがgdbを使用してLinux仮想メモリで繰り返されるのはなぜですか?

enter image description here

これは、gdbでプロセスの仮想メモリを調べた結果です。これに関していくつか質問があります:

  1. 仮想メモリの一部が繰り返されるのはなぜですか?たとえば、プログラム(stack6)とlibcライブラリは4回繰り返されます。彼らがそれらを異なる部分に分割しているのなら、なぜですか?それらをすべてまとめてみませんか?

  2. トップパス(/ opt/pro ...)は仮想メモリの命令セクション(テキストセクション)であり、命令のみが含まれていますか?

  3. 4つのlibcのサイズが異なるのはなぜですか?オフセットとの関係は何ですか、すでにサイズと開始アドレスがある場合、オフセットの目的は何ですか?

  4. データ、bss、カーネル、ヒープのセクションはどこにありますか、そして上記の画像の一部にそれらに関する情報がないのはなぜですか?実際にすべての部分を表示するgdbのより良いオプションはありますか?

  5. プロセスの仮想メモリの部分をはるかによく示すgdbよりも優れたプログラムはありますか?実際の仮想メモリをよく視覚化したいだけです。デバッグプログラムが最良の結果をもたらします。

私が言及したセクション:

enter image description here

5
John P

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 mappingsstack6で示される小さいサイズも説明します。各ヘッダーは4KiB未満を要求し、4KiBアライメントであるため、異なるアドレスで同じオフセットを持つ2つの4KiBマッピングを取得します。)

空白のマッピングは匿名のマッピングに対応します。詳細については、 man 5 proc を参照してください。 mmapgdbで中断して、それらが何に対応するかを判断する必要があります。

カーネルマッピングは、プロセスの観点からは重要ではないため(アクセスできないため)、(一部のアーキテクチャのレガシーvsyscallを除いて)表示できません。

より良いgdbオプションを知りません。常に/proc/$$/mapsを使用します。

カーネルによって読み取られるELF形式の詳細、およびメモリ割り当てへのマッピング方法については、 プログラムの実行方法:ELFバイナリ を参照してください。より多くの参考資料へのポインタがあります。

5
Stephen Kitt