From 6b45b84ab1303b26d06233eb1b41c1ddd4074cc5 Mon Sep 17 00:00:00 2001 From: Kwarde Date: Sat, 26 Jul 2025 00:20:25 +0200 Subject: [PATCH] printf->__INTERNAL_fmt. FD passed via RAX. fwrite now allows specifiers and variable arguments. --- src/console.asm | 21 ++++++++++++++++---- src/file.asm | 51 +++++++++++++++++++++++++------------------------ src/tests.asm | 25 ++++++++++++++++++++++++ 3 files changed, 68 insertions(+), 29 deletions(-) diff --git a/src/console.asm b/src/console.asm index 111b9fb..d623eb2 100644 --- a/src/console.asm +++ b/src/console.asm @@ -11,6 +11,8 @@ section .bss printfBuff resb printfBuffLen printfArgs resq 5 ;5=>rsi,rdx,rcx,r8,r9 section .text + global __INTERNAL_fmt + global print global puts global printf @@ -94,13 +96,23 @@ puts: ; r12 Padding length ; r13 Bitmask, 1 = insert specifier yes/no, 2 = use zeroes for padding yes/no ; r14 Keeps track of amount of processed format specifiers +; r15 Stores fd to write output to (passed to __INTERNAL_fmt via RAX) printf: + mov rax, FD_stdout + jmp __INTERNAL_fmt + +__INTERNAL_fmt: %macro load_arg 1 cmp r14, 4 ja %%fromStack mov %1, [printfArgs + SIZE_QWORD * r14] jmp %%continue %%fromStack: + cmp r15, FD_stdout + je %%stackNoShift + mov %1, [rbp + (RBP_OFFSET_CALLER*2 + SIZE_QWORD) + ((r14-5) * SIZE_QWORD)] ;non-printf functions calling __INTERNAL_fmt require RDI to be FD, all args shifted and rbp+RBP_OFFSET_CALLER to r9. Also requires function prologue and a CALL to __INTERNAL_fmt (not a JMP like in printf); hence the RBP_OFFSET_CALLER*2 + jmp %%continue + %%stackNoShift: mov %1, [rbp + RBP_OFFSET_CALLER + ((r14-5) * SIZE_QWORD)] %%continue: %endmacro @@ -152,10 +164,11 @@ printf: ; entry: push rbp mov rbp, rsp - sub rsp, SIZE_QWORD push r12 push r13 push r14 + push r15 + mov r15, rax cmp byte [rdi], EOS je .emptyStr @@ -414,7 +427,7 @@ printf: push rdx push r11 mov rax, NR_write - mov rdi, FD_stdout + mov rdi, r15 lea rsi, [rel printfBuff] mov rdx, r10 syscall @@ -435,7 +448,7 @@ printf: .wrapup: mov rax, NR_write - mov rdi, FD_stdout + mov rdi, r15 lea rsi, [rel printfBuff] mov rdx, r10 mov r10, r11 @@ -447,9 +460,9 @@ printf: xor rax, rax .quit: + pop r15 pop r14 pop r13 pop r12 - add rsp, SIZE_QWORD leave ret diff --git a/src/file.asm b/src/file.asm index dcd9a62..db953d2 100644 --- a/src/file.asm +++ b/src/file.asm @@ -1,5 +1,7 @@ %include "src/constants.asm" +extern __INTERNAL_fmt + extern strlen extern umask_get @@ -76,7 +78,7 @@ fopen: call fexist pop rsi pop rdi - mov rax, 1 + test rax, 1 jz %%createFile jmp %1 %%createFile: @@ -86,7 +88,7 @@ fopen: pop rdi push rdi not rax - mov rsi, 00666q + mov rsi, 0666q and rsi, rax mov rax, NR_creat syscall @@ -155,6 +157,7 @@ fopen: ; rax* (ret) ; rdi (arg) Pointer to opened file fclose: + sub rsp, SIZE_QWORD cmp rdi, 3 jl .invalid_fd ;disallow closing stdin,stdout,stderr mov rax, NR_close @@ -165,6 +168,7 @@ fclose: mov rax, -EINVAL .quit: + add rsp, SIZE_QWORD ret ;----- fexist(*file[]) -----; @@ -174,7 +178,7 @@ fclose: ; rax* (ret) ; rdi (arg) Pointer to string holding (path+)file name fexist: - ;sub rsp, SIZE_QWORD + sub rsp, SIZE_QWORD mov rsi, 'r' call fopen test rax, rax @@ -186,35 +190,32 @@ fexist: .not_exist: xor rax, rax .quit: - ;add rsp, SIZE_QWORD + add rsp, SIZE_QWORD ret -;--- fwrite(*filePointer, *data[]) -----; -; Writes data to given file +;--- fwrite(*filePointer, *data[], ...) -----; +; Writes data to given file. Allows format specifiers and variable arguments (see `__INTERNAL_fmt` for supported specifiers) ; Return value: Length of given string(data[]), 0 if nothing was written (eg invalid file or file not writable, or data[] is empty) ; Used registers: ; rax* (ret) ; rdi (arg) Pointer to file ; rsi (arg) Data to write -; r8* Backs up rdi -; r9* Backs up rsi fwrite: - sub rsp, SIZE_QWORD + push rbp + mov rbp, rsp + cmp rdi, 2 + jg .cnt xor rax, rax - cmp rdi, 3 - jl .quit - mov r8, rdi - mov r9, rsi - - mov rdi, rsi - call strlen - - mov rdx, rax - mov rax, NR_write - mov rdi, r8 - mov rsi, r9 - syscall - - .quit: - add rsp, SIZE_QWORD + leave + ret + .cnt: + mov rax, rdi + mov rdi, rsi + mov rsi, rdx + mov rdx, rcx + mov rcx, r8 + mov r8, r9 + mov r9, [rbp + RBP_OFFSET_CALLER] + call __INTERNAL_fmt + leave ret diff --git a/src/tests.asm b/src/tests.asm index 5467e58..94797d2 100644 --- a/src/tests.asm +++ b/src/tests.asm @@ -330,6 +330,8 @@ section .rodata addTest(fwrite1, "fwrite(fp1, 'Hello world!\n') //mode 'a'") addTest(fwrite2, "fwrite(fp1, 'How are you doing?\n') //mode 'a'") addTest(fwrite3, "fwrite(fp1, 'Howdy environment!') //mode 'w'") + addTest(fwrite4, "fwrite(fp1, ''%c%c%c%c%c%c%c%c\n'', 'H', 'e', 'l', 'l', 'o', '!', '?', '!')") + fwriteStr1 db "%c%c%c%c%c%c%c%c\n",EOS section .bss strBuff1 resb 64 @@ -1198,6 +1200,29 @@ _start: call fwrite assert_eq(18) + ; Re-open in write mode, again + mov rdi, [fp1] + call fclose + lea rdi, [rel file1] + mov rsi, 'w' + call fopen + mov [fp1], rax + + ; TEST 4 + printTest(fwrite4) + mov rdi, [fp1] + lea rsi, [fwriteStr1] + mov rdx, 'H' + mov rcx, 'e' + mov r8, 'l' + mov r9, 'l' + push byte '!' + push byte '?' + push byte '!' + push byte 'o' + call fwrite + add rsp, SIZE_QWORD * 4 + ; Close file1 mov rdi, [fp1] call fclose