Assembly Language - Numeric Processing

Handling numbers in assembly language involves a combination of base conversion, ASCII conversion, and arithmetic operations. This chapter explains in detail how to input and output numbers in various bases in a program.


Representation of Numbers

Internally, all numbers in a computer are stored in binary, but in a program they can be represented in different bases:

BaseRadixNASM SyntaxNumber Range (32-bit)
Binary20b10101010or10101010b0 and 1
Octal80o52or52o0-7
Decimal10420-9
Hexadecimal160x2Aor2Ah0-9, A-F

Relationship between ASCII and Numbers

Everything input and output on the screen isASCII characters, not binary numeric values.

Understanding the conversion between characters and numeric values is the core of assembly numeric processing:

CharacterASCII ValueCorresponding Numeric Value
'0'0x30(48)0
'1'0x31(49)1
'9'0x39(57)9
'A'0x41(65)10 (hexadecimal)
'F'0x46(70)15 (hexadecimal)
'a'0x61(97)10 (hexadecimal)

Converting character to number:数值 = ASCII码 - '0'(i.e.ASCII码 - 0x30)

Converting number to character:ASCII码 = 数值 + '0'(i.e.数值 + 0x30)


Inputting Numbers (String to Numeric Value)

What the user inputs is a character sequence, which needs to be converted into a binary numeric value before it can be used in calculations:

Example

; File path: string_to_int.asm
; Convert a decimal digit string to an integer value

section .data
    input_str db '12345', 0      ; Input string "12345"
    input_len dd 5               ; String length

section .bss
    result_val resd 1            ; Store the converted numeric value

section .text
    global _start

_start:
    ; Conversion algorithm: result = 0
    ; result = result * 10 + (current character - '0')
    mov esi, input_str           ; esi points to the input string
    mov ecx, [input_len]         ; ecx = loop count
    mov eax, 0                   ; eax = accumulated result

convert_loop:
    mov ebx, 10
    mul ebx                      ; eax = eax * 10
    ; mul ebx: edx:eax = eax * ebx

    mov bl, [esi]                ; Read the current character
    sub bl, '0'                  ; Convert to numeric: character - '0'
    movzx ebx, bl                ; Zero-extend ebx (bl -> ebx)
    add eax, ebx                 ; eax = eax + current digit's value

    inc esi                      ; Move to the next character
    loop convert_loop
    ; eax now = 12345

    mov [result_val], eax        ; Save the result

    mov eax, 1
    mov ebx, 0
    int 0x80

Algorithm analysis: take "12345" as an example:
Round 1: result = 0×10 + 1 = 1
Round 2: result = 1×10 + 2 = 12
Round 3: result = 12×10 + 3 = 123
...Finally we get 12345.


Outputting Numbers (Numeric Value to String)

Convert a binary numeric value into a displayable decimal string:

Example

; File path: int_to_string.asm
; Convert an integer value to a decimal string and output

section .data
    number dd 12345              ; The number to output
    newline db 0xA

section .bss
    output_buf resb 12           ; Output buffer (maximum 32-bit integer is 10 digits + sign + null)

section .text
    global _start

_start:
    mov eax, [number]            ; Load the number
    mov edi, output_buf + 11     ; edi points to the end of the buffer
    mov byte [edi], 0            ; null terminator (for easy debugging)
    dec edi

    mov ebx, 10                  ; Divisor = 10
    mov ecx, 0                   ; Digit counter

convert_digit:
    mov edx, 0                   ; Clear edx (div requires edx:eax)
    div ebx                      ; eax = eax/10, edx = eax%10
    add dl, '0'                  ; Convert remainder to character
    mov [edi], dl                ; Store into buffer (from back to front)
    dec edi                      ; Move buffer pointer forward
    inc ecx                      ; Digit count +1
    cmp eax, 0                   ; Is the quotient 0?
    jne convert_digit            ; No, continue the loop

    ; Now edi+1 points to the first valid digit character
    inc edi                      ; Fix pointer, point to the start of the string

    ; Calculate valid character length
    ; output_buf + 11 - edi is the valid length

    ; Output number
    mov eax, 4
    mov ebx, 1
    mov ecx, edi                 ; Point to the converted string
    ; Calculate length
    mov edx, output_buf + 11
    sub edx, edi                 ; edx = buffer end - string start
    int 0x80

    ; Output newline
    mov eax, 4
    mov ebx, 1
    mov ecx, newline
    mov edx, 1
    int 0x80

    mov eax, 1
    mov ebx, 0
    int 0x80

Running result:

$ nasm -f elf32 int_to_string.asm -o int_to_string.o
$ ld -m elf_i386 int_to_string.o -o int_to_string
$ ./int_to_string
12345

Hexadecimal Input and Output

Handling hexadecimal requires processing both 0-9 and A-F/a-f conversion:

Example

; File path: hex_output.asm
; Output a value in hexadecimal format

section .data
    number dd 0x1A2B3C4D         ; Value to output
    hex_prefix db '0x'
    hex_prefix_len equ $ - hex_prefix
    newline db 0xA

