如何在汇编中添加和减去大变量?

时间:2016-04-28 19:26:52

标签: assembly

所以这应该是一个非常容易回答的问题。

假设我有两个非常大的变量 a b ,我想从 a中减去 b 即可。假设每个变量都是30个字。我不能只使用 sub 指导员吗?我被告知默认为 sub.w ,并且只会从 a 的第一个单词中减去 b 的第一个单词。

那我该怎么做呢?

1 个答案:

答案 0 :(得分:2)

要执行多字减法,您可以从低位字开始,然后从两个变量中减去相应的字。使用sbb指令处理借用,并仅在第1次减法时使用sub

mov  dx, [ebx]     ;First word of b
sub  [eax], dx     ;Subtract from 1st word of a
mov  dx, [ebx+2]   ;Second word of b
sbb  [eax+2], dx   ;Subtract from 2nd word of a
mov  dx, [ebx+4]   ;Third word of b
sbb  [eax+4], dx   ;Subtract from 3rd word of a
...
mov  dx, [ebx+58]  ;Thirtieth word of b
sbb  [eax+58], dx  ;Subtract from 30th word of a

更实用的解决方案是使用循环:

mov  ecx, 30
xor  esi, esi      ;This clears the CF, needed for the very first SBB
Again:
mov  dx, [ebx+esi]
sbb  [eax+esi], dx
lea  esi, [esi+2]
loop Again         ; loop without clobbering CF.

better ways to write fast adc / sbb loops,但最佳选择因微体系结构而异。减少slow loop instruction开销的一种简单方法是展开一点。

mov  ecx, 15
xor  esi, esi      ;This clears the CF, needed for the very first SBB
Again:
mov  dx, [ebx+esi]
sbb  [eax+esi], dx
mov  dx, [ebx+esi+2]
sbb  [eax+esi+2], dx
lea  esi, [esi+4]
loop Again

优化此任务的下一步是停止使用16位寄存器DX,而是使用更大的EDX寄存器。这将使完全展开版本中的指令数量减半,或者使循环版本中的迭代次数减半。我们可以这样做,因为“30个字长的变量”可以被认为是“15个双字长的变量”。

这是完全展开的版本:

mov  edx, [ebx]    ;First dword of b
sub  [eax], edx    ;Subtract from 1st dword of a
mov  edx, [ebx+4]  ;Second dword of b
sbb  [eax+4], edx  ;Subtract from 2nd dword of a
mov  edx, [ebx+8]  ;Third dword of b
sbb  [eax+8], edx  ;Subtract from 3rd dword of a
...
mov  edx, [ebx+56] ;Fifteenth dword of b
sbb  [eax+56], edx ;Subtract from 15th dword of a

和部分展开的循环版本:

mov  ecx, 5
clc                ;This clears the CF, needed for the very first SBB
Again:
mov  edx, [ebx]    ; <1>
sbb  [eax], edx
mov  edx, [ebx+4]  ; <2>
sbb  [eax+4], edx
mov  edx, [ebx+8]  ; <3>
sbb  [eax+8], edx
lea  ebx, [ebx+12]
lea  eax, [eax+12]
loop Again

显然在x86-64上类似地使用RDX会进一步改进这个代码。请注意,30个单词对应7个qwords和1个双字。