Assembly 如何添加两个数字,每个数字有12个字节?

Assembly 如何添加两个数字,每个数字有12个字节?,assembly,x86,bigint,carryflag,extended-precision,Assembly,X86,Bigint,Carryflag,Extended Precision,我想添加两个有12个字节的数字,并将结果存储在一个16字节的变量中。我如何才能做到这一点 section .data big_num1 dd 0x11111111, 0x22222222, 0x33333333 big_num2 dd 0xffffffff, 0x22222222, 0x33333333 section .bss result_4word resd 4 我想我可以把数字1的前4个字节和数字2的前4个字节相加,以此类推。。但是我不知道如何在我的结果变

我想添加两个有12个字节的数字,并将结果存储在一个16字节的变量中。我如何才能做到这一点

section .data
    big_num1 dd 0x11111111, 0x22222222, 0x33333333
    big_num2 dd 0xffffffff, 0x22222222, 0x33333333
section .bss   
    result_4word resd 4
我想我可以把数字1的前4个字节和数字2的前4个字节相加,以此类推。。但是我不知道如何在我的结果变量中连接结果。 如果需要的话,我该如何搬运? 这是正确的解决方案吗

xor eax, eax
xor ebx, ebx
mov ecx, 3
loop1:
mov eax, dword[big_num1+4*(ecx-1)]
mov ebx, dword[big_num2+4*(ecx-1)]
mov [result_4word+4*(ecx-1)], eax
adc [result_4word+4*(ecx-1)], ebx
loop loop1
这里定义了什么数字? 因为是一种小端结构,所以数字的最低部分存储在最低地址的内存中。对于big_num1,第一个定义的dword(值为0x11111111)位于最低地址,因此是数字的最低部分。在正常的数字表示法中,这是右手边的数字

big_num1 == 0x333333332222222211111111
big_num2 == 0x3333333322222222FFFFFFFF
添加大数字 从右到左添加相应的数字,就像每个人在学校学到的一样

在这些数字的十六进制表示中,有24个数字需要考虑。然而,由于体系结构是32位的,我们可以很好地制作3组8位数字

对于第一组,我们只需使用
添加

mov     eax, [big_num1]           ;   0x11111111
add     eax, [big_num2]           ; + 0xFFFFFFFF <-- This produces a carry
mov     [result_4dword], eax      ;   0x00000000
对于第三组,我们使用
ADC
从上一次添加中提取可能的进位:

mov     eax, [big_num1 + 4]       ;   0x22222222
adc     eax, [big_num2 + 4]       ; + 0x22222222 + CF=1  <-- No new carry
mov     [result_4dword + 4], eax  ;   0x44444445
mov     eax, [big_num1 + 8]       ;   0x33333333
adc     eax, [big_num2 + 8]       ; + 0x33333333 + CF=0  <-- No new carry
mov     [result_4dword + 8], eax  ;   0x66666666
现在我们可以编写一个包含3次迭代的循环,但是我们必须小心不要无意中更改进位标志。这就是为什么我使用
LEA
而不是
ADD
来推进偏移量
DEC
也是一条不会破坏进位标志的指令。我更喜欢DEC ECX的组合,因为它比循环更好

    mov     ecx, 3
    xor     ebx, ebx              ; This additionally clears the carry flag
Again:
    mov     eax, [big_num1 + ebx]
    adc     eax, [big_num2 + ebx] ; Can produce a new carry flag
    mov     [result_4dword + ebx], eax
    lea     ebx, [ebx + 4]        ; This does not clobber the carry flag
    dec     ecx                   ; This does not clobber the carry flag
    jnz     Again
如果在这3个加法之后仍然有一个进位,您必须在result_4word的第4个双字中写一个1,否则您必须在这里写一个0。因为result_4dword在.bss部分,所以您不应该指望任何预设值,比如零

    setc    cl
    mov     [result_4dword + ebx], ecx  ; ECX=[0,1]

请注意,我已将result_4word更改为result_4dword。更有意义…

小学:

   1234
+  5678
========
开始填写

     1
   1234
+  5678
========
      2
4+8=12,所以2代表1

在电脑里你会 加上a=4+8 adc b=3+7 adc c=2+6 adc d=1+5

然后dcba包含您的结果,它可以扩展到您想要的范围。d、 根据指令集的不同,c、b、a可以是8位、16位、32位或64位。大多数都有add和adc,如果它们有标志,那些没有标志,那么你可以用各种方式合成它们,一点也不困难。。。(使用32位寄存器/内存将操作数分解为16位量。现在32位加法第16位是您的执行,将其添加到下一个16位块中,需要一些移位和掩蔽,但所有操作都是一样的,因为您可能有adc,所以您不需要执行任何操作,只需执行简单的加法、adc、adc、adc…直到完成

如果在开始之前清除该标志,则可以在循环中使用adc

现在,如果你的变量没有和处理器中的加法器对齐,那么你必须以某种方式合成它

小学数学对于同样的问题,现在你必须分开做专栏

  4
+ 8
====
 12
您必须手动屏蔽并移动结果(12>>1)%9=1,以10为基数

  1
  3
+ 7
====
 11
然后

  1
  2
+ 6
====
  9
这个带零

  0
  1
+ 5
====
  6

阅读指令集参考中的
adc
条目。您无需验证任何内容。
adc
将为您完成此操作。使用
Add
添加最低的DWORD,其余部分使用
adc
。完成。是的,但这是
adc
的明确目的,因此您不必手动完成。它确实有效,但您只有最后加法的进位,不存储在任何地方。操作数和结果的大小仅受内存限制。如果要将100万位数字添加到另一个100万位数字中,非常简单。第一个字节/字/dword,无论您选择使用什么,都可以添加,其余的使用adc。是的,
dec
/
jnz
是在Sandybridge系列上,部分标志暂停不是问题。在早期的Intel上,如Nehalem和Core 2,您可能希望保存/恢复标志或可能使用LEA/JECXZ/JMP循环(但这有点糟糕,所以您需要展开以隐藏成本)除了最近的AMD之外,
loop
在所有方面都很慢,这真是太糟糕了,因为它在其他方面非常适合ADC环路
  1
  2
+ 6
====
  9
  0
  1
+ 5
====
  6