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 printfBuff resb printfBuffLen
printfArgs resq 5 ;5=>rsi,rdx,rcx,r8,r9 printfArgs resq 5 ;5=>rsi,rdx,rcx,r8,r9
section .text section .text
global __INTERNAL_fmt
global print global print
global puts global puts
global printf global printf
@@ -94,13 +96,23 @@ puts:
; r12 Padding length ; r12 Padding length
; r13 Bitmask, 1 = insert specifier yes/no, 2 = use zeroes for padding yes/no ; r13 Bitmask, 1 = insert specifier yes/no, 2 = use zeroes for padding yes/no
; r14 Keeps track of amount of processed format specifiers ; r14 Keeps track of amount of processed format specifiers
; r15 Stores fd to write output to (passed to __INTERNAL_fmt via RAX)
printf: printf:
mov rax, FD_stdout
jmp __INTERNAL_fmt
__INTERNAL_fmt:
%macro load_arg 1 %macro load_arg 1
cmp r14, 4 cmp r14, 4
ja %%fromStack ja %%fromStack
mov %1, [printfArgs + SIZE_QWORD * r14] mov %1, [printfArgs + SIZE_QWORD * r14]
jmp %%continue jmp %%continue
%%fromStack: %%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)] mov %1, [rbp + RBP_OFFSET_CALLER + ((r14-5) * SIZE_QWORD)]
%%continue: %%continue:
%endmacro %endmacro
@@ -152,10 +164,11 @@ printf:
; entry: ; entry:
push rbp push rbp
mov rbp, rsp mov rbp, rsp
sub rsp, SIZE_QWORD
push r12 push r12
push r13 push r13
push r14 push r14
push r15
mov r15, rax
cmp byte [rdi], EOS cmp byte [rdi], EOS
je .emptyStr je .emptyStr
@@ -414,7 +427,7 @@ printf:
push rdx push rdx
push r11 push r11
mov rax, NR_write mov rax, NR_write
mov rdi, FD_stdout mov rdi, r15
lea rsi, [rel printfBuff] lea rsi, [rel printfBuff]
mov rdx, r10 mov rdx, r10
syscall syscall
@@ -435,7 +448,7 @@ printf:
.wrapup: .wrapup:
mov rax, NR_write mov rax, NR_write
mov rdi, FD_stdout mov rdi, r15
lea rsi, [rel printfBuff] lea rsi, [rel printfBuff]
mov rdx, r10 mov rdx, r10
mov r10, r11 mov r10, r11
@@ -447,9 +460,9 @@ printf:
xor rax, rax xor rax, rax
.quit: .quit:
pop r15
pop r14 pop r14
pop r13 pop r13
pop r12 pop r12
add rsp, SIZE_QWORD
leave leave
ret ret

View File

@@ -1,5 +1,7 @@
%include "src/constants.asm" %include "src/constants.asm"
extern __INTERNAL_fmt
extern strlen extern strlen
extern umask_get extern umask_get
@@ -76,7 +78,7 @@ fopen:
call fexist call fexist
pop rsi pop rsi
pop rdi pop rdi
mov rax, 1 test rax, 1
jz %%createFile jz %%createFile
jmp %1 jmp %1
%%createFile: %%createFile:
@@ -86,7 +88,7 @@ fopen:
pop rdi pop rdi
push rdi push rdi
not rax not rax
mov rsi, 00666q mov rsi, 0666q
and rsi, rax and rsi, rax
mov rax, NR_creat mov rax, NR_creat
syscall syscall
@@ -155,6 +157,7 @@ fopen:
; rax* (ret) ; rax* (ret)
; rdi (arg) Pointer to opened file ; rdi (arg) Pointer to opened file
fclose: fclose:
sub rsp, SIZE_QWORD
cmp rdi, 3 cmp rdi, 3
jl .invalid_fd ;disallow closing stdin,stdout,stderr jl .invalid_fd ;disallow closing stdin,stdout,stderr
mov rax, NR_close mov rax, NR_close
@@ -165,6 +168,7 @@ fclose:
mov rax, -EINVAL mov rax, -EINVAL
.quit: .quit:
add rsp, SIZE_QWORD
ret ret
;----- fexist(*file[]) -----; ;----- fexist(*file[]) -----;
@@ -174,7 +178,7 @@ fclose:
; rax* (ret) ; rax* (ret)
; rdi (arg) Pointer to string holding (path+)file name ; rdi (arg) Pointer to string holding (path+)file name
fexist: fexist:
;sub rsp, SIZE_QWORD sub rsp, SIZE_QWORD
mov rsi, 'r' mov rsi, 'r'
call fopen call fopen
test rax, rax test rax, rax
@@ -186,35 +190,32 @@ fexist:
.not_exist: .not_exist:
xor rax, rax xor rax, rax
.quit: .quit:
;add rsp, SIZE_QWORD add rsp, SIZE_QWORD
ret ret
;--- fwrite(*filePointer, *data[]) -----; ;--- fwrite(*filePointer, *data[], ...) -----;
; Writes data to given file ; 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) ; 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: ; Used registers:
; rax* (ret) ; rax* (ret)
; rdi (arg) Pointer to file ; rdi (arg) Pointer to file
; rsi (arg) Data to write ; rsi (arg) Data to write
; r8* Backs up rdi
; r9* Backs up rsi
fwrite: fwrite:
sub rsp, SIZE_QWORD push rbp
mov rbp, rsp
cmp rdi, 2
jg .cnt
xor rax, rax xor rax, rax
cmp rdi, 3 leave
jl .quit ret
mov r8, rdi .cnt:
mov r9, rsi mov rax, rdi
mov rdi, rsi
mov rdi, rsi mov rsi, rdx
call strlen mov rdx, rcx
mov rcx, r8
mov rdx, rax mov r8, r9
mov rax, NR_write mov r9, [rbp + RBP_OFFSET_CALLER]
mov rdi, r8 call __INTERNAL_fmt
mov rsi, r9 leave
syscall
.quit:
add rsp, SIZE_QWORD
ret ret

View File

@@ -330,6 +330,8 @@ section .rodata
addTest(fwrite1, "fwrite(fp1, 'Hello world!\n') //mode 'a'") addTest(fwrite1, "fwrite(fp1, 'Hello world!\n') //mode 'a'")
addTest(fwrite2, "fwrite(fp1, 'How are you doing?\n') //mode 'a'") addTest(fwrite2, "fwrite(fp1, 'How are you doing?\n') //mode 'a'")
addTest(fwrite3, "fwrite(fp1, 'Howdy environment!') //mode 'w'") 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 section .bss
strBuff1 resb 64 strBuff1 resb 64
@@ -1198,6 +1200,29 @@ _start:
call fwrite call fwrite
assert_eq(18) 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 ; Close file1
mov rdi, [fp1] mov rdi, [fp1]
call fclose call fclose