2

我想添加两个具有 12 字节的数字并将结果存储在 16 字节的 var 中。我怎样才能做到这一点?

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
4

2 回答 2

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

这里定义了哪些数字?

因为是 little-endian 架构,所以数字的最低部分存储在内存中的最低地址。对于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 个 dword 中写入1,否则您必须在此处写入0。因为result_4dword在 .bss 部分,所以你不应该指望任何像零这样的预设值!

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

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

于 2019-01-31T15:29:36.650 回答
2

小学:

   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

并且您必须手动屏蔽并移动以 10 为底的结果 (12>>1) % 9 = 1。

  1
  3
+ 7
====
 11

然后

  1
  2
+ 6
====
  9

这个带零

  0
  1
+ 5
====
  6
于 2019-01-31T15:46:05.210 回答