Files
klibc/console.asm
2025-06-26 10:38:01 +02:00

282 lines
5.3 KiB
NASM

extern EOS
extern NL
extern NR_write
extern strlen
extern itoa
section .rodata
bufferLength equ 4096
ERR_buffLen db "<!> ERROR: Failed to complete printf(), reached buffer length!",NL,EOS
lERR_buffLen equ $-ERR_buffLen-1
; Errors (perror)
perrorMsg db "%s: %s",NL,EOS
perrorInvalid db "%s: Unknown error (errno %d)",NL,EOS
errorMsgs dq em0,em1,em2,em3,em4,em5,em6,em7,em8,em9,em10,em11,em12,em13,em14,em15,em16,em17,em18,em19,em20,em21,em22,em23,em24,em25,em26,em27,em28,em29,em30,em31,em32,em33,em34
em0 db "No error",EOS
em1 db "Operation not permitted",EOS
em2 db "No such file or directory",EOS
em3 db "No such process",EOS
em4 db "Interrupted system call",EOS
em5 db "I/O error",EOS
em6 db "No such device or address",EOS
em7 db "Argument list too long",EOS
em8 db "Exec format error",EOS
em9 db "Bad file number",EOS
em10 db "No child processes",EOS
em11 db "Try again",EOS
em12 db "Out of memory",EOS
em13 db "Permission denied",EOS
em14 db "Bad address",EOS
em15 db "Block device required",EOS
em16 db "Device or resource busy",EOS
em17 db "File exists",EOS
em18 db "Cross-device link",EOS
em19 db "No such device",EOS
em20 db "Not a directory",EOS
em21 db "Is a directory",EOS
em22 db "Invalid argument",EOS
em23 db "File table overflow",EOS
em24 db "Too many open files",EOS
em25 db "Not a typewriter",EOS
em26 db "Text file busy",EOS
em27 db "File too large",EOS
em28 db "No space left on device",EOS
em29 db "Illegal seek",EOS
em30 db "Read-only file system",EOS
em31 db "Too many links",EOS
em32 db "Broken pipe",EOS
em33 db "Math argument out of domain of func",EOS
em34 db "Math result not representable",EOS
section .bss
printfBuff resb bufferLength
printfNBuff resb 32
section .text
global print
global puts
global printf
global perror
;----- print (char* string) -----;
; return value: N/A
print:
call strlen
mov rdx, rax
mov rax, NR_write
mov rsi, rdi
mov rdi, 1
syscall
ret
;----- puts (char* string) -----;
; return value: N/A
puts:
mov r10, rdi
call print
mov rdi, r10
mov rax, NR_write
mov rdi, 1
mov rsi, NL
mov rdx, 1
syscall
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 r12
push r14
xor r10, r10
xor r14, r14
lea r11, [rel printfBuff]
.makeStr:
cmp byte [rdi], 0x0
je .finish
cmp r14, bufferLength-1
je .finish
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
jmp .continue
;--- %d ---;
.rep_d:
cmp r10, 0
cmove rdi, rsi
je .convertInt
cmp r10, 1
cmove rdi, rdx
je .convertInt
cmp r10, 2
cmove rdi, rcx
je .convertInt
cmp r10, 3
cmove rdi, r8
je .convertInt
cmp r10, 4
cmove rdi, r9
je .convertInt
mov rdi, qword [rbp + 16 + (r10-5)*8]
.convertInt:
lea rsi, [rel printfNBuff]
push rcx
push rdx
push r8
push r10
call itoa
pop r10
pop r8
pop rdx
pop rcx
mov rsi, rax
jmp .insertLoop
;--- %% ---;
.rep_pct:
mov rdi, '%'
dec r10
jmp .charToStr
;--- %c ---;
.rep_c:
cmp r10, 0
cmove rdi, rsi
je .charToStr
cmp r10, 1
cmove rdi, rdx
je .charToStr
cmp r10, 2
cmove rdi, rcx
je .charToStr
cmp r10, 3
cmove rdi, r8
je .charToStr
cmp r10, 4
cmove rdi, r9
je .charToStr
mov rdi, qword [rbp + 16 + (r10-5)*8]
.charToStr:
mov [printfNBuff], dil
mov dil, 0
mov [printfNBuff+1], dil
lea rsi, [rel printfNBuff]
jmp .insertLoop
;--- %s ---;
.rep_s:
cmp r10, 0
je .insertLoop
cmp r10, 1
cmove rsi, rdx
je .insertLoop
cmp r10, 2
cmove rsi, rcx
je .insertLoop
cmp r10, 3
cmove rsi, r8
je .insertLoop
cmp r10, 4
cmove rsi, r9
je .insertLoop
mov rsi, qword [rbp + 16 + (r10-5)*8]
;--- Move fetched data to buffer ---;
.insertLoop:
cmp r14, bufferLength-1
je .finish
cmp byte [rsi], 0x0
je .s0f
mov r12b, byte [rsi]
mov byte [r11], r12b
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:
mov byte [r11], 0x0
mov rax, NR_write
mov rdi, 1
lea rsi, [rel printfBuff]
mov rdx, r14
syscall
mov rax, r14
cmp r14, bufferLength-1
jl .final
mov rax, NR_write
mov rdi, 2
lea rsi, [rel ERR_buffLen]
mov rdx, lERR_buffLen
syscall
.final:
pop r14
pop r12
leave
ret
;----- perror(const char *str) -----;
; retrieves last returned error. Uses rax to fetch errno.
; errno must be negative
; Returns nothing (rax restored to original value)
perror:
push rax
cmp rax, 0
jge .quit
neg rax
cmp rax, 34
jg .unknown
mov rsi, rdi
lea rdi, [rel perrorMsg]
lea rdx, [errorMsgs + rax*8]
mov rdx, [rdx]
call printf
jmp .quit
.unknown:
mov rsi, rdi
lea rdi, [rel perrorInvalid]
mov rdx, rax
call printf
.quit:
pop rax
ret