初学者对x86堆栈的困惑

时间:2015-05-18 21:15:35

标签: c stack

首先,我想知道这个模型是否准确表示了堆栈"框架"处理。

我已经被告知,从概念上讲,堆栈就像一个可乐瓶。糖在底部,你把它填满了顶部。考虑到这一点,Call如何告诉EIP寄存器" target"如果EIP在另一个瓶子里(它在代码段中,而不是堆栈段),被调用的函数?我在YouTube上观看了一段视频,内容是" RAM的代码段" (保存功能的地方)是EIP注册的地方。

1 个答案:

答案 0 :(得分:8)

通常,计算机程序使用四种存储区域(也称为区段或段):

  • text部分:包含程序代码。当程序由操作系统加载时保留。此区域是固定的,在程序运行时不会更改。这最好被称为"代码"部分,但名称有历史原因。
  • data部分:包含程序的变量。程序加载并初始化为程序员定义的值时保留它。程序在执行时可以更改这些值。
  • 堆栈:这是一个动态的内存区域。它用于存储函数调用的数据。它主要通过"推动"值堆栈并从堆栈弹出。这也被称为" LIFO":先进先出。这是函数的局部变量所在的位置。如果函数完成,则数据将从堆栈中删除并丢失(基本上)。
  • :这也是一个动态内存区域。编程语言中有特殊的功能,即分配"根据该计划的要求(保留)该区域的一部分。如果不再需要,可以使用另一个函数将此区域返回到堆中。当数据被明确释放时,它可以用来存储比函数调用更长的数据(不同于堆栈)。

textdata部分的数据存储在程序文件中(例如,可以使用objdump在Linux中找到它们(在名称中添加. )。堆栈不会存储在文件中的任何位置,因为它们是由程序本身动态(按需)分配的。

通常,在加载程序后,内存区域重新定义被视为单个大块,其中堆栈都位于其中。它们从该区域的另一端开始并朝向彼此生长。对于大多数体系结构,堆从低到高的内存地址(升序)和堆栈向下(降序)增长。如果它们相交,程序就会耗尽内存。由于这可能未检测到,堆栈可能会损坏(更改外部数据)堆,反之亦然。这可能会导致任何类型的错误,具体取决于数据/数据的变化。如果堆栈被破坏,这可能导致程序疯狂(这实际上是木马可能工作的一种方式)。然而,现代操作系统应该采取措施在这种情况变得至关重要之前对其进行检测。

这不仅适用于x86,也适用于大多数其他CPU系列和操作系统,特别是:ARM,x86,MIPS,MSP430(微控制器),AVR(微控制器),Linux,Windows,OS-X,iOS,Android (使用Linux OS),DOS。对于微控制器,通常没有堆(在运行时分配所有内存),堆栈的组织方式可能有所不同;对于基于ARM的Cortex-M微控制器也是如此。但无论如何,这是一个非常特殊的主题。

免责声明:这是非常简化的,所以请不要评论像" bss,const,myspecialarea" ;-)怎么样。对于这些区域,C标准也没有要求,特别是使用堆或堆栈。确实有些实施方案也没有使用。这些是大多数时候嵌入式系统具有小型(8或16位)MCU或DSP。现代架构也使用CPU寄存器而不是堆栈来传递参数并保留局部变量。这些是在目标平台的应用程序二进制接口中定义的。

对于堆栈,您可能会阅读wikipedia article。注意数据结构与#34; stack"之间的实现差异。和#34;硬件堆栈"在典型的(微)处理器中实现。