From 00568e2e7c43004f8d2a3f23bb6ccde549506715 Mon Sep 17 00:00:00 2001 From: Kwarde Date: Thu, 31 Jul 2025 14:18:00 +0200 Subject: [PATCH] Adds format(), modified __INTERNAL_fmt to allow writing to memory (instead of writing to given FD) --- src/console.asm | 109 +++++++++++++++++++++++++++++++++++------------- src/string.asm | 32 ++++++++++++++ 2 files changed, 112 insertions(+), 29 deletions(-) diff --git a/src/console.asm b/src/console.asm index 5ed4698..403577f 100644 --- a/src/console.asm +++ b/src/console.asm @@ -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 diff --git a/src/string.asm b/src/string.asm index 87df0a5..8787b2c 100644 --- a/src/string.asm +++ b/src/string.asm @@ -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