如何将两个数字各加12个字节?

时间:2019-01-30 16:08:36

标签: assembly x86 bigint carryflag extended-precision

我想添加两个具有12个字节的数字,并将结果存储在16个字节的var中。我该怎么办?

$('#mylink').off('click');

我想我可以将数字1的前4个字节与数字2的其他前4个字节相加,依此类推..但我不知道如何在结果变量中串联结果。 如果需要,该如何携带? 此解决方案正确吗?

section .data
    big_num1 dd 0x11111111, 0x22222222, 0x33333333
    big_num2 dd 0xffffffff, 0x22222222, 0x33333333
section .bss   
    result_4word resd 4

2 个答案:

答案 0 :(得分:2)

big_num1 dd 0x11111111, 0x22222222, 0x33333333
big_num2 dd 0xffffffff, 0x22222222, 0x33333333

此处定义了哪些数字?

由于是一种低端字节序的体系结构,因此数字的最低部分存储在内存中的最低地址处。对于 big_num1 ,第一个定义的dword(值为0x11111111)位于最低地址,因此是数字的最低部分。在普通数字表示中,这是右侧的内容。

big_num1 == 0x333333332222222211111111
big_num2 == 0x3333333322222222FFFFFFFF

添加大数字

您添加从右到左的相应数字,就像每个人在学校学到的一样。

在这些数字的十六进制表示形式中,有24位数字需要考虑。但是,由于该体系结构是32位的,因此我们可以很好地将3组8位数字组合在一起。

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

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

对于第3组,我们使用ADC从前面的添加项中提取可能的进位:

mov     eax, [big_num1 + 8]       ;   0x33333333
adc     eax, [big_num2 + 8]       ; + 0x33333333 + CF=0  <-- No new carry
mov     [result_4dword + 8], eax  ;   0x66666666

将其变成循环

这里的关键是,如果我们事先明确清除了进位标记,我们也可以将ADC用于第一组:

clc
mov     eax, [big_num1]           ;   0x11111111
adc     eax, [big_num2]           ; + 0xFFFFFFFF + CF=0 <-- This produces a carry
mov     [result_4dword], eax      ;   0x00000000

现在我们可以编写一个包含3次迭代的循环,但是我们有请注意不要意外更改进位标志。这就是为什么我使用LEA而不是ADD来推进偏移量的原因。 DEC也是不会破坏进位标志的指令。我更喜欢组合DEC ECX JNZ ...,因为它比LOOP ...更好:

    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_4dword 的第4个双字中写一个 1 ,否则就必须写此处为 0 。因为 result_4dword 位于.bss部分中,所以您不应指望任何预设值(例如零!)!

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

请注意,我已将 result_4word 更改为 result_4 d word 。更有道理...

答案 1 :(得分:1)

小学:

   1234
+  5678
========

开始填写

     1
   1234
+  5678
========
      2

4 + 8 = 12,所以2个携带一个。

在计算机上,您会 加一个= 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,没有标志的则具有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