為什麼某些庫和其他部分會在 gdb 的 linux 虛擬記憶體中重複?
這是在 gdb 中查看程序的虛擬記憶體的結果;我對此有一些疑問:
- 為什麼虛擬記憶體的某些部分是重複的?比如我們的程序(stack6)和libc庫重複4次;如果他們將它們分成不同的部分,那為什麼呢?為什麼不把它們放在一起呢?
- 最上面的路徑(/opt/pro…)是我們虛擬記憶體的指令部分(文本部分)並且只包含指令嗎?
- 為什麼4個libc的大小不同?偏移量是怎麼回事,如果我們已經有了大小和起始地址,那麼偏移量是什麼?
- 數據、bss、核心和堆部分在哪裡?為什麼上圖中的某些部分沒有關於它們的資訊?gdb 中是否有更好的選項可以實際顯示所有部分?
- 有沒有比 gdb 更好的程序可以更好地顯示我們程序的虛擬記憶體部分?我只想對實際的虛擬記憶體有一個很好的了解,哪個調試程序提供了最好的結果。
我提到的部分:
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 映射。第四個映射是一個不可讀、不可寫、不可執行的段,通常用於防止緩衝區溢出(儘管考慮到這裡使用的核心和 C 庫的年齡,這可能會有所不同)。偏移量,當給出時,表示文件中數據的偏移量,它不一定與它在地址空間中的位置有很大關係。載入時,這會受到對齊約束;例如,
libc-2.11.2.so
的程序標頭檔指定了兩個“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,因此它在不同地址獲得兩個具有相同偏移量的 4KiB 映射。)空白映射對應匿名映射;詳情見
man 5 proc
。您需要闖入mmap
以gdb
確定它們對應的內容。您看不到核心映射(除了
vsyscall
某些架構上的遺留問題),因為從程序的角度來看它們並不重要(它們不可訪問)。我不知道更好的
gdb
選擇,我總是使用/proc/$$/maps
.有關核心讀取的 ELF 格式的詳細資訊,以及它如何映射到記憶體分配,請參閱程序如何執行:ELF 二進製文件;它有指向更多參考資料的指針。