汇编语言-从ecx中减去edx并将结果放置在ebx中

时间:2018-07-04 21:20:33

标签: assembly x86 instructions

在不更改任何其他寄存器的情况下如何做到这一点(又使ecxedx与以前一样)?

在C ++中,应该是这样:

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

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

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

2 个答案:

答案 0 :(得分:4)

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

# 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保存在堆栈中,然后在ECX中生成C - D结果而不是新寄存器。

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

编译器通常非常擅长寄存器分配,但是它们的代码可能很难阅读,因为它们甚至没有尝试与寄存器使用保持一致。对于非破坏性操作,他们通常会无缘无故地将结果放入新的寄存器中。尽管如此,编译器输出通常仍是优化的良好起点。 (编写一个微型函数来执行操作,并查看其编译方式。或者使用args函数而不是常量作为输入在C语言中编写整个内容,然后进行编译。)


x86具有一些用于其他操作(非submost notably LEA)的复制和操作指令。

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

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


immediate-operand form of imul也是3个操作数,用于不能使用1个或2个LEA的乘法器:

imul   ebx,  ecx,  0x01010101     ;  ebx = C repeated 4 times, if it was < 256

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


ISA扩展(例如BMI1和BMI2)已添加了一些新的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

vs。 AVX:

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

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

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

答案 1 :(得分:0)

您始终可以使用堆栈来保存寄存器:

Super.__init__()