5

为什么我们有 push 和 pop 之类的命令?

据我了解poppush基本上与分别执行 ( movthen add) 和 ( subthen mov)esp相同。


例如不会:

pushl %eax

相当于:

subl $4, %esp
movl %eax, (%esp-4)

如果堆栈访问不是(%esp-4),请纠正我,我还在学习组装


我能看到的唯一真正的好处是,如果同时进行这两项操作会提供一些优势;但是我不明白它怎么可能。

4

3 回答 3

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 KB 是很多 RAM,而 RAM 则要慢得多。每个指令字节都是宝贵的,仅仅从内存中获取一条指令就有大量的开销。取指令花费的时间比执行时间长的情况并不少见。因此,通过尽可能少的指令字节对事物进行编码,可以获得巨大的性能提升。

与 CPU 时钟速度相比,RAM 仍然非常慢,因此通过尽可能少的指令字节编码仍然可以获得收益。确实,我们拥有的大型 CPU 缓存非常有用,分支预测和预取逻辑也有很大帮助,但是从 RAM 传输到 CPU 缓存的每个字节仍然很昂贵。节省指令编码是值得的。

关于调用程序:

汇编语言调用过程的标准方法是先传入参数,然后再call传入过程。例如,这会传递两个 dword 值:

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

于 2012-04-14T20:09:53.197 回答
2

好。如果您有两条指令,那么它们可能会占用更多空间。这需要cpu传输更多数据。这需要更多时间。两条单独的指令通常也需要更多的 CPU 资源。即使 cpu 将它们并行化,提取器、解码器还有更多工作......如果您尝试删除所有但绝对必要的指令,您最终会得到图灵机。终极风险,但在实践中不是很有效。

于 2012-04-14T21:50:28.940 回答
1

1 个操作码 > 2 个操作码,至少在您尝试降低 CPU 使用率时。

于 2012-04-14T17:26:57.350 回答