堆栈是否在需要时分配更多空间或是否溢出?

Dra*_*eel 1 c memory assembly stack

对于x86程序集,假设我们有一个像这样的堆栈 在此输入图像描述

堆栈有2个单词分配给它拥有的2个局部变量.但是如果你强行将第三个局部变量推送到堆栈会怎么样呢.ESP是否向上移动以为变量腾出空间或变量是否覆盖ESP?

Eri*_*hil 9

使用x86,将数据"推送"到堆栈的指令也会修改堆栈指针(%esp在本例中)以标记新的堆栈顶部."弹出"数据的指令以相反的方向修改堆栈指针.

在没有特殊推送和弹出指令的机器上,程序必须首先修改堆栈指针,然后将数据存储到堆栈中.

通常,为堆栈保留大面积.堆栈指针仅标记当前正在使用的部分.程序可以根据需要自由地上下移动堆栈指针.

为堆栈保留的区域可能取决于操作系统和/或开发人员工具.例如,在使用Apple开发人员工具的macOS上,默认堆栈大小为8兆字节,可以通过"-stack_size size "切换到链接器(ld命令)进行更改.(这是针对主堆栈的.使用多个线程的程序为每个创建的线程都有一个额外的堆栈.这些堆栈的堆栈大小是单独设置的.)

尽管为堆栈保留了大面积的虚拟地址空间,但是一旦程序启动,操作系统可能不会将其全部映射到物理内存.操作系统可能只映射其中的一部分,然后在堆栈扩展到区域时映射更多部分.

通常,堆栈之外的虚拟地址空间的某些部分保持未映射,因此尝试访问它将导致异常.此区域中的地址空间页面称为保护页面.因此,如果程序使堆栈超出保留区域并尝试将值写入未映射的防护页面,则会发生异常,系统将报告堆栈溢出.

没有什么能阻止程序写入为堆栈保留的区域,但稍微超出堆栈指针.这将是一个错误,但通常不会被硬件检测到.此外,执行此操作的程序可能会正常运行一段时间; 它可以将数据存储到该区域并按预期加载回来.但是,您的过程中还会发生一些您通常不知道的事情.例如,可以将信号传递给您的过程.发生这种情况时,系统会中断程序的常规处理,将新数据压入堆栈,并调用信号处理程序例程.例程返回时,数据将从堆栈中删除,程序将恢复正常执行.但是,如果您的程序已经存储了超出堆栈指针的数据,那么该数据现在已经消失,因为它被信号处理程序的数据覆盖了.因此,存储超出堆栈指针的数据的程序似乎在大多数时间都可以工作,但在信号到达错误时刻的极少数情况下会失败.

(在某些系统上,堆栈的安全区域实际上是超出堆栈指针中地址的固定距离,而不是指向该地址的固定距离.这个额外的安全空间可称为"红色区域".)