Adds format(), modified __INTERNAL_fmt to allow writing to memory (instead of writing to given FD)

This commit is contained in:
2025-07-31 14:18:00 +02:00
parent c36ae377ba
commit 00568e2e7c
2 changed files with 112 additions and 29 deletions

View File

@@ -1,6 +1,7 @@
%include "src/constants.asm"
extern strlen
extern strcat
extern itoa
extern utoa
@@ -88,6 +89,7 @@ puts:
; \t Tab
; Used registers:
; rax* (ret) amount of printed characters
; rbx Length of array being written to (if rax != FD)
; rdi* (arg) pointer to format[] to format and print >> pointer to buffer
; rsi* (optional arg) >> Used for inserting strings to buffer
; rdx* (optional arg) >> misc
@@ -181,7 +183,32 @@ __INTERNAL_fmt:
jmp .insertString
%endmacro
%macro check_formatted_len 2 ;check_format_len [return_label] [offset]
test rbx, rbx
jz %%checkBufferLen
cmp r11, rbx
jae .wrapup
jmp .flushReturn_%1
%%checkBufferLen:
mov r9b, %1
cmp r10, __fmt_BuffLen-%2
je .flushBuffer
.flushReturn_%1:
%endmacro
%macro write_format_data 3 ;write_format_data [size] [offset] [what]
test rbx, rbx
jz %%writeToBuffer
mov %1 [r15 + %2], %3
jmp %%cnt
%%writeToBuffer:
mov %1 [__fmt_Buff + %2], %3
%%cnt:
%endmacro
; entry:
test rax, rax
js .start_fmt ;jump if signed; FD => Mem
cmp rax, 0
jg .start_fmt
mov rax, -EBADF
@@ -189,12 +216,20 @@ __INTERNAL_fmt:
.start_fmt:
push rbp
mov rbp, rsp
sub rsp, SIZE_QWORD
push rbx
push r12
push r13
push r14
push r15
mov r15, rax
xor rbx, rbx
test r15, r15
jns .checkEmptyStr
not r15
mov rbx, [rbp + RBP_OFFSET_CALLER]
.checkEmptyStr:
cmp byte [rdi], EOS
je .emptyStr
@@ -213,16 +248,13 @@ __INTERNAL_fmt:
.process:
cmp byte [rdi], EOS
je .wrapup
xor r9b, r9b
cmp r10, __fmt_BuffLen-1
je .flushBuffer
.flushReturn_0:
check_formatted_len 0,1
cmp byte [rdi], '\'
je .asciiReplacement
cmp byte [rdi], '%'
je .argReplacement
mov r8b, [rdi]
mov [__fmt_Buff+r10], r8b
write_format_data byte,r10,r8b
inc r10
inc r11
inc rdi
@@ -240,15 +272,10 @@ __INTERNAL_fmt:
cmp byte [rdi + 1], 't'
cmove r9, r8
je .replaceAscii
jmp .invalidReplacement
.replaceAscii:
mov r8b, r9b
mov r9b, 2
cmp r10, __fmt_BuffLen-1
je .flushBuffer
.flushReturn_2:
mov [__fmt_Buff + r10], r8b
check_formatted_len 1, 1
write_format_data byte,r10,r8b
add rdi, 2
inc r10
inc r11
@@ -342,7 +369,7 @@ __INTERNAL_fmt:
cmp byte [rdi + 1], '\'
je .invalidReplacement_specialChar; '%\n' would become "'%','\','n'" instead of "'%',EOS" when inserting full invalid specifier.
mov r9w, word [rdi]
mov [__fmt_Buff+r10], r9w
write_format_data word,r10,r9w
add rdi, 2
add r10, 2
add r11, 2
@@ -350,7 +377,7 @@ __INTERNAL_fmt:
jmp .process
.invalidReplacement_specialChar:
mov r9b, byte [rdi]
mov [__fmt_Buff+r10], r9b
write_format_data byte,r10,r9b
inc rdi
inc r10
inc r11
@@ -405,14 +432,10 @@ __INTERNAL_fmt:
.insertString:
test rsi, rsi
jnz .doInsertString
;rsi = NULL:
mov r9b, 3
cmp r10, __fmt_BuffLen-7
je .flushBuffer
.flushReturn_3:
mov byte [__fmt_Buff + r10], '('
mov qword [__fmt_Buff + r10 + 1], 'null'
mov byte [__fmt_Buff + r10 + 5], ')'
check_formatted_len 2, 7
write_format_data byte,r10,'('
write_format_data qword,r10+1,'null'
write_format_data byte,r10+5,')'
add r10, 6
add r11, 6
jmp .endInsertString
@@ -420,12 +443,9 @@ __INTERNAL_fmt:
.doInsertString:
cmp byte [rsi], EOS
je .endInsertString
mov r9b, 1
cmp r10, __fmt_BuffLen-1
je .flushBuffer
.flushReturn_1:
check_formatted_len 3, 1
mov r8b, byte [rsi]
mov [__fmt_Buff + r10], r8b
write_format_data byte,r10,r8b
inc rsi
inc r10
inc r11
@@ -438,7 +458,7 @@ __INTERNAL_fmt:
;--- Insert char to buffer ---;
.insertChar:
mov [__fmt_Buff + r10], sil
write_format_data byte,r10,sil
add rdi, 2
add r10, 1
add r11, 1
@@ -447,6 +467,22 @@ __INTERNAL_fmt:
jmp .process
.flushBuffer:
test rbx, rbx
jz .flush_print
sub rsp, SIZE_QWORD
push rdi
push rsi
push rdx
lea rdi, [r15]
lea rsi, [rel __fmt_Buff]
mov rdx, rbx
call strcat
pop rdx
pop rsi
pop rdi
add rsp, SIZE_QWORD
jmp .flush_ret
.flush_print:
push rdi
push rsi
push rdx
@@ -463,7 +499,7 @@ __INTERNAL_fmt:
test rax, rax
js .quit
xor r10, r10
.flush_ret:
cmp r9b, 0
je .flushReturn_0
cmp r9b, 1
@@ -474,6 +510,19 @@ __INTERNAL_fmt:
je .flushReturn_3
.wrapup:
test rbx, rbx
jz .wrapup_print
mov byte [r15+r10+1], EOS
lea rdi, [r15]
lea rsi, [rel __fmt_Buff]
mov rdx, rbx
sub rsp, SIZE_QWORD
push r11
call strcat
pop rax
add rsp, SIZE_QWORD
jmp .quit
.wrapup_print:
mov rax, NR_write
mov rdi, r15
lea rsi, [rel __fmt_Buff]
@@ -493,6 +542,8 @@ __INTERNAL_fmt:
pop r14
pop r13
pop r12
pop rbx
add rsp, SIZE_QWORD
leave
ret

