Having trouble adding two numbers taken as input from the terminal in assembly

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.

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<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
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
</code>
<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 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 </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
    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

New contributor

Brett Tyler is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.

2

  1. The argument to int_to_string points to the end of result_buffer
  2. It iterates backward
  3. When it returns, 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:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<code>lea rsi, [result_buffer] # Address of result_buffer
</code>
<code>lea rsi, [result_buffer] # Address of result_buffer </code>
lea rsi, [result_buffer]    # Address of result_buffer

Here is the corrected code:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<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
</code>
<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 </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

Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa Dịch vụ tổ chức sự kiện 5 sao Thông tin về chúng tôi Dịch vụ sinh nhật bé trai Dịch vụ sinh nhật bé gái Sự kiện trọn gói Các tiết mục giải trí Dịch vụ bổ trợ Tiệc cưới sang trọng Dịch vụ khai trương Tư vấn tổ chức sự kiện Hình ảnh sự kiện Cập nhật tin tức Liên hệ ngay Thuê chú hề chuyên nghiệp Tiệc tất niên cho công ty Trang trí tiệc cuối năm Tiệc tất niên độc đáo Sinh nhật bé Hải Đăng Sinh nhật đáng yêu bé Khánh Vân Sinh nhật sang trọng Bích Ngân Tiệc sinh nhật bé Thanh Trang Dịch vụ ông già Noel Xiếc thú vui nhộn Biểu diễn xiếc quay đĩa Dịch vụ tổ chức tiệc uy tín Khám phá dịch vụ của chúng tôi Tiệc sinh nhật cho bé trai Trang trí tiệc cho bé gái Gói sự kiện chuyên nghiệp Chương trình giải trí hấp dẫn Dịch vụ hỗ trợ sự kiện Trang trí tiệc cưới đẹp Khởi đầu thành công với khai trương Chuyên gia tư vấn sự kiện Xem ảnh các sự kiện đẹp Tin mới về sự kiện Kết nối với đội ngũ chuyên gia Chú hề vui nhộn cho tiệc sinh nhật Ý tưởng tiệc cuối năm Tất niên độc đáo Trang trí tiệc hiện đại Tổ chức sinh nhật cho Hải Đăng Sinh nhật độc quyền Khánh Vân Phong cách tiệc Bích Ngân Trang trí tiệc bé Thanh Trang Thuê dịch vụ ông già Noel chuyên nghiệp Xem xiếc khỉ đặc sắc Xiếc quay đĩa thú vị
Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa
Thiết kế website Thiết kế website Thiết kế website Cách kháng tài khoản quảng cáo Mua bán Fanpage Facebook Dịch vụ SEO Tổ chức sinh nhật