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

C 堆栈是否在需要时分配更多空间,还是溢出?,c,assembly,memory,stack,C,Assembly,Memory,Stack,对于x86程序集,假设我们有这样一个堆栈 堆栈为其拥有的2个局部变量分配了2个字。但是,如果强制将第三个局部变量推送到堆栈中会怎么样呢。ESP是否向上移动以为变量腾出空间,或者变量是否覆盖ESP?使用x86,“推送”数据到堆栈的指令也会修改堆栈指针(%ESP,在这种情况下)以标记新的堆栈顶部。“弹出”数据以相反方向修改堆栈指针的指令 在没有特殊push和pop指令的机器上,程序必须首先修改堆栈指针,然后将数据存储到堆栈中 通常,为堆栈保留一个较大的区域。堆栈指针仅标记当前正在使用的部分。程序可

对于x86程序集,假设我们有这样一个堆栈


堆栈为其拥有的2个局部变量分配了2个字。但是,如果强制将第三个局部变量推送到堆栈中会怎么样呢。ESP是否向上移动以为变量腾出空间,或者变量是否覆盖ESP?

使用x86,“推送”数据到堆栈的指令也会修改堆栈指针(
%ESP
,在这种情况下)以标记新的堆栈顶部。“弹出”数据以相反方向修改堆栈指针的指令

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

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

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

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

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

没有任何东西阻止程序写入为堆栈保留的区域,但略超出堆栈指针。这可能是一个bug,但硬件通常不会检测到它。此外,这样做的程序可能会正常运行一段时间;它可以将数据存储到此区域,并按预期将其加载回。然而,在你的过程中还有一些你通常不知道的事情发生。例如,可能会向您的进程发送一个信号。发生这种情况时,系统会中断程序的常规处理,将新数据推送到堆栈上,并调用信号处理程序例程。当例程返回时,数据将从堆栈中删除,程序将恢复正常执行。但是,如果您的程序在堆栈指针之外存储了数据,那么该数据现在就消失了,因为它被信号处理程序的数据覆盖了。因此,在堆栈指针之外存储数据的程序似乎大部分时间都在工作,但在信号到达错误时刻的罕见情况下会失败


(在某些系统上,堆栈的安全区域实际上是超出堆栈指针地址的固定距离,而不是正好位于该地址。这个额外的安全空间可以称为“红色区域”。

对于x86,“推送”数据到堆栈的指令也会修改堆栈指针(
%esp
)标记新的堆栈顶部。“弹出”数据以相反方向修改堆栈指针的指令

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

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

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

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

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

没有任何东西阻止程序写入为堆栈保留的区域,但略超出堆栈指针。这可能是一个bug,但硬件通常不会检测到它。此外,这样做的程序可能会正常运行一段时间;它可以将数据存储到此区域,并按预期将其加载回。然而,在你的过程中还有一些你通常不知道的事情发生。例如,可能会向您的进程发送一个信号。发生这种情况时,系统会中断程序的常规处理,将新数据推送到堆栈上,并调用信号处理程序例程。当例程返回时,数据将从堆栈中删除,程序将恢复正常执行。但是,如果您的程序在堆栈指针之外存储了数据,那么该数据现在就消失了,因为它被信号处理程序的数据覆盖了。因此,在堆栈指针之外存储数据的程序似乎大部分时间都能工作