I'm new to learning assembly language, and am trying to program a calculator where a user can input 2 numbers, and use either addition or subtraction and for the result to display. I have tried so many things, but can't seem to find where I've gone wrong! Any advice or solution would be greatly appreciated. Thank you in advance :)
section .data
welcome db 0dh, 0ah, 0dh, 0ah, "**Hey, welcome to this calculator!**", 0dh, 0ah
welcome_length equ $ - welcome
msg_prompt db "Add your calculation (e.g., 24 + 6): ", 0
msg_result db "Result: ", 0
msg_newline db 10, 0
invalid_operator db "Invalid input, please use + or - for operations", 0
section .bss
buffer resb 32
num1 resq 1 ; Number 1
num2 resq 1 ; Number 2
section .text
global _start
_start:
; Print the welcome message
mov rsi, welcome
mov rdx, welcome_length
mov rax, 1
mov rdi, 1
syscall
; Print the message prompt
mov rsi, msg_prompt
mov rdx, 37
mov rax, 1
mov rdi, 1
syscall
; Read the input
mov rsi, buffer
mov rdx, 32
mov rax, 0
mov rdi, 0
syscall
; Convert first number to an int
mov rsi, buffer
call parse_number
mov [num1], rax
; Move to the operator (adjusying rsi based on parsed length)
add rsi, rax
call skip_spaces
; Check the operator
movzx rbx, byte [rsi]
cmp rbx, '+'
je add_numbers
cmp rbx, '-'
je subtract_numbers
; Invalid operator - print error message
mov rsi, invalid_operator
mov rdx, 47
mov rax, 1
mov rdi, 1
syscall
jmp _exit
; Move to the 2nd
add_numbers:
inc rsi
call skip_spaces
call parse_number
mov [num2], rax
; Perform additiom
mov rax, [num1]
add rax, [num2]
call print_result
jmp _exit
; Move to the 2nd
subtract_numbers:
inc rsi
call skip_spaces
call parse_number
mov [num2], rax
; Perform subtraction
mov rax, [num1]
sub rax, [num2]
call print_result
jmp _exit
print_result:
; Printing the results
mov rsi, msg_result
mov rdx, 8
mov rax, 1
mov rdi, 1
syscall
; Converting results to a string
call print_number
ret
parse_number:
; Convering a string to a number
xor rax, rax
mov rcx, 0
parse_loop:
movzx rbx, byte [rsi]
test rbx, rbx
jz done_parsing
cmp rbx, '0'
jb done_parsing
cmp rbx, '9'
ja done_parsing
sub rbx, '0'
imul rax, rax, 10
add rax, rbx
inc rsi
inc rcx
jmp parse_loop
done_parsing:
mov rax, rcx
ret
print_number:
; Convert the number in rax to ASCII in buffer and display
mov rsi, buffer + 32
mov rcx, 10
add rsi, 1
mov byte [rsi], 0
; If the number is 0, handle it seperately
cmp rax, 0
je print_zero
print_loop:
xor rdx, rdx
div rcx
dec rsi
add dl, '0'
mov [rsi], dl
test rax, rax
jnz print_loop
jmp print_result_buffer
print_zero:
dec rsi
mov byte [rsi], '0'
jmp print_result_buffer
print_result_buffer:
; display result from buffer
mov rdx, buffer + 32
sub rdx, rsi
mov rax, 1
mov rdi, 1
syscall
ret
skip_spaces:
; skipping any spaces in the buffer
skip_space_loop:
movzx rbx, byte [rsi]
cmp rbx, ' '
jne skip_done
inc rsi
jmp skip_space_loop
skip_done:
ret
_exit:
; Exit the program
mov rax, 60
xor rdi, rdi
syscall
I've lost track of all the variations I've tried. The output does allow a user to put the equation, 3 + 2 for example, and Result: prints, but doesn't actually show the numerical calculation
First, the bugs:
done_parsing
overwrites the number parsed with the lengthprint_result
destroys the number before it can be printedprint_result_buffer
prints 1 less characters than needed(adjusying rsi based on parsed length)
is not needed because rsi
is automatically pointing where parsing stoppedbuffer
Next, the missed optimizations:
rip
relative addressingparse_number
does not need to count the lengthAn alternate version could look like:
default rel
section .data
welcome db 0dh, 0ah, 0dh, 0ah, "**Hey, welcome to this calculator!**", 0dh, 0ah
welcome_length equ $ - welcome
msg_prompt db "Add your calculation (e.g., 24 + 6): ", 0
msg_result db "Result: ", 0
msg_newline db 10, 0
invalid_operator db "Invalid input, please use + or - for operations", 0
section .bss
buffer resb 32
num1 resq 1 ; Number 1
num2 resq 1 ; Number 2
section .text
global _start
_start:
; Print the welcome message
lea rsi, [welcome]
mov edx, welcome_length
mov eax, 1
mov edi, 1
syscall
; Print the message prompt
lea rsi, [msg_prompt]
mov edx, 37
mov eax, 1
mov edi, 1
syscall
; Read the input
lea rsi, [buffer]
mov edx, 32
xor eax, eax
xor edi, edi
syscall
; Convert first number to an int
call parse_number
mov [num1], rax
; Move to the operator
call skip_spaces
; Check the operator
mov bl, [rsi]
inc rsi
call skip_spaces
call parse_number
mov [num2], rax
cmp bl, '+'
je add_numbers
cmp bl, '-'
je subtract_numbers
; Invalid operator - print error message
lea rsi, [invalid_operator]
mov edx, 47
mov eax, 1
mov edi, 1
syscall
jmp _exit
; Move to the 2nd
add_numbers:
; Perform additiom
mov rax, [num1]
add rax, [num2]
call print_result
jmp _exit
; Move to the 2nd
subtract_numbers:
; Perform subtraction
mov rax, [num1]
sub rax, [num2]
call print_result
jmp _exit
print_result:
push rax
; Printing the results
lea rsi, [msg_result]
mov edx, 8
mov eax, 1
mov edi, 1
syscall
; Converting results to a string
pop rax
jmp print_number
parse_number:
; Convering a string to a number
xor eax, eax
parse_loop:
movzx ecx, byte [rsi]
sub cl, '0'
cmp cl, '9'
ja done_parsing
imul rax, rax, 10
add rax, rcx
inc rsi
jmp parse_loop
done_parsing:
ret
print_number:
; Convert the number in rax to ASCII in buffer and display
lea rsi, [buffer + 32]
mov ecx, 10
print_loop:
xor edx, edx
div rcx
dec rsi
add dl, '0'
mov [rsi], dl
test rax, rax
jnz print_loop
print_result_buffer:
; display result from buffer
lea rdx, [buffer + 32]
sub rdx, rsi
mov eax, 1
mov edi, 1
syscall
ret
skip_spaces:
; skipping any spaces in the buffer
skip_space_loop:
cmp byte [rsi], ' '
jne skip_done
inc rsi
jmp skip_space_loop
skip_done:
ret
_exit:
; Exit the program
mov eax, 60
xor edi, edi
syscall