【问题标题】:Balancing the stack平衡堆栈
【发布时间】:2014-01-10 06:43:14
【问题描述】:

如果我这样设置堆栈

push rbp;
mov rbp, rsp;
sub rsp, 64;

我需要吗

mov rsp, rbp;
pop rbp;
ret 64;

或只有

mov rsp, rbp;
pop rbp;
ret;

?

【问题讨论】:

  • 第一个(带有ret 64)正在释放调用者设置的堆栈空间。这就是stdcall 摆脱堆栈上的参数的方式。但在这里它只会破坏一些东西。
  • @harold 如何在不破坏堆栈参数的情况下保留一些空间?
  • @harold 或者更好的问题是:我可以放心地使用 [rbp - from-8-to-64] 吗?
  • 通常是的,除非你写的东西当然大于 8 个字节
  • 那不是64字节的保留栈吗?还是它的 64 位?

标签: assembly x86-64 stack-pointer


【解决方案1】:

第二个,如果你打算使用 C 调用约定(调用者删除参数)。

mov rsp, rbp;
pop rbp;
ret;

如果您要使用第一个 Epilog,那么您的堆栈会发生以下情况:

push rbp;     ;RSP = RSP - 8  (1)  |
mov rbp, rsp; ;Keep RSP (2)        | Your prologue. Nothing wrong here.
sub rsp, 64;  ;RSP = RSP - 64      |
...
...
mov rsp, rbp; ;Retrieve RSP from (2)
pop rbp;      ;RSP = RSP + 8. Now it's at the same address as before (1)
ret 64;       ;Return, but after that, add 64 to RSP

所以当这个函数返回给它的调用者时,堆栈指针比它在CALL之前的位置提前了64个字节。这很好,如果您的函数是使用 STD 调用约定定义的(被调用者删除参数)。我认为这不是您想要的,因为您似乎认为 ret 64 是用于恢复堆栈为自动变量分配的 64 字节。

【讨论】:

  • 事实上,这段代码将替换Linux内核中的系统调用。那里有什么假设?谁必须关心参数?
  • 您可能需要检查此问题的所选答案:stackoverflow.com/questions/20520778/…
【解决方案2】:

这样做就足够了:

mov rsp, rbp;
pop rbp;
ret;

因为它将恢复 rsp 的旧值(无论在sub 指令中减少了多少)。

【讨论】:

  • 顺便说一句,我会尽快接受你的回答,让我来做吧(还剩 18 分钟)
猜你喜欢
  • 2016-05-06
  • 1970-01-01
  • 2011-05-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-10-10
  • 2014-03-13
相关资源
最近更新 更多