Linux

動態載入/連結庫的記憶體佈局

  • May 5, 2015

在 Linux 系統中載入共享庫時,共享庫的記憶體佈局是怎樣的?

例如,原始記憶體佈局如下:

+-----------+
|heap(ori)  |
+-----------+
|stack(ori) |
+-----------+
|.data(ori) |
+-----------+
|.text(ori) |
+-----------+

當我 dlopenfoo.so時,記憶體佈局是 A 還是 B?

A
+-----------+
|heap(ori)  |
+-----------+
|stack(ori) |
+-----------+
|.data(ori) |
+-----------+
|.text(ori) |
+-----------+
|heap(foo)  |
+-----------+
|stack(foo) |
+-----------+
|.data(foo) |
+-----------+
|.text(foo) |
+-----------+

或者

B
+-----------+
|heap(ori)  |
+-----------+
|heap(foo)  |
+-----------+
|stack(foo) |
+-----------+
|stack(ori) |
+-----------+
|.data(foo) |
+-----------+
|.data(ori) |
+-----------+
|.text(foo) |
+-----------+
|.text(ori) |
+-----------+

還是A和B以外的任何東西……?

答案是“其他”。您可以使用cat /proc/self/maps. 在我的 64 位 Arch 筆記型電腦上::

00400000-0040c000 r-xp 00000000 08:02 1186758                            /usr/bin/cat
0060b000-0060c000 r--p 0000b000 08:02 1186758                            /usr/bin/cat
0060c000-0060d000 rw-p 0000c000 08:02 1186758                            /usr/bin/cat
02598000-025b9000 rw-p 00000000 00:00 0                                  [heap]
7fe4b805c000-7fe4b81f5000 r-xp 00000000 08:02 1182914                    /usr/lib/libc-2.21.so
7fe4b81f5000-7fe4b83f5000 ---p 00199000 08:02 1182914                    /usr/lib/libc-2.21.so
7fe4b83f5000-7fe4b83f9000 r--p 00199000 08:02 1182914                    /usr/lib/libc-2.21.so
7fe4b83f9000-7fe4b83fb000 rw-p 0019d000 08:02 1182914                    /usr/lib/libc-2.21.so
7fe4b83fb000-7fe4b83ff000 rw-p 00000000 00:00 0
7fe4b83ff000-7fe4b8421000 r-xp 00000000 08:02 1183072                    /usr/lib/ld-2.21.so
7fe4b85f9000-7fe4b85fc000 rw-p 00000000 00:00 0
7fe4b85fe000-7fe4b8620000 rw-p 00000000 00:00 0
7fe4b8620000-7fe4b8621000 r--p 00021000 08:02 1183072                    /usr/lib/ld-2.21.so
7fe4b8621000-7fe4b8622000 rw-p 00022000 08:02 1183072                    /usr/lib/ld-2.21.so
7fe4b8622000-7fe4b8623000 rw-p 00000000 00:00 0
7ffe430c4000-7ffe430e5000 rw-p 00000000 00:00 0                          [stack]
7ffe431ed000-7ffe431ef000 r-xp 00000000 00:00 0                          [vdso]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0                  [vsyscall]

您可以看到執行檔被載入到低記憶體中,顯然是 .text 段、只讀數據和 .bss。差不多就是“堆”。在更高的記憶體中,C 庫和“ELF 文件解釋器”、“ld-so”被載入。然後是堆棧。對於任何給定的地址空間,只有一個堆棧和一個堆,無論載入了多少共享庫。cat似乎只載入了 C 庫。

這樣做cat /proc/$$/maps將為您提供呼叫的 shell 的記憶體映射cat。任何 shell 都會有許多動態載入的庫,但zshbash大量載入。你會看到只有一個“

$$ heap $$“,一個”$$ stack $$”。 如果您呼叫dlopen(),共享對象文件將在地址空間中映射到比/usr/lib/libc-2.21.so. 有一些“依賴於實現”的記憶體映射段,其中mmap()顯示了返回的所有地址。請參閱Anatomy of a Program in Memory以獲得漂亮的圖形。

的來源/usr/lib/ld-2.21.so有點棘手,但它與dlopen(). dlopen()不是二等公民。

“vdso”和“vsyscall”有點神秘,但是這個 Stackoverflow 問題有一個很好的解釋,維基百科也是如此。

引用自:https://unix.stackexchange.com/questions/200348