首页 > 解决方案 > 汇编语言 - 从 ecx 中减去 edx 并将结果放入 ebx

问题描述

我将如何在不更改任何其他寄存器的情况下做到这一点(又名保持ecx&edx与以前相同)?

在 C++ 中,它会是这样的:

int ecx = 3;
int edx = 1;
int ebx = ecx - edx;

到目前为止,我已经这样做了:

mov ecx, 1
mov edx, 3
sub ecx, edx
mov ebx, ecx

标签: assemblyx86instructions

解决方案


使用破坏其目标的 x86 样式 2 操作数指令,您始终可以模拟非破坏性 3 操作数指令,mov将一个操作数复制到目标,然后在该目标上运行破坏性指令。

# with ecx and edx holding your inputs (which I'm calling C and D).

mov  ebx, ecx      ; ebx = C
sub  ebx, edx      ; ebx = C - D

这是您在这种情况下可以做的最好的事情,您不需要破坏 ECX 和 EDX 中的值。

如果您的可用寄存器不足,将 ECX 保存在堆栈中,然后C - D在 ECX 中生成结果而不是新寄存器可能是一个不错的选择。

通常,您可以在整个函数中为相同的变量继续使用相同的寄存器,但这不是必需的,有时也不是最佳的。使用评论来跟踪事情。

编译器通常非常擅长寄存器分配,但它们的代码可能难以阅读,因为它们甚至不尝试与寄存器使用保持一致。对于非破坏性操作,他们通常会无缘无故地将结果放入新的寄存器中。尽管如此,编译器输出通常是优化的良好起点。(写一个做某事的小函数,看看它是如何编译的。或者用函数 args 而不是常量作为输入,用 C 语言编写你的整个东西,然后编译它。)


subx86 对其他操作(不是)有一些复制和操作指令,最值得注意的是 LEA

lea  ebx, [ecx + ecx*4]     ; ebx = C * 5
lea  ebx, [ecx + ebx - 2]   ; ebx = C + D - 2

x86 寻址模式可以添加或减去常量,但只能左移和添加寄存器。


立即操作数形式imul也是 3 操作数,用于使用 1 或 2 个 LEA 无法实现的乘法器:

imul   ebx,  ecx,  0x01010101     ;  ebx = cl repeated 4 times, if upper bytes were zero

与大多数立即操作数指令不同,imul它不会将 ModRM 字节中的字段作为额外的操作码位重载/r。所以它有空间来编码一个寄存器目标和一个 reg/mem 源,因为186专用一个完整的操作码字节给它。


像 BMI1 和 BMI2 这样的ISA 扩展添加了一些新的 3 操作数整数指令,比如ANDNSHRX

andn   ebx,  ecx, edx             ; ebx = (~C) & D   ; BMI1

shrx   ebx,  edx, ecx             ; ebx = D >> C     ; BMI2

但它们并不是普遍可用的,只有 Haswell 及更高版本,以及 Ryzen。(并且 Haswell/Skylake 的 Pentium/Celeron 版本仍然在没有它们的情况下出售,进一步延迟了它们成为基准的时间点。谢谢,英特尔。)

当然对于向量指令,AVX 提供了所有 SSE 指令的无损版本

movaps    xmm2, xmm0         ; copy a whole register
subsd     xmm2, xmm1         ; scalar double-precision FP subtract: xmm0-xmm1

vsubsd    xmm3, xmm0, xmm1

或不太明显的用例

xorps     xmm0, xmm0    ; zero the register and break any false dependencies
cvtsi2sd  xmm0, eax     ; convert to double-precision FP, with the upper element = 0

xorps     xmm1, xmm1
cvtsi2sd  xmm1, edx

与 AVX:

vxorps    xmm1,  xmm1,xmm1   ; xmm1 = all-zero

vcvtsi2sd  xmm0, xmm1, eax
vcvtsi2sd  xmm1, xmm1, edx

这将重用相同的归零 reg 作为合并目标,以避免错误的依赖关系(并且使 128 位寄存器的高 64 位为零)。


推荐阅读