Как я могу добавить два числа по 12 байт каждый?

Я хочу добавить два числа, которые имеют 12 байтов и сохранить результат в 16-байтовой переменной. Как я могу это сделать?

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

Я думаю, что я могу добавить первые 4 байта из числа 1 с другими первыми 4 байтами из числа 2 и так далее... но я не знаю, как объединить результаты в моей переменной результата. Как мне сделать переноску, если она нужна? Является ли это решение правильным?

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

2 ответа

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

Какие числа определены здесь?

Поскольку x86 - это архитектура с прямым порядком байтов, младшая часть числа хранится в памяти по самым низким адресам. Для big_num1 первое определенное слово (значение 0x11111111) находится по самому низкому адресу и, следовательно, является самой низкой частью числа. В нормальном представлении чисел это то, что идет с правой стороны.

big_num1 == 0x333333332222222211111111
big_num2 == 0x3333333322222222FFFFFFFF

Добавление больших чисел

Вы добавляете соответствующие цифры справа налево, как все учили в школе.

В шестнадцатеричном представлении этих чисел есть 24 цифры для рассмотрения. Однако, поскольку архитектура 32-битная, мы можем сделать 3 группы по 8 цифр.

Для 1-й группы мы просто используем ADD:

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

Для 2-й группы мы используем 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 для 1-й группы, если мы заранее ясно очистим флаг переноса:

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 ECXJNZ ... потому что это лучше чем 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-х дополнений все еще есть перенос набора, вам нужно будет написать 1 в 4-м двойном слове result_4dword, иначе вам придется написать 0 здесь. Поскольку result_4dword находится в разделе.bss, вы не должны рассчитывать на любое заданное значение, например ноль!

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

Обратите внимание, что я изменил result_4word на слово result_4 d. Имеет больше смысла...

Начальная школа:

   1234
+  5678
========

начать заполнять его

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

4+8 = 12, поэтому 2 несут один.

в компьютере вы должны добавить a = 4 + 8 АЦП b = 3 + 7 АЦП c = 2 + 6 АЦП d = 1 + 5

тогда dcba содержит ваш результат, он масштабируется так, как вы хотите. d, c, b, a могут быть 8-битными, 16-битными, 32-битными или 64-битными в зависимости от набора команд. у большинства есть add и adc, если у них есть флаги, те, у которых нет флагов, тогда вы можете синтезировать их различными способами, которые совсем не сложны... (разбейте ваши операнды на 16-битные величины, используя 32-битные регистры / память, делайте 32 bit add now bit 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
Другие вопросы по тегам