是否可以识别地址引用是否属于进程地址空间中的静态/堆/堆栈

时间:2016-02-04 16:28:00

标签: c heap-memory memory-address

我们有一种监控负载和机制的机制。存储捕获所引用地址的指令。我想对地址进行分类,无论它们属于堆栈,堆还是分配静态变量的区域。有没有办法以编程方式进行这种分类?

我最初的想法是在进程开始运行时立即执行一个带有小内存请求(1?)的malloc(),这样我就可以捕获"基地址"堆的(或起始地址)。这样,我可以区分静态分配的那些变量和其余的变量。对于那些不属于静态区域的引用(那些是堆和堆栈),我怎么能区分它们呢?

一些小测试显示以下简单代码(在Linux 3.18 / x86-64中使用gcc 4.8.4编译)

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

int x;

int foo (void)
{
    int s;
    int *h = malloc (sizeof(int));

    printf ("x = %p, *s = %p, h = %p\n", &x, &s, h);
}

int main (int argc, char *argv[])
{
    foo();
    return 0;
}

显示了地址空间的一些随机化(不是在静态变量中,而是在剩下的部分 - 堆和堆栈中),这可能会增加一些不确定性,但可能是一种找到地址空间的这些区域的限制的方法。 / p>

2 个答案:

答案 0 :(得分:8)

没有标准的C API,这意味着所有可能的解决方案都将基于特定于平台的黑客攻击。此外,这个答案仅限于单线程应用程序。

  1. 如何识别堆栈地址?
  2. 堆栈是一个连续的内存区域。因此,您需要知道的只有两个数字:堆栈的顶部和堆栈的底部。堆栈的顶部基本上受当前函数的堆栈帧的限制。但是,由于无法从C代码访问当前堆栈帧的大小,因此很难确定当前帧的确切位置。这里的技巧是从当前调用另一个函数,并使用被调用函数堆栈帧中的地址作为stack_top的边界值。

    学习堆栈的底部更简单 - 它的值在程序执行期间保持不变,并且受入口点函数的堆栈帧(C程序中的main())的限制。因此,在main()函数中获取某个局部变量的地址就足够了。

    另一个警告是x86堆栈向后增长,这意味着堆栈顶部的地址小于底部。这段代码总结了一下:

    void *stack_bottom;
    
    bool IS_IN_STACK(void *x) __attribute__((noinline));
    bool IS_IN_STACK(void *x) {
        void *stack_top = &stack_top;
        return x <= stack_bottom && x >= stack_top;
    }
    
    int main (int argc, char *argv[]) {
       int x;
       stack_bottom = &x;
       ...
    
    1. 如何识别静态变量的地址?
    2. 逻辑在这里更简单。静态变量在固定的,特定于平台的地址开始的内存区域中分配。通常该区域位于存储器中的所有其他区域之前。因此,唯一需要学习的是此静态存储区的 end 地址。

      幸运的是,GCC链接器provides symbols endedataetext表示.bss.data和{{1}的结尾分别是段。静态变量在.text.bss段中分配,因此在大多数平台上进行此检查应该足够了:

      .data

      此宏检查#define IS_STATIC(x) ((void*)(x) <= (void*)&end || (void*)(x) <= (void*)&edata) edata,以避免假设end.bss中的哪一个位于内存中。

      1. 堆地址。
      2. 堆变量通常直接分配在.data.data区域中的地址之后的地址中。但是,有时堆地址可能属于非连续的内存范围。因此,您可以在此处执行的最佳操作是读取Linux进程文件以查找其他答案中建议的内存映射。或者,只需检查.bssIS_IN_STACK是否都返回false。

        使用这些宏的完整程序:

        IS_STATIC

答案 1 :(得分:2)

我想为了获得正确的结果,您应该在Linux上解析/proc/<pid>/maps文件。样本内容:

# cat maps
00400000-00407000 r-xp 00000000 fc:02 1837717           /sbin/getty
00606000-00607000 r--p 00006000 fc:02 1837717           /sbin/getty
00607000-00608000 rw-p 00007000 fc:02 1837717           /sbin/getty
00608000-0060a000 rw-p 00000000 00:00 0 
0252e000-0254f000 rw-p 00000000 00:00 0                 [heap]
7f3ca601f000-7f3ca6833000 r--p 00000000 fc:02 2105304   /usr/lib/locale/locale-archive
...
7f3ca7656000-7f3ca7657000 r--p 00022000 fc:02 1711858   /lib/x86_64-linux-gnu/ld-2.19.so
7f3ca7657000-7f3ca7658000 rw-p 00023000 fc:02 1711858   /lib/x86_64-linux-gnu/ld-2.19.so
7f3ca7658000-7f3ca7659000 rw-p 00000000 00:00 0 
7fffbbcf2000-7fffbbd13000 rw-p 00000000 00:00 0         [stack]
7fffbbdfc000-7fffbbdfe000 r-xp 00000000 00:00 0         [vdso]
7fffbbdfe000-7fffbbe00000 r--p 00000000 00:00 0         [vvar]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0 [vsyscall]

请参阅proc(5)