How printf() Works in Assembly | x86-64 Beginner Tutorial | Print Strings, Chars, Hex, & Integers

Опубликовано: 01 Июль 2026
на канале: Mxy
1,925
91

Start Course from Beginning:    • Learn Assembly For Beginners | Introductio...  
Previous Video:    • Dynamic Memory in Assembly | The Heap | Be...  
Free x86-64 Emulator: https://x64.halb.it

;################ CODE BEGINS #########
.intel_syntax noprefix
.global _start
.text

_start:
lea rdi, [fmt]
lea rsi, [name]
mov rdx, 1234
mov rcx, 5678
lea r8, [byebye]
call printf
jmp _exit


printf:
push rbp
mov rbp, rsp
sub rsp, 80

mov [rbp - 48], rdi
mov [rbp - 40], rsi
mov [rbp - 32], rdx
mov [rbp - 24], rcx
mov [rbp - 16], r8
mov [rbp - 8], r9

mov r13, [rbp - 48]
lea r14, [buf]
lea r15, [rbp - 40]
.pf_loop:
mov al, [r13]
cmp al, 0
je .pf_done

cmp al, '%'
je .pf_handlearg

mov [r14], al
inc r13
inc r14
jmp .pf_loop

.pf_handlearg:
inc r13
mov al, [r13]
cmp al, 'c'
je .pf_handle_char

cmp al, '%'
je .pf_handle_percent

cmp al, 's'
je .pf_handle_string

cmp al, 'd'
je .pf_handle_signed_decimal

cmp al, 'u'
je .pf_handle_unsigned_decimal

cmp al, 'x'
je .pf_handle_hex

jmp .pf_unsupported

.pf_handle_signed_decimal:
mov rdi, [r15]
cmp rdi, 0
jl .pf_handle_negative
jmp .pf_handle_unsigned_decimal

.pf_handle_negative:
mov byte ptr [r14], '-'
inc r14
neg rdi
lea rsi, [rsp-80]
mov rdx, 32
call itoa
mov rsi, rax
jmp .pf_append_string

.pf_handle_hex:
mov rdi, [r15]
lea rsi, [rbp - 80]
mov rdx, 32
call htoa
mov rsi, rax
jmp .pf_append_string

.pf_handle_unsigned_decimal:
mov rdi, [r15]
lea rsi, [rbp - 80]
mov rdx, 32
call itoa
mov rsi, rax
jmp .pf_append_string

jmp .pf_loop
.pf_handle_string:
mov rsi, [r15]
jmp .pf_append_string

.pf_append_string:
mov al, [rsi]
cmp al, 0
je .pf_append_string_done

mov [r14], al
inc rsi
inc r14
jmp .pf_append_string

.pf_append_string_done:
add r15, 8
inc r13
jmp .pf_loop

.pf_handle_percent:
mov byte ptr [r14], '%'
inc r13
inc r14
jmp .pf_loop

.pf_handle_char:
mov al, [r15]
mov [r14], al

inc r13
inc r14
add r15, 8
jmp .pf_loop

.pf_unsupported:
jmp .pf_loop

.pf_done:
mov byte ptr [r14], 0

mov rax, 1
mov rdi, 1
lea rsi, [buf]
sub r14, rsi
mov rdx, r14
syscall

mov rsp, rbp
pop rbp
ret

htoa:

mov rax, rdi
dec rdx
add rsi, rdx
lea rdi, [rsi]
mov byte ptr [rdi], 0
dec rdi

.htoa_loop:
xor rdx, rdx ;# mov rdx, 0
mov rcx, 16
div rcx
cmp rdx, 10
jl .htoa_map_to_num
jmp .htoa_map_to_letter

.htoa_map_to_num:
add rdx, '0'
mov [rdi], dl
cmp rax, 0
je .htoa_done
dec rdi
jmp .htoa_loop

.htoa_map_to_letter:
add rdx, 'a'
sub rdx, 10
mov [rdi], dl
cmp rax, 0
je .htoa_done
dec rdi
jmp .htoa_loop
.htoa_done:
mov rax, rdi
ret

itoa:

mov rax, rdi
dec rdx
add rsi, rdx
lea rdi, [rsi]
mov byte ptr [rdi], 0
dec rdi

.itoa_loop:
xor rdx, rdx ;# mov rdx, 0
mov rcx, 10
div rcx
add rdx, '0'
mov byte ptr [rdi], dl
cmp rax, 0
je .itoa_done
dec rdi
jmp .itoa_loop
.itoa_done:
mov rax, rdi
ret


_exit:
mov rax, 60
xor rdi, rdi
syscall

.data
fmt: .asciz "Ahoy there, %s! (Num: %d Hex: 0x%x) %s"
name: .asciz "matey"
byebye: .asciz "bye bye, now!"
buf: .skip 128

;######## CODE END #########

00:00 How Printf Works
00:32 How Arguments are Passed
01:58 Printf in Assembly
02:35 Fmt Specifier String
04:05 Convert Arguments to Stack Array
08:29 Looping through fmt string
12:38 Creating Output Buffer
16:11 Detecting '%' Symbols
17:45 Handling %c Arguments
22:37 Handling %%
24:27 Handling %s Arguments
29:23 Handling %d Arguments
38:13 Adding Buffer to Stack
41:15 Handling %x Arguments
47:30 Handling Negative Numbers
51:33 Printing an ASCII Table
53:54 Fix: Callee Saved Registers
57:21 Fix: Unaligned Stack
59:00 Bye-by▒▒ - Incoming Transmission