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:
| Base | Radix | NASM Syntax | Number Range (32-bit) |
|---|---|---|---|
| Binary | 2 | 0b10101010or10101010b | 0 and 1 |
| Octal | 8 | 0o52or52o | 0-7 |
| Decimal | 10 | 42 | 0-9 |
| Hexadecimal | 16 | 0x2Aor2Ah | 0-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:
| Character | ASCII Value | Corresponding 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
; 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
; 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
; 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
; 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
Other extensionsIn 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.