Rewrite X2str functions to itoa/utoa ; it was a stupid idea to have seperate functions (=> more maintenance)

This commit is contained in:
2025-07-15 07:58:18 +02:00
parent 954bc21eee
commit 9f33e36883
3 changed files with 223 additions and 359 deletions

View File

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

View File

@@ -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
; 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 r12, 1
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
.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
.quit:
pop r15
pop r14
pop r13
pop r12
pop rbx
lea rax, [rel cnvtBuff]
ret

View File

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