![动态加载/链接库的内存布局](https://linux22.com/image/64423/%E5%8A%A8%E6%80%81%E5%8A%A0%E8%BD%BD%2F%E9%93%BE%E6%8E%A5%E5%BA%93%E7%9A%84%E5%86%85%E5%AD%98%E5%B8%83%E5%B1%80.png)
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之外还有什么...?
答案1
答案是“其他”。您可以使用 来了解内存布局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
加载大量库。您会看到只有一个“[堆]”和一个“[堆栈]”。
如果调用dlopen()
,共享对象文件将被映射到比 更高的地址的地址空间中/usr/lib/libc-2.21.so
。有一些“依赖于实现”的内存映射段,其中mmap()
显示了返回的所有地址。看内存中程序的剖析为了一个漂亮的图形。
的来源/usr/lib/ld-2.21.so
有点棘手,但它与dlopen()
.dlopen()
不是二等公民。
“vdso”和“vsyscall”有点神秘,但是这个 Stackoverflow 问题有很好的解释,维基百科也有。