Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/assembly/6.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Assembly 汇编语言-从ecx中减去edx,并将结果放入ebx_Assembly_X86_Instructions - Fatal编程技术网

Assembly 汇编语言-从ecx中减去edx,并将结果放入ebx

Assembly 汇编语言-从ecx中减去edx,并将结果放入ebx,assembly,x86,instructions,Assembly,X86,Instructions,我如何做到这一点而不改变任何其他寄存器,使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 始终可以使用堆栈保留寄存器: push ecx push edx mov ecx, 1 mov edx, 3 sub ecx, edx

我如何做到这一点而不改变任何其他寄存器,使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

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

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

对于销毁其目标的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有一些用于其他操作的复制和操作指令,而不是子操作

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

也是3操作数,用于1或2 LEAs无法使用的乘法器:

imul   ebx,  ecx,  0x01010101     ;  ebx = cl repeated 4 times, if upper bytes were zero
与大多数直接操作数指令不同,imul没有。因此,它有空间对寄存器目的地和reg/mem源进行编码,因为它专用于整个操作码字节

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

但它们不是普遍可用的,只有Haswell和later以及Ryzen。而奔腾/赛扬版本的Haswell/Skylake仍在销售中没有它们,这进一步推迟了它们成为基线的时间。谢谢,英特尔

当然,对于矢量指令,AVX提供了所有SSE指令的非破坏性版本

或者一个不太明显的用例

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作为合并目标,以避免错误的依赖关系,并使高64位为零,您尝试过做什么?从ecx中减去edx,然后使ebx等于ecx,但我必须更改ecx的值。您是否考虑过在直接在ebx上执行sub之前,先将ecx的值复制到ebx中?这实际上是大多数C++编译器所做的,因为它没有LEA,但减去了Addit,而不是添加,如果你需要的话,你需要其他的Debug Suffv Ebx,ECX在子EBX之前,EDX是最理想的。您可以通过许多其他方式实现相同的功能,例如neg edx lea ebx、[ecx+edx]neg edx,或在答案中使用push/pop like,但所有这些变体都是人为地复杂,以避免最简单的一个,并带来额外的性能损失edx@PandaAssassin:您的问题是希望保持ECX和EDX与beofre相同。此代码中的ECX将是推ECX之前ECX中的任何内容。“我想你的问题可能是错的?”迈克尔佩奇:我现在明白了。我只是想把ecx保留为3。对我来说,在我移动ecx和EDX之后,我只会推一下。这是正确的,但太复杂了。我很想否决这一点,因为大量的push/pop会让你的代码变得很难阅读。我的意思是,鼓励人们在不必要的时候使用push/pop会导致无法阅读的初学者代码,这些代码会保存每个函数周围的所有寄存器,甚至单个函数内部的寄存器。我不是说2是一船货。BTW,OP的C++源将修改EDX和ECX,所以如果你必须在推/ POP内运行MOV RG,IMM,那么你最好把它优化为MOV EBX,1-3。作为记录,我不是这个答案的反对者。在我说我很想这么做之后,其他人就投了反对票。你可能以为那是我,所以非常生气。
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
vxorps    xmm1,  xmm1,xmm1   ; xmm1 = all-zero

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