Files
klibc/console.asm
Kwarde 01e14d418a FIX: No longer allow exceeding printf buffer, instead print an error to stdout. Temporary fix
Later, if buffer is full, print current buffer and reset buffer so that there is no limit.
2025-06-25 16:23:59 +02:00

277 lines
4.6 KiB
NASM

extern NR_write
extern strlen
extern strcat
extern itoa
section .rodata
NL db 0xA
bufferLength equ 4096
ERR_buffLen db "<!> ERROR: Failed to complete printf(), reached buffer length!",0xA,0x0
lERR_buffLen equ $-ERR_buffLen-1
section .bss
printfBuff resb bufferLength
printfNBuff resb 32
section .text
global print
global puts
global printf
;----- print (char* string) -----;
; return value: N/A
print:
push rbp
mov rbp, rsp
call strlen
mov rdx, rax
mov rax, NR_write
mov rsi, rdi
mov rdi, 1
syscall
leave
ret
;----- puts (char* string) -----;
; return value: N/A
puts:
push rbp
mov rbp, rsp
mov r10, rdi
call print
mov rdi, r10
mov rax, NR_write
mov rdi, 1
mov rsi, NL
mov rdx, 1
syscall
leave
ret
;----- printf(const char* string, ...) -----;
; Currently only supports specifiers: %d, %c, %s, %%
; Return value: Amount of printed characters
printf:
push rbp
mov rbp, rsp
push rbx ; used to check if error must be sent (reached buff len)
push r12 ; used for writing byted to printBuff
push r13 ; (also) used for writing bytes to printBuff (why again? gotta check that out - probably not needed, just lost count of register usage at some point)
push r14 ; count length of printBuff
xor rbx, rbx
xor r10, r10
xor r14, r14
lea r11, [rel printfBuff]
.makeStr:
cmp byte [rdi], 0x0
je .finish
cmp r14, bufferLength-1
je .finish_L
cmp byte [rdi], '%'
je .replaceArg
mov r12b, byte [rdi]
mov byte [r11], r12b
inc r14
jmp .continue
.replaceArg:
cmp byte [rdi+1], 0x0
je .continue
push rdi
cmp byte [rdi+1], 'd'
je .rep_d
cmp byte [rdi+1], '%'
je .rep_pct
cmp byte [rdi+1], 'c'
je .rep_c
cmp byte [rdi+1], 's'
je .rep_s
;--- invalid specifier ---;
mov byte [r11], '%'
inc r14
inc r10 ;assuming args were passed for invalid specifiers !
jmp .continue
;--- %d ---;
.rep_d:
cmp r10, 0
je .rep_d_rsi
cmp r10, 1
je .rep_d_rdx
cmp r10, 2
je .rep_d_rcx
cmp r10, 3
je .rep_d_r8
cmp r10, 4
je .rep_d_r9
;get from stack
mov rdi, qword [rbp + 16 + (r10-5)*8]
jmp .convertInt
.rep_d_rsi:
mov rdi, rsi
jmp .convertInt
.rep_d_rdx:
mov rdi, rdx
jmp .convertInt
.rep_d_rcx:
mov rdi, rcx
jmp .convertInt
.rep_d_r8:
mov rdi, r8
jmp .convertInt
.rep_d_r9:
mov rdi, r9
.convertInt:
lea rsi, [rel printfNBuff]
push rcx
push rdx
push r8
push r10
push rsi
call itoa
pop rsi
pop r10
pop r8
pop rdx
pop rcx
mov rsi, rax
jmp .insertLoop
;--- %% ---;
.rep_pct:
mov rdi, '%'
dec r10 ;r10 is increased at the end, but not needed because '%%' requires no arg
jmp .charToStr
;--- %c ---;
.rep_c:
cmp r10, 0
je .rep_c_rsi
cmp r10, 1
je .rep_c_rdx
cmp r10, 2
je .rep_c_rcx
cmp r10, 3
je .rep_c_r8
cmp r10, 4
je .rep_c_r9
;get from stack
mov rdi, qword [rbp + 16 + (r10-5)*8]
jmp .charToStr
.rep_c_rsi:
mov rdi, rsi
jmp .charToStr
.rep_c_rdx:
mov rdi, rdx
jmp .charToStr
.rep_c_rcx:
mov rdi, rcx
jmp .charToStr
.rep_c_r8:
mov rdi, r8
jmp .charToStr
.rep_c_r9:
mov rdi, r9
jmp .charToStr
.charToStr:
mov [printfNBuff], dil
inc r14
cmp r14, bufferLength-1
; Print error to stdout
je .finish_L
mov dil, 0
mov [printfNBuff+1], dil
inc r14
cmp r14, bufferLength-1
je .finish_L
lea rsi, [rel printfNBuff]
jmp .insertLoop
;--- %s ---;
.rep_s:
cmp r10, 0
je .insertLoop ;nothing to do, rsi already correct
cmp r10, 1
je .rep_s_rdx
cmp r10, 2
je .rep_s_rcx
cmp r10, 3
je .rep_s_r8
cmp r10, 4
je .rep_s_r9
;get from stack
mov rsi, qword [rbp + 16 + (r10-5)*8]
jmp .insertLoop
.rep_s_rdx:
mov rsi, rdx
jmp .insertLoop
.rep_s_rcx:
mov rsi, rcx
jmp .insertLoop
.rep_s_r8:
mov rsi, r8
jmp .insertLoop
.rep_s_r9:
mov rsi, r9
;--- Move fetched data to buffer ---;
.insertLoop:
cmp r14, bufferLength-1
je .finish_L
cmp byte [rsi], 0x0
je .s0f
mov r13b, byte [rsi]
mov byte [r11], r13b
inc r14
inc rsi
inc r11
jmp .insertLoop
.s0f:
inc r10
pop rdi
add rdi, 2
jmp .makeStr
.continue:
inc rdi
inc r11
jmp .makeStr
.finish_L:
mov rbx, 1
.finish:
mov byte [r11], 0x0
lea rdi, [rel printfBuff]
call print
lea rdi, [rel printfBuff]
call strlen
test rbx, rbx
jz .final
push r11
mov rax, NR_write
mov rdi, 2
lea rsi, [rel ERR_buffLen]
mov rdx, lERR_buffLen
syscall
.final:
pop r11
pop r14
pop r13
pop r12
pop rbx
leave
ret