-1

我刚开始组装,我发现这些指令和类似的指令遍布代码片段:

sub esp , something
mov esp, dword ptr [esp + something] 

为什么要这样做?我听说这是关于堆栈帧的初始化。您能解释一下或指出我要查找的关键字吗?

4

2 回答 2

0

每个 C(除了一些inline函数,而不仅仅是 C 函数)函数都有它的开始和结束。开头通常是这样的:

push ebp
mov ebp, esp
sub esp, x

第一行推送旧的堆栈帧。由于在程序运行期间调用了许多函数,因此函数可以在调用另一个函数时将其堆栈帧保存在堆栈中。堆栈帧(通常存储在EBP寄存器中)是每个局部变量寻址的基础。假设您有以下代码:

int main() {
    __volatile int localVariable = 0x10;
    printf("%d");
}

变量localVariable可以静态存储在某个地方(例如在 address 上0x410000),但如果main再次调用,该地址上的值将被覆盖。因此需要动态分配之类的东西。这就是堆栈帧的用途;保存先前的堆栈帧并为局部变量相对于堆栈指针的实际位置“分配”位置。在这种情况下,localVariable应始终在位置上EBP-sizeof(int)

第二行和第三行实际上是分配“新”内存的那段代码。第三行从ESP(stack grows down) -> 中减去一些值,这就是函数不会覆盖其变量的原因;每个功能都有自己的位置。第二行保存旧的堆栈指针,所以当被调用的函数从它的堆栈帧返回时,它会堆栈上一个函数的指针。

函数的标准结尾是

mov esp, ebp
pop ebp
ret

或在第二个示例中保留 ret leave可以替代第一个示例中的前两行,因为函数经常返回到前一个函数的执行。

寻址EBP - something通常意味着访问被调用(当前)函数的局部变量。

寻址EBP + someting通常意味着访问传递给函数的参数。

需要注意的是,EBP实际上存储的地址并不指向参数,而是指向函数的返回地址,该地址是call在调用函数时由指令推送的。存储的值EBP + 4可以是第一个(旧做法,例如用于具有可变数量参数的函数,printfObject... values它)。

于 2013-07-18T06:32:24.700 回答
0

乍看之下是 Intel x86。'Something' 通常是所有本地(堆栈分配的)变量的总长度,如果它出现在汇编子程序的开头。由于堆栈向下增长,即朝向较低地址,这为它们保留了空间。你确定第二行就是你写的吗?esp 已经指向空闲区域,因此在您的例程递归调用自身或调用另一个函数之前,可以将参数推送到本地人下方的堆栈中。除非它用于允许(下一个)被调用者访问调用者的堆栈帧,就像在 Pascal 中,当你有嵌套函数时,我没有看到在调整它以适应本地变量之后立即将其加载到 esp 的意义。

于 2013-07-15T15:33:10.490 回答