gdbを使用すると、Linux仮想メモリにいくつかのライブラリや他の部分が重複するのはなぜですか?

gdbを使用すると、Linux仮想メモリにいくつかのライブラリや他の部分が重複するのはなぜですか?

ここに画像の説明を入力してください。

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

  1. 仮想メモリの一部が重複するのはなぜですか?たとえば、私たちのプログラム(stack6)とlibcライブラリが異なる部分に分割されているとしたら、なぜですか?みんなで集めてみてはいかがでしょうか?

  2. 最上位パス(/opt/pro...)は仮想メモリのコマンド部分(テキスト部分)であり、コマンドのみを含めますか?

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

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

  5. プロセスの仮想メモリ部分をよりよく表示できるgdbよりも優れたプログラムはありますか?私は実際の仮想メモリとどのデバッガが最良の結果を提供するかを明確に確認したいと思います。

私が言及した部分:

ここに画像の説明を入力してください。

ベストアンサー1

出力にgdbページ権限という重要な情報がありません。 (彼らは示しています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(これはfor stack6:各ヘッダー要求が4KiBソートを使用して4KiBより小さいため、異なるアドレスから同じオフセットを持つ2つの4KiBマップを取得するための小さなサイズを表します。)

空のマッピングは匿名マッピングに対応します。man 5 procもっと学ぶ。あなたは彼らが何に該当するのかmmapを深く理解する必要があります。gdb

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

より良いオプションがあるかどうかわからないので、gdb常に/proc/$$/maps

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

おすすめ記事