纯粹为了短时间保存而推送寄存器可以吗?

Is it okay to push registers purely for preservation for short periods of time?

我已经学习 NASM 几个星期了。一切顺利 - 我现在一直专注于 64 位。

早些时候我注意到当我执行 mul 指令时 rdx 寄存器被弄乱了。

基本上,代码类似于:

; Code using RDX is up here

mov rax,2
mov rbx,10

mul rbx

; Code using RDX again is down here .. but the value is now zero

所以,显然黑索金与mul有关。为了解决这个问题,我将代码更改为:

push rdx
mov rax,2
mov rbx,10

mul rbx

pop rdx

基本上,我在 mul 指令之前将寄存器保存在堆栈中...然后将其弹出(因为我不关心 [=12] 中的值=] .. 我希望它成为我想要的样子)。

我的问题是:这样做可以吗?常见吗?很久没做这个了。。感觉有点奇怪。

我可以改为使用局部变量而不是寄存器来进行某些计算..这可能会解决问题而无需在这么短的时间内将其推入堆栈..但问题仍然存在.

额外问题:是否有某个地方完全涵盖了这些指令在 64 位上下文中的作用?我似乎找不到可以用简单的英语实际告诉我在 mul 指令之后 rdx 寄存器发生了什么的参考资料。

Is there somewhere that has full coverage of what these instructions do in a 64-bit context? I can't seem to find a reference that actually tells me in plain English what is happening to the rdx register after the mul instruction

Intel's manual 说得很清楚了:

MUL r/m64   Unsigned multiply (RDX:RAX ← RAX ∗ r/m64).

也就是说,RDX 将保留乘积的最高 64 位。

至于你的主要问题;如果可以的话,使用不同的寄存器。如果不能,则需要以某种方式备份 RDX 的值,使用堆栈是一种简单的方法。

Pushing/popping 在这种情况下是完全合理的。

为什么不使用 imul rax,rbx 甚至 imul rax,10?这些 完全不会与 RDX 混淆

并不总是好的。例如在 win64 上,不在 prolog 或 epilog 中的随机 push 和 pops 失败展开,如果在堆栈指针恢复正常之前发生异常,事情就会变得非常错误。

虽然在这种情况下并不是真的有必要,因为您可以相乘而不影响 rdx