Как я могу добавить два числа по 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 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-х дополнений все еще есть перенос набора, вам нужно будет написать 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