为什么我们有像push和pop这样的命令?
根据我的理解pop
和push
基本上与执行(mov
然后add
)和(sub
然后{{1} })分别在mov
上。
例如不会:
esp
相当于:
pushl %eax
如果堆栈访问不是subl $4, %esp
movl %eax, (%esp-4)
,我还在学习汇编 请更正我
我能看到的唯一真正的好处是,如果同时进行两种操作都会带来一些好处;但我不明白它是怎么回事。
答案 0 :(得分:8)
但是,也没有理由进行CALL
指令。毕竟,您可以使用以下方式模拟通话:
sub esp,4
mov [esp-4], offset return_address
jmp myproc
也不需要RET
指令,因为你可以用以下方法模拟它:
mov eax,[esp]
add esp,4
jmp [eax]
如果你看起来足够努力,你会发现许多可以通过组合其他指令来模拟的指令。有什么意义?
这些类型问题的答案源于x86处理器系列的悠久历史,以及之前的处理器。设计人员研究了程序员如何使用处理器并创建了一个在执行速度和内存使用方面都很有效的指令集。
在70年代后期,64千字节的内存很多,RAM也慢得多。每个指令字节都很珍贵,并且从内存中获取指令会产生大量开销。指令获取比执行花费更长时间并不罕见。因此,通过尽可能少的指令字节对事物进行编码,可以获得巨大的性能提升。
与CPU时钟速度相比,RAM仍然非常慢,因此通过尽可能少的指令字节进行编码仍然可以获得增益。确实,大型CPU缓存我们有很多帮助,分支预测和预取逻辑也是如此,但从RAM传输到CPU缓存的每个字节仍然很昂贵。用指令编码节俭是值得的。关于调用程序:
在汇编语言中调用过程的标准方法是推送参数,然后call
过程。例如,这会传递两个双字值:
push eax
push ebx
call proc ; pushes the return address and jumps to proc
...
proc:
; at this point, [esp] contains the return address
ret
指令将返回地址弹出到指令指针中。
当然,有人必须清理堆栈。调用者可以通过递增堆栈指针来清理堆栈。或者被调用的过程可以使用ret 8
来清理堆栈,这将弹出返回地址并递增堆栈指针。
有关调用约定的详细信息,请参阅http://www.delorie.com/djgpp/doc/ug/asm/calling.html。
答案 1 :(得分:2)
好。如果您有两条指令,那么它们可能会占用更多空间。这需要cpu传输更多数据。这需要更多时间。两个单独的指令通常还需要更多的cpu资源。即使cpu并行化它们,还有更多的工作来获取器,解码器...... 如果您尝试删除所有但绝对必要的说明,最终会使用图灵机。终极风险,但在实践中不是很有效。
答案 2 :(得分:1)
1个操作码> 2个操作码,至少在您尝试降低CPU使用率时。