pop或者add esp, 4?有什么区别?

12

我看到这个问题,但在其中没有找到我的答案。

那么,为什么我更喜欢使用add esp, 4add esp, 8而不是使用pop一次或两次?是否完全没有差别(性能、安全等),还是只是个人选择的问题?


7
这取决于你是否有一个可用的寄存器来进行 pop 操作。如果没有,请使用 add esp - Paul R
哈哈,这是一个很好的观点,我还没有考虑过这个。 - Kiril Kirov
相关:为什么这个函数在第一次操作时将RAX推入堆栈? - 在现代CPU上,使用一个虚拟的pop到一个无用寄存器中可能更有效率,因为负载端口通常不会饱和,并且对于add操作可能需要一个堆栈同步uop。请参见我在链接问题上的答案。 - Peter Cordes
3个回答

21

pop指令也会执行add esp, 4操作,它只是在操作之前将栈顶的内容保存到它的操作数中。如果你需要栈上的内容,pop指令可能比使用mov wherever, [esp]; add esp, 4指令更快,但如果你只需要清空栈,add esp, 4指令就足够了。


2
一般来说,pop指令不等同于add esp, N指令。 pop用于从堆栈中移除数据并将其存储在某个寄存器中;它也不关心堆栈增长的方向,尽管通常这不是一个问题。手动添加或减去堆栈指针esp无法保存已经移除的数据到寄存器中。假设您不需要对从堆栈中移除的数据进行任何操作,这样做可能更有效率。

POP 不仅可以将堆栈中的值存储到寄存器中,还可以存储到内存位置中。 - Maxim Masiutin

1

pop从内存(由ss:[esp]指向的堆栈)加载数据到通用寄存器、内存位置或段寄存器。无论如何,pop使用处理器的load单元访问堆栈,而add esp不使用load单元。自Pentium Pro以来,处理器具有乱序执行功能Out-of-order execution,即如果这些指令可以同时执行,则在一个周期内执行尽可能多的指令,并且必要时重新排列指令顺序以充分利用单元。

由于大多数处理器只有两个load单元,如果您不需要来自堆栈的数据(即您只想跳过数据),最好使用add esp,因为它是一个仅寄存器操作,不使用load单元,因此您的处理器将能够在那个时间使用load单元进行其他操作。


1
如果先前使用ESP的操作是像“ret”或“push”这样的堆栈操作,而不是像“mov ecx,esp”这样的显式引用,则“add esp”可能需要CPU使用堆栈同步uop。 如果在此pop或add操作之后将有任何显式使用“esp”的操作,则无论如何都需要堆栈同步uop,否则您可能可以避免使用它。请参见为什么此函数将RAX作为第一个操作推送到堆栈中?了解现代编译器为什么只使用一个虚拟的push或pop(如果只需要一个) 。 - Peter Cordes

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接