From 9f33e36883e39d9d4fb49646f29bb655f97f0040 Mon Sep 17 00:00:00 2001 From: Kwarde Date: Tue, 15 Jul 2025 07:58:18 +0200 Subject: [PATCH] Rewrite X2str functions to itoa/utoa ; it was a stupid idea to have seperate functions (=> more maintenance) --- src/console.asm | 66 ++++---- src/convert.asm | 439 ++++++++++++++++++++---------------------------- src/tests.asm | 77 +-------- 3 files changed, 223 insertions(+), 359 deletions(-) diff --git a/src/console.asm b/src/console.asm index c894ffc..3689d9c 100644 --- a/src/console.asm +++ b/src/console.asm @@ -1,10 +1,8 @@ %include "src/constants.asm" extern strlen -extern dec2str -extern udec2str -extern hex2str -extern bin2str +extern itoa +extern utoa section .rodata mNL db NL @@ -104,17 +102,21 @@ printf: %endmacro %macro push_regs 0 + sub rsp, SIZE_QWORD push rax push rdi push r9 push r10 + push r11 %endmacro %macro pop_regs 0 + pop r11 pop r10 pop r9 pop rdi pop rax + add rsp, SIZE_QWORD %endmacro ; entry: @@ -271,44 +273,40 @@ printf: .rep_d: load_arg rsi push_regs - mov rdx, r13 + mov rdx, r12 + mov rcx, r13 cmp byte [rdi + 1], 'u' - je .callUINT2STR + je .callUTOA mov rdi, rsi - mov rsi, r12 - call dec2str - jmp .loadConvertedStr - .callUINT2STR: + mov rsi, 10 + call itoa + jmp .pr + .callUTOA: mov rdi, rsi - mov rsi, r12 - call udec2str - .loadConvertedStr: + mov rsi, 10 + mov r8, 0 + call utoa + .pr: mov rsi, rax pop_regs jmp .insertString ;--- '%x' / '%X' ---; .rep_x: - push rdi - load_arg rcx - xor rsi, rsi - mov r8, 1 - cmp byte [rdi + 1], 'X' - cmove rsi, r8 - mov rdi, rcx - push rax - push rdx - push r9 - push r10 + load_arg rsi + push_regs mov rdx, r12 mov rcx, r13 - call hex2str + mov r8, 0 + cmp byte [rdi + 1], 'x' + je .lower + mov r8, 1 + .lower: + mov rdi, rsi + mov rsi, 16 + call utoa mov rsi, rax - pop r10 - pop r9 - pop rdx - pop rax - pop rdi + pop_regs jmp .insertString ;--- '%b' ---; @@ -316,9 +314,11 @@ printf: load_arg rsi push_regs mov rdi, rsi - mov rsi, r12 - mov rdx, r13 - call bin2str + mov rsi, 2 + mov rdx, r12 + mov rcx, r13 + mov r8, 0 + call utoa mov rsi, rax pop_regs jmp .insertString diff --git a/src/convert.asm b/src/convert.asm index 4b79554..f01e5ba 100644 --- a/src/convert.asm +++ b/src/convert.asm @@ -6,294 +6,225 @@ section .bss cnvtBuff resb 67 cnvtBuffRev resb 67 section .text - global dec2str - global udec2str - global hex2str - global bin2str + global itoa + global utoa -;----- dec2str(int, padLen, bool padZeroes) -----; -; Converts a signed integer to a string (decimal output) -; Return value: Pointer to string containing the converted integer +;----- itoa(int, base, padLen, bool padZeroes) -----; +; Converts a signed integer to a string +; Return value: Pointer to converted string or 0(EOS) if entered base is invalid +; Supported bases: 10 (decimal) ; Used registers: -; rax* int stored for div >> (ret) pointer to cnvtBuff[] -; rcx* Counts length of created string -; rdx* (arg) padZeroes >> modulo as calculated by div >> character storage for cnvtBuff -; rdi* (arg) integer to convert to string >> Remembers if num is negative -; rsi* (arg) Padding length -; r8* Dividor for div -; r9* Points to cnvtBuff[] -; r10* padZeroes arg (since rdx used by DIV) -; r12 Remembers if number is negative -dec2str: +; rax* num to divide (DIV) >> Copy bytes when reversing string >> (ret) Pointer to converted string +; rdi* (arg) Integer to convert +; rsi* (arg) Base to convert to +; rdx* (arg) Padding length >> modulo (DIV) +; rcx* (arg) 0=pad spaces, otherwise pad zeroes >> Loop counter +; r9* Counts string length +; r10* Points to cnvtBuff(Rev)[] +; r11* Remembers if number is negative (r11b) +; r12 Stores (int) +; r13 Stores (base) +; r14 Stores (padLen) +; r15 Stores (padZeroes) +itoa: + ; Before doing anything, check if base is valid + cmp rsi, 10 + je .ok + xor rax, rax + ret + .ok: push r12 - xor r12, r12 - mov r10, ' ' - mov r9, '0' - test rdx, rdx - cmovnz r10, r9 - lea r9, [rel cnvtBuffRev] - mov rax, rdi - xor dil, dil - xor rcx, rcx + push r13 + push r14 + push r15 + ; Store original arguments + mov r12, rdi + mov r13, rsi + mov r14, rdx + mov r15, rcx + ; First, assure 0 <= padLen <= 64 ;(64, even though max signed int64 = 19 characters; enables to pad with base 2) + mov rdi, rdx + xor rsi, rsi + mov rdx, 64 + call clamp + mov r14, rax + ; Store padding character + mov rdi, ' ' + mov rdx, '0' + test r15, r15 + cmovnz rdi, rdx + mov r15, rdi + ; Prepare for conversion + mov rax, r12 + xor r9, r9 + lea r10, [rel cnvtBuffRev] + ; Check if negative + xor r11b, r11b test rax, rax jns .convert + mov r11b, 1 neg rax - mov dil, 1 .convert: xor rdx, rdx - mov r8, 10 - div r8 + div r13 add rdx, '0' - mov [r9], dl + mov byte [r10], dl + inc r10 inc r9 - inc rcx test rax, rax jnz .convert - test dil, dil - jz .makeString - mov r12, 1 + ; Adds '-' if needed + cmp r15, '0' + je .checkPadding ; If padding with zeroes, add minus sign before zeroes. Otherwise, add '-' and then add spaces + test r11b, r11b + jz .checkPadding + mov byte [r10], '-' + inc r10 + inc r9 + .checkPadding: + ; Substract length of converted number from padLen + sub r14, r9 + cmp r14, 0 + jle .makeString + mov rcx, r14 + .addPadding: + mov byte [r10], r15b + inc r10 + inc r9 + loop .addPadding + cmp r15, ' ' + je .makeString + ; Adds '-' if needed + test r11b, r11b + jz .makeString + mov byte [r10], '-' + inc r10 + inc r9 .makeString: - sub rsi, rcx - cmp rsi, 0 - jle .noPadding - mov r8, rcx - mov rdi, rsi - xor rsi, rsi - mov rdx, 64 - call clamp - mov rcx, rax - test r12, r12 - jz .paddingLoop - cmp r10, '0' - je .paddingLoop - mov byte [r9], '-' - inc r9 - inc r8 - xor r12, r12 - .paddingLoop: - mov byte [r9], r10b - inc r9 - inc r8 - loop .paddingLoop - mov rcx, r8 - .noPadding: - test r12, r12 - jz .positive - mov [r9], byte '-' - inc r9 - inc rcx - .positive: + dec r10 ;don't point to past last character lea rdi, [rel cnvtBuff] - dec r9 + mov rcx, r9 + xor rax, rax .makeStringLoop: - mov al, [r9] - mov [rdi], al + mov al, byte [r10] + mov byte [rdi], al inc rdi - dec r9 + dec r10 loop .makeStringLoop - mov byte [rdi], EOS + mov byte [rdi], EOS - .quit: - lea rax, [rel cnvtBuff] + pop r15 + pop r14 + pop r13 pop r12 - ret - -;----- udec2str(uint, padLen, bool padZeroes) -----; -; Converts an unsigned integer to a string (decimal output) -; Return value: Pointer to string containing the converted integer -; Used registers: -; rax* uint stored for div >> (ret) pointer to cnvtBuff[] -; rcx* Counts length of created string -; rdx* (arg) padZeroes >> modulo as calculated by div -; rdi* (arg) integer to convert to string -; rsi* (arg) padLen -; r8* Dividor for div -; r9* Points to cnvtBuff for writing characters -; r10* padZeroes arg (since rdx used by DIV) -udec2str: - mov r10, ' ' - mov r9, '0' - test rdx, rdx - cmovnz r10, r9 - lea r9, [rel cnvtBuffRev] - mov rax, rdi - xor rcx, rcx - .convert: - xor rdx, rdx - mov r8, 10 - div r8 - add rdx, '0' - mov [r9], dl - inc r9 - inc rcx - test rax, rax - jnz .convert - sub rsi, rcx - cmp rsi, 0 - jle .noPadding - mov r8, rcx - mov rdi, rsi - xor rsi, rsi - mov rdx, 64 - call clamp - mov rcx, rax - .paddingLoop: - mov byte [r9], r10b - inc r9 - inc r8 - loop .paddingLoop - mov rcx, r8 - .noPadding: - lea rdi, [rel cnvtBuff] - dec r9 - .makeStringLoop: - mov al, [r9] - mov [rdi], al - inc rdi - dec r9 - loop .makeStringLoop - mov byte [rdi], EOS - - .quit: lea rax, [rel cnvtBuff] ret -;----- hex2str(uint, bool uppercase, padLen, bool padZeroes) -----; -; Converts an unsigned integer to a string (hexadecimal output) -; Return value: Pointer to string containing the converted integer +;----- utoa(int, base, padLen, bool padZeroes, bool upperCase) -----; +; Converts an unsigned integer to a string +; Return value: Pointer to converted string or 0(EOS) if entered base is invalid +; Supported bases: 2 (binary), 10 (decimal), 16 (hexadecimal) ; Used registers: -; rax* uint stored for div >> (ret) Pointer to cnvtBuff[] -; rdi (arg) Integer to convert -; rsi* (arg) 0=convert lowercase, (any other value)=convert uppercase >> Points to cnvtBuff for writing characters -; rdx* (arg) Padding length >> module as calculated by div -; rcx* (arg) padZeroes >> Counts length of created string -; r8* Dividor for div -; r9* Store arg rsi (uppercase) -; r10* Store arg rdx -; r11* Amount to add to number (for ASCII conversion, lowercase or uppercase) -; r12 Store arg padZeroes -hex2str: +; rax* num to divide (DIV) >> Copy bytes when reversing string >> (ret) Pointer to converted string +; rbx Stores (upperCase) +; rdi* (arg) Integer to convert +; rsi* (arg) Base to convert to +; rdx* (arg) Padding length >> modulo (DIV) +; rcx* (arg) 0=pad spaces, otherwise pad zeroes >> Loop counter +; r8* (arg) 0=lowercase letters (for bases using letters, ie 16), uppercase otherwise >> Stores character to copy to when determining number or uppercase/lowercase letter +; r9* Counts string length +; r10* Points to cnvtBuff(Rev)[] +; r11* Remembers if number is negative (r11b) +; r12 Stores (int) +; r13 Stores (base) +; r14 Stores (padLen) +; r15 Stores (padZeroes) +utoa: + ; Before doing anything, check if base is valid + cmp rsi, 2 + je .ok + cmp rsi, 10 + je .ok + cmp rsi, 16 + je .ok + xor rax, rax + ret + .ok: + push rbx push r12 - mov r9, rsi - mov r10, rdx - mov r12, ' ' - mov rsi, '0' - test rcx, rcx - cmovnz r12, rsi - lea rsi, [rel cnvtBuffRev] - mov rax, rdi - xor rcx, rcx - mov r8, 87 - test r9, r9 - cmovz r11, r8 - test r9, r9 + push r13 + push r14 + push r15 + ; Store original arguments + mov rbx, r8 + mov r12, rdi + mov r13, rsi + mov r14, rdx + mov r15, rcx + ; First, assure 0 <= padLen <= 64 ;(64, even though max signed int64 = 19 characters; enables to pad with base 2) + mov rdi, rdx + xor rsi, rsi + mov rdx, 64 + call clamp + mov r14, rax + ; Store padding character + mov rdi, ' ' + mov rdx, '0' + test r15, r15 + cmovnz rdi, rdx + mov r15, rdi + ; Prepare for conversion + mov rax, r12 + xor r9, r9 + lea r10, [rel cnvtBuffRev] + mov rdx, 'a'-10 + test rbx, rbx + cmovz r8, rdx jz .convert - mov r11, 55 + mov r8, 'A'-10 .convert: xor rdx, rdx - mov r8, 16 - div r8 - cmp rdx, 10 - jb .num - add rdx, r11 - jmp .push - .num: - add rdx, '0' - .push: - mov [rsi], dl - inc rsi - inc rcx + div r13 + cmp dl, 9 + jle .noLetter + add dl, r8b + jmp .write + .noLetter: + add dl, '0' + .write: + mov byte [r10], dl + inc r10 + inc r9 test rax, rax jnz .convert - sub r10, rcx - cmp r10, 0 - jle .noPadding - mov r8, rcx - push rsi - mov rdi, r10 - xor rsi, rsi - mov rdx, 64 - call clamp - pop rsi - mov rcx, rax - .paddingLoop: - mov byte[rsi], r12b - inc rsi - inc r8 - loop .paddingLoop - mov rcx, r8 - .noPadding: - dec rsi - lea rdi, [rel cnvtBuff] + .checkPadding: + ; Substract length of converted number from padLen + sub r14, r9 + cmp r14, 0 + jle .makeString + mov rcx, r14 + .addPadding: + mov byte [r10], r15b + inc r10 + inc r9 + loop .addPadding .makeString: - mov al, [rsi] - mov [rdi], al - inc rdi - dec rsi - loop .makeString - mov byte [rdi], EOS - - .quit: - lea rax, [rel cnvtBuff] - pop r12 - ret - -;----- bin2str(uint, padLen, bool padZeroes) -----; -; Converts an unsigned integer to a string (binary output) -; Return value: Pointer to string containing the converted integer -; Used registers: -; rax* uint stored for div >> (ret) pointer to cnvtBuff[] -; rcx* Counts length of created string -; rdx* (arg) If padLen>0, use Zeroes (rdx!=0) or spaces (rdx=0) >> modulo as calculated by div >> character storage for cnvtBuff -; rdi* (arg) integer to convert to string -; rsi* (arg) Padding length -; r8* Dividor for div -; r9* Points to cnvtBuff for writing characters -; r10* padZeroes arg (since rdx used by DIV) -bin2str: - mov r10, ' ' - mov r9, '0' - test rdx, rdx - cmovnz r10, r9 - lea r9, [rel cnvtBuffRev] - mov rax, rdi - xor rcx, rcx - .convert: - xor rdx, rdx - mov r8, 2 - div r8 - add rdx, '0' - mov [r9], dl - inc r9 - inc rcx - test rax, rax - jnz .convert - sub rsi, rcx - cmp rsi, 0 - jle .noPadding - mov r8, rcx - mov rdi, rsi - xor rsi, rsi - mov rdx, 64 - call clamp - mov rcx, rax - .paddingLoop: - mov byte [r9], r10b - inc r9 - inc r8 - loop .paddingLoop - mov rcx, r8 - .noPadding: - dec r9 + dec r10 ;don't point to past last character lea rdi, [rel cnvtBuff] + mov rcx, r9 + xor rax, rax .makeStringLoop: - mov al, [r9] - mov [rdi], al + mov al, byte [r10] + mov byte [rdi], al inc rdi - dec r9 + dec r10 loop .makeStringLoop - mov byte [rdi], EOS + mov byte [rdi], EOS - .quit: + pop r15 + pop r14 + pop r13 + pop r12 + pop rbx lea rax, [rel cnvtBuff] ret diff --git a/src/tests.asm b/src/tests.asm index e5c2897..ce3ee0f 100644 --- a/src/tests.asm +++ b/src/tests.asm @@ -31,9 +31,7 @@ extern bin2str section .rodata TEST_print equ 1 TEST_puts equ 1 - TEST_dec2str equ 1 ;includes udec2str - TEST_hex2str equ 1 - TEST_bin2str equ 1 + TEST_itoa equ 1 ;includes utoa TEST_printf equ 1 TEST_strlen equ 1 TEST_strcpy equ 1 @@ -61,12 +59,8 @@ section .rodata ; puts() msgPuts db NL,"TEST puts()",EOS - ; START LAZY SECTION - ; [u]dec2str() / hex2str() / bin2str() - msgDec2str db NL,"TEST dec2str() / udec2str()",NL,"See printf outputs",NL,EOS - msgHex2str db NL,"TEST hex2str()",NL,TAB,"See printf outputs",NL,EOS - msgBin2str db NL,"TEST bin2str()",NL,TAB,"See printf outputs",NL,EOS ;Even more lazy - ; END LAZY SECTION + ; itoa() / utoa9) + msgItoa db NL,"TEST itoa() / utoa()",NL,TAB,"See printf outputs",NL,EOS ; printf() msgPrintf db NL,"TEST printf()",NL,EOS @@ -241,69 +235,8 @@ _start: call puts %endif -;--- -;--- dec2str() / udec2str() -;--- -%if TEST_dec2str - lea rdi, [rel msgDec2str] - call print - - ; TEST 1 - mov rdi, -569384 - call dec2str - ; TEST 2 - mov rdi, -569384 - call udec2str - ; TEST 3 - mov rdi, 0xFFFFFFFFFFFFFFFF - call dec2str - ; TEST 4 - mov rdi, 0xFFFFFFFFFFFFFFFF - call udec2str -%endif - -;--- -;--- hex2str() -;--- -%if TEST_hex2str - lea rdi, [rel msgHex2str] - call print - - ; TEST 1 - xor rdi, rdi - mov rsi, 0 - call hex2str - mov rdi, -1 - mov rsi, 0 - call hex2str - - ; TEST 2 - xor rdi, rdi - mov rsi, 1 - call hex2str - mov rdi, -1 - mov rsi, 1 - call hex2str - - ; TEST 3 - mov rdi, 0x123456789ABCDEF - mov rsi, 0 - call hex2str - mov rdi, 0x123456789ABCDEF - mov rsi, 1 - call hex2str - - ; TEST 4 - mov rdi, 128 - mov rsi, 0 - call hex2str -%endif - -;--- -;--- bin2str() -;--- -%if TEST_bin2str - lea rdi, [rel msgBin2str] +%if TEST_itoa + lea rdi, [rel msgItoa] call print %endif