I'm taking in two numbers as strings in assembly, then I'm converting them to integers, adding them, converting the result to a string, then printing it to the terminal. The main issue I have is that I'll be able to enter the two numbers, but after entering them no result is displayed.
.global _start # Declare the global entry point
.intel_syntax noprefix # Use Intel assembly syntax without prefixes
.section .bss # Reserve uninitialized space for buffers
buffer1: .space 20
buffer2: .space 20
result_buffer: .space 20
.section .text
_start:
# Read the first number
mov rax, 0 # sys_read
mov rdi, 0 # File descriptor: stdin
lea rsi, [buffer1]
mov rdx, 20 # Max bytes to read
syscall
mov byte ptr [rsi + rax], 0 # null terminate the input buffer
lea rsi, [buffer1]
call string_to_int
mov r8, rax # Store the first integer in r8
# Read the second number
mov rax, 0 # sys_read
mov rdi, 0 # File descriptor: stdin
lea rsi, [buffer2]
mov rdx, 20 # Max bytes to read
syscall
mov byte ptr [rsi + rax], 0
lea rsi, [buffer2] # Use buffer2 for the second input
call string_to_int
mov r9, rax # Store the second integer in r9
add r8, r9 # r8 = r8 + r9
# Convert the result back to a string
mov rax, r8 # Move the result into rax
lea rsi, [result_buffer + 19] # Point to the end of result_buffer
call int_to_string
# Calculate the string length (RCX holds the number of digits)
mov rdx, rcx
# Write the result
mov rax, 1 # sys_write
mov rdi, 1 # File descriptor: stdout
lea rsi, [result_buffer] # Address of result_buffer
mov rdx, rcx # number of digits in result
syscall # Perform system call
# Exit
mov rax, 60 # sys_exit
xor rdi, rdi # Exit code: 0
syscall
# Subroutine: string_to_int
# Converts a null-terminated string to an integer
# Input: RSI points to the string
# Output: RAX contains the integer value
string_to_int:
xor rax, rax # Clear rax (result)
xor rcx, rcx # Clear rcx (multiplier, initially 0)
convert_loop:
movzx rdx, byte ptr [rsi] # Load byte from the string
cmp rdx, 10 # Check for newline (ASCII '\n')
je convert_done # Exit loop on newline
sub rdx, '0' # Convert ASCII to digit (0-9)
imul rax, rax, 10 # Multiply result by 10
add rax, rdx # Add the current digit to the result
inc rsi # Move to the next character
jmp convert_loop
convert_done:
ret
# Subroutine: int_to_string
# Converts an integer to a null-terminated string
# Input: RAX contains the integer, RSI points to the buffer
# Output: The buffer contains the string representation
int_to_string:
xor rcx, rcx # Digit counter (RCX will store the length)
xor rbx, rbx # Temporary register
convert_to_str:
xor rdx, rdx # Clear RDX for division
mov rbx, 10 # Divisor
div rbx # RAX = RAX / 10, RDX = remainder
add dl, '0' # Convert remainder to ASCII
dec rsi # Move backwards in buffer
mov [rsi], dl # Store ASCII character
inc rcx # Increment digit counter
test rax, rax # Check if RAX is 0
jnz convert_to_str # Continue if not zero
# Null-terminate the string
mov byte ptr [rsi + rcx], 0 # Null-terminate the string
ret
int_to_string
points to the end of result_buffer
rsi
is [correctly] pointing to the resulting ascii string (which is nearer the end of result_buffer
than the beginning).For example, if we enter 23
and 36
, the result of the addition will be 59
The result_buffer
will look like:
OFFSET | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
ASCII | 5 | 9 | ||||||||||||||||||
HEXVAL | 35 | 39 | 00 | |||||||||||||||||
RSI | ↑rsi |
So, when printing, we should just use the returned value of rsi
and not do:
lea rsi, [result_buffer] # Address of result_buffer
Here is the corrected code:
.global _start # Declare the global entry point
.intel_syntax noprefix # Use Intel assembly syntax without prefixes
.section .bss # Reserve uninitialized space for buffers
buffer1: .space 20
buffer2: .space 20
result_buffer: .space 20
.section .text
_start:
# Read the first number
mov rax, 0 # sys_read
mov rdi, 0 # File descriptor: stdin
lea rsi, [buffer1]
mov rdx, 20 # Max bytes to read
syscall
mov byte ptr [rsi + rax], 0 # null terminate the input buffer
lea rsi, [buffer1]
call string_to_int
mov r8, rax # Store the first integer in r8
# Read the second number
mov rax, 0 # sys_read
mov rdi, 0 # File descriptor: stdin
lea rsi, [buffer2]
mov rdx, 20 # Max bytes to read
syscall
mov byte ptr [rsi + rax], 0
lea rsi, [buffer2] # Use buffer2 for the second input
call string_to_int
mov r9, rax # Store the second integer in r9
add r8, r9 # r8 = r8 + r9
# Convert the result back to a string
mov rax, r8 # Move the result into rax
lea rsi, [result_buffer + 19] # Point to the end of result_buffer
call int_to_string
# Calculate the string length (RCX holds the number of digits)
mov rdx, rcx
# Write the result
mov rax, 1 # sys_write
mov rdi, 1 # File descriptor: stdout
# FIX: do _not_ do this
###lea rsi, [result_buffer] # Address of result_buffer
mov rdx, rcx # number of digits in result
syscall # Perform system call
# Exit
mov rax, 60 # sys_exit
xor rdi, rdi # Exit code: 0
syscall
# Subroutine: string_to_int
# Converts a null-terminated string to an integer
# Input: RSI points to the string
# Output: RAX contains the integer value
string_to_int:
xor rax, rax # Clear rax (result)
xor rcx, rcx # Clear rcx (multiplier, initially 0)
convert_loop:
movzx rdx, byte ptr [rsi] # Load byte from the string
cmp rdx, 10 # Check for newline (ASCII '\n')
je convert_done # Exit loop on newline
sub rdx, '0' # Convert ASCII to digit (0-9)
imul rax, rax, 10 # Multiply result by 10
add rax, rdx # Add the current digit to the result
inc rsi # Move to the next character
jmp convert_loop
convert_done:
ret
# Subroutine: int_to_string
# Converts an integer to a null-terminated string
# Input: RAX contains the integer, RSI points to the buffer
# Output: The buffer contains the string representation
int_to_string:
xor rcx, rcx # Digit counter (RCX will store the length)
xor rbx, rbx # Temporary register
convert_to_str:
xor rdx, rdx # Clear RDX for division
mov rbx, 10 # Divisor
div rbx # RAX = RAX / 10, RDX = remainder
add dl, '0' # Convert remainder to ASCII
dec rsi # Move backwards in buffer
mov [rsi], dl # Store ASCII character
inc rcx # Increment digit counter
test rax, rax # Check if RAX is 0
jnz convert_to_str # Continue if not zero
# Null-terminate the string
mov byte ptr [rsi + rcx], 0 # Null-terminate the string
ret