View File

@@ -1,5 +1,7 @@
%include "src/constants.asm"
extern __INTERNAL_fmt
section .text
global strlen
global strcpy
@@ -7,6 +9,7 @@ section .text
global strclr
global strcmp
global strfind
global format
;----- strlen(*str[]) -----;
; Gets the length of given string
@@ -216,3 +219,32 @@ strfind:
mov rax, r8
.quit:
ret
;----- format(*dest[], len, *fmt[], ...) -----;
; Formats a string and writes it to memory.
; See __INTERNAL_fmt for valid specifiers
; Return value: Amount of characters written to dest[]
; Used registers:
; rax* (ret)
; rdi* (arg) Pointer to dest[]
; rsi* (arg) Size of dest[]
; rdx* (arg) Pointer to fmt[]
format:
push rbp
mov rbp, rsp
mov rax, rdi
not rax ;__INTERNAL_fmt; ~FD => Mem
sub rsp, SIZE_QWORD
push rsi ;__INTERNAL_fmt: pop len from stack if rax is signed
lea rdi, [rdx]
mov rsi, rcx
mov rdx, r8
mov rcx, r9
mov r8, [rbp + RBP_OFFSET_CALLER + SIZE_QWORD * 0]
mov r9, [rbp + RBP_OFFSET_CALLER + SIZE_QWORD * 1]
call __INTERNAL_fmt
add rsp, SIZE_QWORD * 2
leave
ret