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
Advertisement
Answer
- 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