堆地址范围内全局变量的地址

Address of a Global Variable in the Heap Address Range

我正在调试 MPlayer-1.3.0 源代码,我看到一个全局变量,其地址(由 GDB 或什至简单打印返回)在堆分配范围内,而不是数据部分。我使用 procfs.

检查了堆范围
555555554000-555555834000 r-xp 00000000 08:12 798876  /usr/bin/mplayer
555555a33000-555555b25000 r--p 002df000 08:12 798876  /usr/bin/mplayer
555555b25000-555555b2b000 rw-p 003d1000 08:12 798876  /usr/bin/mplayer
555555b2b000-555556479000 rw-p 00000000 00:00 0       [heap]
7fffc3fff000-7fffc8000000 rw-s 00000000 00:16 1932    /dev/shm/pulse-shm-3887887751

变量定义为int verbose = 0;,位于mp_msg.cline 40,地址为0x555555b3bbb0,在[heap]映射中。我什至检查了它前后的一些变量定义:

int mp_msg_levels[MSGT_MAX]; // verbose level of this module. initialized to -2
int mp_msg_level_all = MSGL_STATUS;
int verbose = 0;
int mp_msg_color = 0;
int mp_msg_module = 0;

其中,只有 mp_msg_level_all 位于数据部分。感谢任何帮助。

mp_msg_level_all 在数据段中,因为它被初始化为非零值。其余初始化为 0,因此属于 bss 部分。

为什么链接器决定将 bss 放入明显的​​堆地址范围,我们可能只是想知道。

假设你的问题是"why is int verbose = 0; allocated to [heap] memory mapping according to /proc/self/maps ?",答案是

  1. 整个 [heap] 概念实际上是早已被遗忘的过去的遗物,
  2. 传统的 [heap].bss 之后立即开始,并且它们通常共享相同的映射,因此这里 没什么 值得惊讶。

稍微扩展点 1,在旧的传统 UNIX 内存模型中(在线程和 mmap 成为事物之前),在堆栈向下增长的处理器上,内存的上半部分保留给内核space,栈从用户内存的最高端开始,程序.text本身从地址0开始,紧随其后的是.data.bss,然后是堆( brk / sbrk kind)之后。这允许堆增长到更高的地址,并为组合的堆+堆栈提供最大可用内存。

该模型在存在线程、共享库和内存映射文件的情况下根本无法正常工作,并且在很大程度上已被现代 malloc 实现所放弃,现代 malloc 实现很少打扰 sbrk根本。相反,他们只是 mmap 他们需要的内存(并且任何此类内存都不会显示在 [heap] 中,而您在 procfs 中看到)。

P.S.

  • 将零页映射到进程 space 的想法早已被放弃,因为它只会导致错误。这就是为什么 .text 在所有现代 UNIXen 上都从较高地址开始的原因。
  • 给内核一半可用地址space也很浪费,32位Linux开始给内核少很多space。在 64 位系统上 运行 超出地址 space 不再是问题。

更新:

So you mean that [heap] contains both .bss and part of heap. So, the only way to determine if an address is inside the heap is to trace malloc(),free(),... calls?

我觉得我没有解释清楚。

进程 space 中有一个名为 "heap" 的区域的 概念 已过时。一个现代的 malloc 实现很可能有多个特定于线程的领域,通过 mmap 从系统获得,并且堆分配的对象可以在其中任何一个中。

你不能轻易说 "oh, this address 0x568901234 looks like heap",因为它可以是任何东西。

What is the standard way to determine the address ranges for virtual memory areas (e.g., .text, heap and .bss) of a process in Linux, if procfs output is obsolete?

在这里,您再次尝试用有些过时的术语来解释内存布局:没有一个.text.bss大多数进程,因为每个共享库都有自己的(除了主可执行文件之外)。还有许多 附加 部分(.tls.plt.got 等) 部分在运行时甚至 都不需要 -- ELF(在运行时)只需要段,而不关心部分。