判断一个地址属于堆、栈还是寄存器

7

我手头有一个指向C/C++变量的指针。是否可能确定该变量属于内存的哪个段?如果可以,如何确定?

注意:我只有这个变量的地址,没有进一步的信息,例如变量是本地的还是全局的等。


10
不可能,至少没有一种可移植的方式。 - juanchopanza
3
你希望解决什么问题?你需要一个运行时或编译时的解决方案吗?寄存器没有地址。 - Maksim Burnin
我们刚刚争论全局变量是属于堆还是栈,想要自己确认一下 :P - Amit Tomar
12
回答实际问题:全局变量是独立的,不在堆栈或堆中。 - Bo Persson
@BradTilley:静态存储是否使用堆内存未指定,如果您依赖于此,则为未定义的行为。静态存储不能使用栈,因为后者会强制执行销毁顺序语义,这与前者不兼容。然而,堆不会强制执行此类限制,因此可以支持静态存储和栈。 - MSalters
感谢 @BoPersson 和 Maksim。学到了新东西 :-) - Amit Tomar
4个回答

2

查找您的架构是否有指向堆或栈区域的指针。通常有一些堆栈指针或帧指针。

然后将实际地址与这些地址进行比较,并确定它们属于哪个区域。


呵呵,是的,你说得对 ;) 但如果你谈论异构架构,也有可能将全局变量放在堆栈或堆中。这也取决于架构。 - duedl0r
我有提到过 Univac 硬件也没有堆栈吗?-. - Bo Persson
1
我只相信1981年之后发明的东西,呵呵呵 :D - duedl0r
@BoPersson:只有当打孔卡片堆不算的时候 :P - Damon

2
如果您使用的是Linux系统(对于其他UNIX系统不确定),您可以在文件/proc/<pid>/maps中找到相关信息。

1

您可以首先确定可执行文件中不同部分的起始和结束位置。为此,您需要在链接器脚本中添加一些变量来标识每个部分,例如:

SECTIONS {
    [...]
    .data : {
        data_start = .;
        *(.data)
        data_end = .;
    }
    [...]
}

然后,您可以在C/C++代码中将这些变量声明为外部变量,并直接使用它们来比较您想要识别的地址。

调整链接器脚本可能并不容易。使用gcc,您可以通过以下命令将其转储出来:

gcc -Wl,-verbose whatever.c

然后尝试在(混乱的)输出中查找已定义的变量。

要获取堆栈的边界,您可以在main()函数开头实例化一个虚拟变量,并将其地址保存为堆栈顶部,然后在当前位置实例化另一个变量,这将给您底部。但是,请注意编译器可能不会完全像这样行事(C语言中变量的堆栈顺序不能保证,甚至不能保证使用堆栈),因此这应该可以工作,但不具备可移植性。

最后,对于堆,我没有什么技巧。我只会推断出不在data/bss/derivated中且不在堆栈中的变量将在堆中(排除寄存器,但如果您可以获取地址,我敢打赌编译器永远不会使用仅寄存器存储)。


0

我不确定它是否适用于您的情况,但您可以尝试使用 objdump -t 来查看 ELF 文件的符号表。您只需要知道变量的地址即可。在那里,您可以找到显示每个变量所属部分的标志。有关更多详细信息,请参阅 objdump 的手册页面。

示例输出:

0804a020 g     O .bss   00000004              var

它表示var是一个global Object,位于地址0804a020,部分为.bss


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接