Adds basic printf() (currently only support '%%')

This commit is contained in:
2025-07-06 20:09:21 +02:00
parent a47ab3cdc6
commit cc214ed5e5
2 changed files with 137 additions and 2 deletions

View File

@@ -3,10 +3,15 @@
extern strlen
section .rodata
mNL db NL
mNL db NL
printfBuffLen equ 128
section .bss
printfBuff resb printfBuffLen
printfArgs resq 5
section .text
global print
global puts
global printf
;----- print(*str[]) -----;
; Prints given string to the console to stdout
@@ -31,7 +36,10 @@ print:
; Prints given string to the console to stdout and prints a new line
; Return value: Amount of printed characters
; Used registers:
;
; rax* syscall >> (ret) amount of printed characters
; rdi* (arg) Pointer to str[] >> syscall arg (fd)
; rsi* syscall arg (pointer to str[])
; rdx* syscall arg (length of str[]+1)
puts:
sub rsp, SIZE_QWORD
call print
@@ -45,3 +53,109 @@ puts:
inc rax
add rsp, SIZE_QWORD
ret
;----- printf(*format[], ...) -----;
; Formats and prints given string to console to stdout
; Return value: Amount of printed characters
; Supported specifiers:
; %% Literal percentage sign
; <!> Unsupported specifiers are printed as-is
; Used registers:
; rax (ret) amount of printed characters
; rdi (arg) pointer to format[] to format and print
; rsi (optional arg)
; rdx (optional arg) >> Keeps track of amount of processed format specifiers
; rcx (optional arg)
; r8 (optional arg) >> Used for moving characters
; r9 (optional arg) >> Keeps track of where to jump after flushing buffer
; r10* Keeps track of current index of printfBuff
; r11* Keeps track of total characters (return value)
printf:
push rbp
mov rbp, rsp
sub rsp, SIZE_QWORD
cmp byte [rdi], EOS
je .emptyStr
xor r10, r10
xor r11, r11
; Store arguments to memory - easier to load data + more available registers (= less stack usage)
mov [printfArgs + SIZE_QWORD * 0], rsi
mov [printfArgs + SIZE_QWORD * 1], rdx
mov [printfArgs + SIZE_QWORD * 2], rcx
mov [printfArgs + SIZE_QWORD * 3], r8
mov [printfArgs + SIZE_QWORD * 4], r9
.process:
cmp byte [rdi], EOS
je .wrapup
mov r9b, 0
cmp r10, printfBuffLen-1
je .flushBuffer
.flushReturn_0:
cmp byte [rdi], '%'
je .argReplacement
mov r8b, [rdi]
mov [printfBuff+r10], r8b
inc r10
inc r11
inc rdi
jmp .process
.argReplacement:
cmp byte [rdi + 1], EOS
je .wrapup
cmp byte [rdi + 1], '%'
je .rep_pct
;--- Invalid ---;
mov r9w, word [rdi]
mov [printfBuff+r10], r9w
add rdi, 2
add r10, 2
add r11, 2
jmp .process
;--- '%%' ---;
.rep_pct:
mov [printfBuff+r10], byte '%'
add rdi, 2
add r10, 1
add r11, 1
jmp .process
.flushBuffer:
push rdx
push r11
mov rax, NR_write
mov rdi, FD_stdout
lea rsi, [rel printfBuff]
mov rdx, r11
syscall
pop r10
pop rdx
xor r10, r10
cmp r9b, 0
je .flushReturn_0
.wrapup:
mov rax, NR_write
mov rdi, FD_stdout
lea rsi, [rel printfBuff]
mov rdx, r10
mov r10, r11
syscall
mov rax, r10
jmp .quit
.emptyStr:
xor rax, rax
.quit:
add rsp, SIZE_QWORD
leave
ret

View File

@@ -5,6 +5,7 @@ extern exit
; console.asm
extern print
extern puts
extern printf
; string.asm
extern strlen
extern strcpy
@@ -14,6 +15,7 @@ extern strcat
section .rodata
TEST_print equ 1
TEST_puts equ 1
TEST_printf equ 1
TEST_strlen equ 1
TEST_strcpy equ 1
TEST_strcat equ 1
@@ -30,6 +32,11 @@ section .rodata
; puts()
msgPuts db "TEST puts()",EOS
; printf()
msgPrintf db "TEST printf()",NL,EOS
printf1 db TAB,"printf(",DQUO,"He%ll%o there%%%%%!%s%!%\n",DQUO,"): ",NL,TAB,TAB,EOS
printf1Str db "He%ll%o there%%%%%!%s%!%",NL,EOS
; strlen()
strlenStr1 db "Hello",EOS
strlenStr2 db "Hello, world!",NL,EOS
@@ -75,6 +82,20 @@ _start:
call puts
%endif
;---
;--- printf()
;---
%if TEST_printf
lea rdi, [rel msgPrintf]
call printf
; TEST 1
lea rdi, [rel printf1]
call print
lea rdi, [rel printf1Str]
call printf
%endif
;---
;--- strlen()
;---