Stack是遵循LIFO规则的数据结构。在汇编语言中,当我们调用一个函数时,我们需要使用“push”指令将参数压入堆栈。但为什么我们需要堆栈清理代码来删除参数?大多数堆栈清理代码看起来像
add esp N
如何从堆栈中删除参数?
答案 0 :(得分:2)
我首先回答OP问题的第一部分:为什么?因为对于大多数CPU来说,堆栈包含当前函数的本地存储(局部变量和参数)和控制信息(返回地址,指向前一个堆栈帧的指针等)
当你调用一个不自行清理堆栈的函数时(例如,遵循cdecl调用约定的函数),调用者负责在被调用者返回后离开堆栈,状态与之前相同电话。这意味着如果调用者将N个字节推送到堆栈,它必须通过弹出并抛弃它们或者更快地从堆栈中删除N个字节,方法是通过直接修改堆栈指针的值来跳过这些字节(即,ADD SP,N指令)。否则,堆栈会为每个未清理的被调用函数增长,最终会发生堆栈溢出。
答案 1 :(得分:1)
对于向下增长的堆栈,意味着它以更高的地址开始,并且当您执行推送指令时,它会从堆栈指针中减去一些值。该函数需要在找到它时返回堆栈(指针)。所以你可以做一堆pop命令,在这种情况下添加到堆栈指针地址,或者你可以简单地向堆栈指针添加推送量。或者另一种解决方案是,您可以以不干扰调用者的方式保存堆栈指针,并简单地恢复该值。一堆弹出指令通常是浪费指令空间和执行时间,尤其是当一个添加指令可以有效地做同样的事情时。
清理堆栈绝不意味着实际上恢复你在堆栈上乱搞的ram,根据定义,在堆栈指针下面的ram是公平的游戏,它只是意味着将堆栈指针返回到它的被调用状态。
答案 2 :(得分:0)
堆栈指针寄存器(ESP)指向堆栈顶部。由于堆栈增长,因此增加ESP的值会从堆栈中删除项目。更改ESP的值是从堆栈中删除项目的唯一方法,无论是使用ADD还是LEA指令显式删除还是隐式使用POP或RET