section .bss
    hex_buf resb 10              ; 8 hexadecimal digits + prefix + null

section .text
    global _start

_start:
    ; Output prefix "0x"
    mov eax, 4
    mov ebx, 1
    mov ecx, hex_prefix
    mov edx, hex_prefix_len
    int 0x80

    mov eax, [number]            ; Value to convert
    mov edi, hex_buf + 8         ; End of buffer (8 hexadecimal digits)
    mov ecx, 8                   ; Loop 8 times (32 bits = 8 hexadecimal digits)

hex_loop:
    mov edx, 0                   ; Prepare for division
    mov ebx, 16                  ; Divide by 16
    div ebx                      ; Now: eax divided by ebx
    ; Note: div ebx here is actually edx:eax / ebx
    ; Remainder in edx (0-15), quotient in eax
    mov ebx, eax                 ; Save quotient

    ; Convert remainder to hexadecimal character
    mov al, dl
    cmp al, 10
    jl  digit_09                 ; 0-9
    add al, 'A' - 10             ; A-F
    jmp store_char

digit_09:
    add al, '0'                  ; 0-9

store_char:
    dec edi
    mov [edi], al
    mov eax, ebx                 ; Restore quotient
    loop hex_loop

    ; Removed loop, directly using decrement method

    ; Output hexadecimal digits (8 digits)
    mov eax, 4
    mov ebx, 1
    mov ecx, hex_buf
    mov edx, 8
    int 0x80

    ; Output newline
    mov eax, 4
    mov ebx, 1
    mov ecx, newline
    mov edx, 1
    int 0x80

    mov eax, 1
    mov ebx, 0
    int 0x80

Complete Example: A Simple Addition Calculator

Input two single-digit numbers from the keyboard, calculate their sum and output:

Example

; File path: simple_calc.asm
; Input two single-digit numbers (0-9), calculate sum and output

section .data
    prompt1 db 'Enter first number (0-9): '
    prompt1_len equ $ - prompt1
    prompt2 db 'Enter second number (0-9): '
    prompt2_len equ $ - prompt2
    result_msg db 'Sum = '
    result_msg_len equ $ - result_msg
    newline db 0xA

section .bss
    num1 resb 2                  ; Input for the first number (1 digit + newline)
    num2 resb 2                  ; Input for the second number
    result_str resb 3            ; Result string (up to 2 digits + newline)

section .text
    global _start

_start:
    ; Prompt to input the first number
    mov eax, 4
    mov ebx, 1
    mov ecx, prompt1
    mov edx, prompt1_len
    int 0x80

    ; Read the first number
    mov eax, 3
    mov ebx, 0
    mov ecx, num1
    mov edx, 2
    int 0x80

    ; Prompt to input the second number
    mov eax, 4
    mov ebx, 1
    mov ecx, prompt2
    mov edx, prompt2_len
    int 0x80

    ; Read the second number
    mov eax, 3
    mov ebx, 0
    mov ecx, num2
    mov edx, 2
    int 0x80

    ; Calculate sum
    mov al, [num1]               ; Read the first number (ASCII character)
    sub al, '0'                  ; Convert to numeric value
    mov bl, [num2]               ; Read the second number
    sub bl, '0'                  ; Convert to numeric value
    add al, bl                   ; Sum

    ; Convert result to string
    mov ah, 0                    ; Prepare for division
    mov bl, 10                   ; Divide by 10
    div bl                       ; al = tens digit, ah = ones digit

    ; Save result
    add al, '0'                  ; Convert tens digit to character
    mov [result_str], al         ; Store tens digit
    add ah, '0'                  ; Convert ones digit to character
    mov [result_str + 1], ah     ; Store ones digit
    mov byte [result_str + 2], 0xA  ; Newline

    ; Output result message
    mov eax, 4
    mov ebx, 1
    mov ecx, result_msg
    mov edx, result_msg_len
    int 0x80

    ; Output calculation result (may be 1 or 2 digits)
    mov eax, 4
    mov ebx, 1
    mov ecx, result_str
    cmp byte [result_str], '0'
    je  output_one_digit        ; If the tens digit is '0', output only the ones digit
    mov edx, 3                  ; 2 digits + newline
    jmp do_output

output_one_digit:
    inc ecx                     ; Skip the tens digit '0'
    mov edx, 2                  ; 1 digit + newline

do_output:
    int 0x80

    mov eax, 1
    mov ebx, 0
    int 0x80

Running result:

$ nasm -f elf32 simple_calc.asm -o simple_calc.o
$ ld -m elf_i386 simple_calc.o -o simple_calc
$ ./simple_calc
Enter first number (0-9): 7
Enter second number (0-9): 8
Sum = 15

In assembly, handling numeric input/output requires a clear understanding of ASCII encoding and base conversion. Number-to-string (int to string) and string-to-number (string to int) are the two most basic utility functions. It is recommended to save them as templates after writing, for direct reuse later.

Other extensions