如何以编程方式获取 Linux 上的堆地址

Posted

技术标签:

【中文标题】如何以编程方式获取 Linux 上的堆地址【英文标题】:How to programmatically get the address of the heap on Linux 【发布时间】:2011-04-03 16:11:31 【问题描述】:

我可以用sbrk(0)得到堆尾的地址,但是除了解析/proc/self/maps的内容之外,还有什么方法可以通过编程方式获取堆的开始地址?

【问题讨论】:

这让我很困惑......如果我得到一个 p = (int *) malloc (sizeof(int)); 的堆,那为什么我不能通过p获取堆的起始地址呢? 【参考方案1】:

我认为解析/proc/self/maps 是Linux 上查找堆段的唯一可靠方法。并且不要忘记一些分配器(包括我的 SLES 中的一个)确实用于大块 mmap(),因此内存不再是堆的一部分,并且可以位于任何随机位置。

否则,通常ld会添加一个符号来标记elf中所有段的结束,该符号称为_end。例如:

extern void *_end;
printf( "%p\n", &_end );

它匹配.bss 的结尾,传统上是elf 的最后一段。在地址之后,经过一些对齐,通常在堆之后。 Stack(s) 和 mmap()s(包括共享库)位于地址空间的较高地址。

我不确定它的可移植性如何,但显然它在 Solaris 10 上的工作方式相同。在 HP-UX 11 上,映射看起来不同,堆似乎与数据段合并,但分配确实发生在 @ 987654327@。在 AIX 上,procmap 根本不显示堆/数据段,但分配也使地址超过了 _end 符号。所以它似乎目前相当便携。

不过,综合考虑,我不确定这有多大用处。

附:测试程序:

#include <stdio.h>
#include <stdlib.h>

char *ppp1 = "hello world";
char ppp0[] = "hello world";
extern void *_end; /* any type would do, only its address is important */

int main()

    void *p = calloc(10000,1);
    printf( "end:%p heap:%p rodata:%p data:%p\n", &_end, p, ppp1, ppp0 );
    sleep(10000); /* sleep to give chance to look at the process memory map */
    return 0;

【讨论】:

那么,如果没有办法找到堆起始地址,malloc是如何实现的,它试图将堆拆分成更小的内存块? 请注意,这在具有随机偏移的系统中可能会失败。它可以启用,但默认情况下 linux 会模糊堆“开始”的位置,因此很难从机器外部找到它(防止缓冲区溢出攻击)。 @Jun,libc调用sbrk(0)查找堆的起始地址。但这仅适用于 libc:它在应用程序启动期间很早就被调用,在 main() 之前,因此堆的结尾与堆的开头相同。在main() 里面,它不再是真的了。

以上是关于如何以编程方式获取 Linux 上的堆地址的主要内容,如果未能解决你的问题,请参考以下文章

Linux C++ 如何以编程方式获取 LAN 上所有适配器的 MAC 地址

如何在 Android 上以编程方式从 Mac 地址获取 IP 地址?

如何以编程方式获取 linux 内核页面大小

如何以编程方式获取android手机的IP地址......? [复制]

如何以编程方式获取 iOS 设备 MAC 地址

如何以编程方式获取公共 IP 地址?