linux - 为什么 .bss 部分映射到一个比目标文件中报告的 bss 更小的进程?

标签 linux memory linux-kernel shared-libraries elf

我一直假设链接器分配了任何库的 bss 部分并将其映射到进程中。该部分的大小将取决于库报告的 bss 的大小。

我查看了进程的/proc/[PID]/maps 文件,并计算了加载库的 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 

这里我们可以看到 libpthread 的 bss 在地址范围 7f1f55839000-7f1f5583d000 中减去它们得到的大小为 16384 字节

使用size命令或readelf,libpthread的bss段大小为16848字节。

它们的不同是有道理的,因为虚拟地址范围需要与页面边界对齐,但虚拟大小如何小于 elf 文件报告的大小?没有足够的空间来容纳所有变量。

链接器是否能够确定 bss 中的某些变量对于特定的加载可执行文件不是必需的?如果是这样,这是如何完成的?

最佳答案

Here we can see that the bss of libpthread is in the address range 7f1f55839000-7f1f5583d000 and subtracting them gives us a size of 16384 bytes.

困难在于陈述并不完全准确。 ELF 链接器和 Linux 加载器实际上不保证节、段和映射之间的一对一关系。结果是突出显示的映射实际上并不代表 .bss所有(如您所见)。

通常使用默认链接器脚本的 ELF 链接器会创建两个 LOAD 段:一个 R/E(用于文本和只读数据)和一个 R/W(用于可写数据,包括.bss)。它将安排 .bss 出现在段的末尾,以便它可以设置关联的 ELF program header p_filesz 仅覆盖初始化数据,同时将 p_memsz 设置为更大的值以为 .bss 添加足够的空间。

当加载器处理这个段时,它会创建一个或两个映射。第一个映射将从 p_offsetp_filesz“支持文件”。因此,初始访问时的页面错误将保证必要的初始值。第一个映射的最后一页中剩余的任何空间都将 memset 设置为零(访问本身首先在任何初始化值中出错)。如果剩余的 p_memsz 适合新填充的零空间,那么这就是加载程序需要做的全部。否则,如果需要更多空间,加载程序将创建一个匿名映射(由 /dev/zero 支持)来覆盖剩余空间。

因此,.bss 在内存中的大小实际上是第二个匿名映射和前一个映射的“尾部”之和。可能是估计内存中 .bss 的最简单方法(在链接器、加载器和内核根据各种适用的 ELF、POSIX 和 Linux 标准应用的各种对齐约束内)正在使用 e.g. readelf --program-headers 获取适用段的 p_fileszp_memsz 并减去前者来自后者。

关于linux - 为什么 .bss 部分映射到一个比目标文件中报告的 bss 更小的进程?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25274569/

相关文章:

c - 在 Linux 中的 C 中添加全局键绑定(bind)?

c - 低级读取文件

java - Worklight 项目在构建时出现内存不足错误

linux - 哪些任务对应Linux内核调度器?

c - 等待用户输入的进程实际上发生了什么?

linux-kernel - Linux ARM 启动中地址 ZTEXTADDR 的使用

linux - 在 Konsole 中执行命令时显示时间

linux -/etc/sudoers 文件有问题但无法访问 root

java - 用于存储 2D 数组值的内存效率最高的数据结构 (Java)

c - 空指针取消引用未初始化的内存是否属于内存损坏