为什么推送堆栈首先从堆栈指针中减去然后插入数据?

时间:2017-05-12 18:35:37

标签: stack

我想知道为什么推送指令首先减去然后插入数据。

通过此实现,堆栈指针指向最后推送的数据。虽然这通常不是问题,但我认为,因为在程序开始时堆栈中没有有效数据,所以首先插入然后减少堆栈指针更有意义。

为什么:

sub  $8,%rsp        # subtract 8 from rsp
mov  reg,(%rsp)     # store, using rsp as the address

而不是这个:

mov  reg,(%rsp)     # store, using rsp as the address
sub  $8,%rsp        # subtract 8 from rsp

他们选择这种操作顺序是否有特殊原因?

1 个答案:

答案 0 :(得分:2)

例如,在32位x86架构中,您可以将不同大小的值压入堆栈。没有办法事先知道你想要推送什么尺寸值,所以指针不能事先移动,在这种情况下是在商店之后。

所以,假设你有这个代码:

PUSH EAX
PUSH BX
PUSH ECX

如果我们先存储然后减去我们得到这个(假设ESP为100并且忽略ESP / SP混合使用的可能问题):

MOV EAX, (%ESP) // EAX -> 100..103
SUB %ESP, 4 // ESP = 96
MOV BX, (%SP) // BX -> 96..97
SUB %SP, 2. // ESP = 94
MOV ECX, (%RSP) // ECX -> 94..97
SUB %RSP, 4 // ESP = 90

了解减法如何始终将之前的大小用于下一个。这意味着推送BX将首先导致两个未使用的字节在堆栈中,然后推送ECX实际上覆盖堆栈中的BX值。首先进行减法时,它总是使用被推送到堆栈的当前值的大小:

SUB %ESP, 4 // ESP = 96
MOV EAX, (%ESP) // EAX -> 96..99
SUB %SP, 2. // ESP = 94
MOV BX, (%SP) // BX -> 94..95
SUB %RSP, 4 // ESP = 90
MOV ECX, (%RSP) // ECX -> 90..93

现在没有任何东西被覆盖,没有差距发生,每个人都很开心。

这当然假设堆栈向下增长,就像通常那样。如果堆栈向上,那么添加将在商店之后保持地址正确。

在x64模式下,它会更简单,因为值(据我所知)总是被推送为8字节块。

此外,其他架构可能允许不同类型的推送,因此在存储数据之前将指针移动到按钮上会导致最通用的操作。