我总是认为链接器分配了任何库的bss部分,并将其映射到进程中。本节的大小将取决于图书馆报告的bss的大小。
我查看了进程的/proc/PID/map文件,并计算了加载库的bss部分的大小。
7f1f5561f000-7f1f55637000 r-xp 00000000 08:01 3018048 /usr/lib/libpthread-2.19.so
7f1f55637000-7f1f55837000 ---p 00018000 08:01 3018048 /usr/lib/libpthread-2.19.so
7f1f55837000-7f1f55838000 r--p 00018000 08:01 3018048 /usr/lib/libpthread-2.19.so
7f1f55838000-7f1f55839000 rw-p 00019000 08:01 3018048 /usr/lib/libpthread-2.19.so
7f1f55839000-7f1f5583d000 rw-p 00000000 00:00 0
7f1f5583d000-7f1f55851000 r-xp 00000000 08:01 3017945 /usr/lib/libresolv-2.19.so
7f1f55851000-7f1f55a50000 ---p 00014000 08:01 3017945 /usr/lib/libresolv-2.19.so
7f1f55a50000-7f1f55a51000 r--p 00013000 08:01 3017945 /usr/lib/libresolv-2.19.so
7f1f55a51000-7f1f55a52000 rw-p 00014000 08:01 3017945 /usr/lib/libresolv-2.19.so
7f1f55a52000-7f1f55a54000 rw-p 00000000 00:00 0 在这里,我们可以看到size线程的bss位于地址范围7f1f55839000-7f1f5583d000,减去它们我们得到的大小为16384字节。
使用size命令或readelf,size线程的bss部分的大小为16848字节。
这是有道理的,因为虚拟地址范围需要排列到页面边界,但虚拟大小如何能够比精灵文件报告的更小的?没有足够的空间来容纳所有的变量。
链接器是否能够确定bss中的某些变量对于特定的加载可执行文件来说并不是必需的?如果是的话,是如何做到的?
发布于 2017-02-21 23:21:15
在这里,我们可以看到size线程的bss在地址范围7f1f55839000-7f1f5583d000,减去它们就得到了16384字节的大小。
困难的根源在于陈述并不完全准确。ELF链接器和Linux加载程序实际上并不保证节、段和映射之间的一对一关系。结果是,突出显示的映射实际上并不代表所有的.bss (正如您已经发现的)。
通常,使用默认链接器脚本的ELF链接器将创建两个LOAD段:一个R/E (用于文本和只读数据)和一个R/W (用于可写数据,包括.bss)。它将安排.bss出现在段的末尾,这样它就可以将关联的精灵程序头 p_filesz设置为只覆盖初始化的数据,同时将p_memsz设置为更大的值,以便为.bss添加足够的空间。
当加载程序处理此段时,它将创建一个或两个映射。第一个映射将是p_offset为p_filesz提供的“文件支持”。因此,初始访问上的页面错误将保证所需的初始值。在第一次映射的最后一页中留下的任何空间都将是memset到零(访问本身在任何初始化值中都有第一个错误)。如果剩余的p_memsz符合新的零填充空间,那么加载程序就只需要这样做了。否则,如果需要更多的空间,加载程序将创建一个匿名映射(由/dev/zero支持)以覆盖其余部分。
因此,内存中.bss的大小实际上是第二个匿名映射和前面映射的“尾部”之和。获得内存中.bss的估计的最简单方法(在链接器、加载程序和内核根据各种适用的ELF、POSIX和Linux标准应用的各种对齐约束范围内)可能是使用例如readelf --program-headers来获得适用段的p_filesz和p_memsz,并从后者中减去前者。
https://stackoverflow.com/questions/25274569
复制相似问题