我在 Linux 系統上檢查 Python 行程的記憶體映射,發現了一些非常令人驚訝的事情。通常,當我檢查 Python 行程的映射時,它們看起來像這樣:
00400000-00401000 r-xp 00000000 fe:01 2904802 python3.9
00600000-00601000 r--p 00000000 fe:01 2904802 python3.9
00601000-00602000 rw-p 00001000 fe:01 2904802 python3.9
00637000-00abe000 rw-p 00000000 00:00 0 [heap]
...
7f67d8565000-7f67d8593000 rw-p 00000000 00:00 0
7f67d8593000-7f67d88ea000 r-xp 00000000 fe:01 2904547 libpython3.9.so.1.0
7f67d88ea000-7f67d8ae9000 ---p 00357000 fe:01 2904547 libpython3.9.so.1.0
7f67d8ae9000-7f67d8aef000 r--p 00356000 fe:01 2904547 libpython3.9.so.1.0
7f67d8aef000-7f67d8b29000 rw-p 0035c000 fe:01 2904547 libpython3.9.so.1.0
7f67d8b29000-7f67d8b4b000 rw-p 00000000 00:00 0
...
7fff72a4f000-7fff72a70000 rw-p 00000000 00:00 0 [stack]
7fff72a7c000-7fff72a80000 r--p 00000000 00:00 0 [vvar]
7fff72a80000-7fff72a82000 r-xp 00000000 00:00 0 [vdso]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0 [vsyscall]
這具有以下結構:
- 與同一個二進制/共享物件關聯的所有映射都是連續的。
- 可執行檔案 (
python3.9) 的映射首先出現,打開的共享庫的映射出現在可執行檔案中的映射之后。這是有道理的,因為首先加載可執行檔案,然后加載器按原樣加載共享物件DT_NEEDED。
但是我找到的地圖是這樣的:
00400000-00401000 r-xp 00000000 fd:00 67488961 python3.9
00600000-00601000 r--p 00000000 fd:00 67488961 python3.9
00601000-00602000 rw-p 00001000 fd:00 67488961 python3.9
0067b000-00a58000 rw-p 00000000 00:00 0 [heap]
...
7f7b46014000-7f7b46484000 r--p 0050b000 fd:00 1059871 libpython3.9.so.1.0
7f7b46484000-7f7b46485000 ---p 00000000 00:00 0
7f7b46485000-7f7b46cda000 rw-p 00000000 00:00 0
7f7b46cda000-7f7b46d16000 r--p 00a3d000 fd:00 1059871 libpython3.9.so.1.0
7f7b46d16000-7f7b46d6f000 rw-p 00000000 00:00 0
7f7b46d6f000-7f7b46d92000 r--p 00001000 fd:00 67488961 python3.9
7f7b46d92000-7f7b46d93000 ---p 00000000 00:00 0
7f7b46d93000-7f7b475d3000 rw-p 00000000 00:00 0
...
7f7b5a35d000-7f7b5a827000 r-xp 00000000 fd:00 1059871 libpython3.9.so.1.0
7f7b5a827000-7f7b5aa27000 ---p 004ca000 fd:00 1059871 libpython3.9.so.1.0
7f7b5aa27000-7f7b5aa2c000 r--p 004ca000 fd:00 1059871 libpython3.9.so.1.0
7f7b5aa2c000-7f7b5aa67000 rw-p 004cf000 fd:00 1059871 libpython3.9.so.1.0
7f7b5aa67000-7f7b5aa8b000 rw-p 00000000 00:00 0
...
7fff26f8e000-7fff27020000 rw-p 00000000 00:00 0 [stack]
7fff27102000-7fff27106000 r--p 00000000 00:00 0 [vvar]
7fff27106000-7fff27108000 r-xp 00000000 00:00 0 [vdso]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0 /vsyscall]
這有以下奇怪之處:
- 沒有與共享物件
python3.9或libpython3.9.so.1.0共享物件相關聯的連續段塊。事實上,這些都是分散的。 - 可執行檔案的映射可以在共享庫中的映射之后找到:
7f7b46cda000-7f7b46d16000 r--p 00a3d000 fd:00 1059871 libpython3.9.so.1.0
7f7b46d16000-7f7b46d6f000 rw-p 00000000 00:00 0
7f7b46d6f000-7f7b46d92000 r--p 00001000 fd:00 67488961 python3.9
7f7b46d92000-7f7b46d93000 ---p 00000000 00:00 0
您知道什么會導致這種影響或在什么條件下會發生這種情況嗎?您知道在多個共享物件之后加載可執行檔案的記憶體映射是如何可能的嗎?
注意:這是使用 kernel Kernel 5.13.12-100.fc33.x86_64。
uj5u.com熱心網友回復:
您知道什么會導致這種影響或在什么條件下會發生這種情況嗎?
可執行檔案可以簡單地mmap(部分)自身。這可以用來檢查它自己的符號表(列印崩潰堆疊跟蹤所必需的),或者提取一些嵌入的資源。
可執行檔案 (python3.9) 的映射首先出現,打開的共享庫的映射出現在可執行檔案中的映射之后。
這只是偶然發生的,并且僅適用于非 PIE 可執行檔案。
非PIE可執行上x86_64被傳統上連接到負載在地址0x400000,和共享庫正常加載從主堆疊下面開始。
如果您鏈接非 PIE 可執行檔案以在 eg 處加載0x7ff000000000,那么它很可能會出現在/proc/$pid/maps 之后的共享庫中。
更新:
這里的 python 二進制檔案肯定不是 mmapping 本身,因此該解釋不適用
- 你不可能知道——你幾乎可以肯定沒有閱讀Python 3.9 中的所有代碼以及你加載的每個模塊。
- 無需猜測這些
mmaped 區域來自何處,您只需查看.
要查看,請在 GDB 下運行您的程式并使用catch syscall mmap后跟where. 這將允許您查看每個映射的來源。
轉載請註明出處,本文鏈接:https://www.uj5u.com/gongcheng/346792.html
上一篇:除了一個之外的Cat檔案
