Linux
動態載入/連結庫的記憶體佈局
在 Linux 系統中載入共享庫時,共享庫的記憶體佈局是怎樣的?
例如,原始記憶體佈局如下:
+-----------+ |heap(ori) | +-----------+ |stack(ori) | +-----------+ |.data(ori) | +-----------+ |.text(ori) | +-----------+
當我 dlopen
foo.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 都會有許多動態載入的庫,但zsh
會bash
大量載入。你會看到只有一個“$$ 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 問題有一個很好的解釋,維基百科也是如此。