printf->__INTERNAL_fmt. FD passed via RAX. fwrite now allows specifiers and variable arguments.

This commit is contained in:
2025-07-26 00:20:25 +02:00
parent d713fdf556
commit 6b45b84ab1
3 changed files with 68 additions and 29 deletions

View File

@@ -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

View File

@@ -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

View File

@@ -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