【问题标题】:Is it okay to push registers purely for preservation for short periods of time?纯粹为了短期保存而推送寄存器可以吗?
【发布时间】:2015-03-19 21:52:26
【问题描述】:

我已经学习 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

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

push rdx
mov rax,2
mov rbx,10

mul rbx

pop rdx

基本上,我在 mul 指令之前将寄存器保留在堆栈上,然后将其弹出(因为我不关心 rdx 中的值。我想要它是我想要的)。

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

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

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

【问题讨论】:

  • n x n 乘法的结果为 2n。这种推送/弹出是告诉机器代码是由人类而不是机器编写的方式:) 它看起来像是一种解决问题的无辜方式,但事实并非如此。堆栈内存访问有 3 个周期的延迟。机器会寻找一种方法将值存储在另一个寄存器中,例如 r9-r15 或 xmm0-15。或者考虑使用 SIMD 指令的可能性,这样你就可以同时得到 4 个乘法:)
  • 是的,这就是我的小脑袋现在意识到的 :) 我试图远离额外的寄存器(r9 等),这样我就可以轻松地将它移植到 32 位有时在路上。我发现这可能不是一个好主意有多种原因 - 所以我将重新访问我的寄存器用法。谢谢:)

标签: assembly 64-bit nasm x86-64


【解决方案1】:

有没有什么地方可以完全涵盖这些指令在 64 位上下文中的作用?我似乎找不到真正用简单的英语告诉我 mul 指令后 rdx 寄存器发生了什么的参考

Intel's manual 说得很清楚:

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

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

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

【讨论】:

  • 谢谢。这听起来可能很愚蠢,但我昨晚找不到手册的相关部分:/感谢您的解释。有时您只需要有人为您指明明显的方向!
【解决方案2】:

在这种情况下,推送/弹出是完全合理的。

为什么不使用imul rax,rbx 甚至imul rax,10?这些根本不会混淆 RDX。

【讨论】:

  • lea rax, [rax + rax * 4] \ shl rax
  • 有趣 - 我没有意识到我能做到这一点。我也会玩这个。
【解决方案3】:

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

不过,在这种情况下,这并不是真正必要的,因为您可以在不影响rdx 的情况下进行乘法运算。

【讨论】:

  • 感谢 Windows 的提及 - 我什至没有考虑过!看来我还有很多东西要学:)
猜你喜欢
  • 2019-12-24
  • 2020-07-24
  • 2021-08-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-04-08
相关资源
最近更新 更多