I'm very new to assembly and having difficulties in getting basic calculations to work with different length numbers.
So this is my adding code, that works with numbers that are 3 or less characters long. for as long as both are the same length. for example 123 123 works just fine and outputs 246. But 12 123 does not work and it outputs 253 as the answer. How would I be able to get this working with different length numbers?
sys_exit equ 1
sys_read equ 3
sys_write equ 4
stdin equ 0
stdout equ 1
section .data
newLine db 10
cquestion db 'Enter a number: ', 0xa
cqLen equ $ - cquestion
answer db 'Your answer is: '
aLen equ $ - answer
section .bss
number1 resb 4
number2 resb 4
number1Len resd 1
number2Len resd 1
answ resb 8
%macro write_string 2
mov eax, 4
mov ebx, 1
mov ecx, %1
mov edx, %2
int 0x80
%endmacro
section .text
global _start
_start:
write_string cquestion, cqLen
mov eax, sys_read
mov ebx, stdin
mov ecx, number1
mov edx, 4
int 0x80
mov [number1Len], eax
write_string cquestion, cqLen
mov eax, sys_read
mov ebx, stdin
mov ecx, number2
mov edx, 4
int 0x80
mov [number2Len], eax
write_string answer, aLen
clc
mov ecx, [number2Len] ;number of digits
dec ecx ;need to decrease one for some reason?
mov esi, ecx
dec esi ;pointing to the rightmost digit.
.add_loop:
mov al, [number1 esi]
adc al, [number2 esi]
aaa
pushf ; also no idea what this is here for
or al, 30h ; or this
popf ; and this...
mov [answ esi], al
dec esi
loop addition.add_loop
mov eax, sys_write
mov ebx, stdout
mov ecx, answ
mov edx, 8
int 0x80
mov eax, sys_write
mov ebx, stdout
mov ecx, newLine
mov edx, 1
int 0x80
mov [answ], DWORD 0
CodePudding user response:
- Your loop never does more than 3 iterations. If there's a final carry, you'll need an extra write to the destination.
- If the code needs to deal with different length inputs, then you can't use the same offset
ESI
to address corresponding digits from both numbers. - And neither can you use that same
ESI
to store the output since you could need one extra position to the left. - About
answ resb 8
, summing a couple of 3-digit numbers can at most produce a 4-digit sum.
Below is one of the many solutions to this question.
ECX=1
v
num1: 31 32 0A 00 31 32 30 30
num2: 31 32 33 0A 31 32 33 30
^
EDX=2
answ: 00 00 00 00 --> 30 31 33 35
^
EDI=3
mov ecx, [number1Len] ; Number of bytes (eg. 3)
sub ecx, 2 ; Offset to 'ones' digit
lea eax, [ecx 1] ; Offset to the newline
.more1:
mov byte [number1 eax], 30h
inc eax
test eax, 3
jnz .more1
mov edx, [number2Len] ; Number of bytes (eg. 4)
sub edx, 2 ; Offset to 'ones' digit
lea eax, [edx 1] ; Offset to the newline
.more2:
mov byte [number2 eax], 30h
inc eax
test eax, 3
jnz .more2
mov edi, 3 ; 4 iterations
clc
.add_loop:
movzx eax, byte [number1 ecx]
adc al, [number2 edx]
aaa
lahf ; Preserves CF gotten from `aaa`
or al, 30h ; Convert into character "0" to "9"
mov [answ edi], al
dec ecx
and ecx, 3 ; Wraparound in number1
dec edx
and edx, 3 ; Wraparound in number2
sahf ; Restores CF
dec edi
jns .add_loop
In the result in answ we can remove at most 3 leading zeroes. If the true result is 0, the 4th character in answ would have to remain.
mov edx, 4
mov ecx, answ
.del:
cmp byte [ecx], 30h
jne .ok
dec edx
inc ecx
cmp edx, 1
ja .del
.ok:
mov ebx, stdout
mov eax, sys_write
int 80h