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" %include "src/constants.asm"
extern strlen extern strlen
extern dec2str extern itoa
extern udec2str extern utoa
extern hex2str
extern bin2str
section .rodata section .rodata
mNL db NL mNL db NL
@@ -104,17 +102,21 @@ printf:
%endmacro %endmacro
%macro push_regs 0 %macro push_regs 0
sub rsp, SIZE_QWORD
push rax push rax
push rdi push rdi
push r9 push r9
push r10 push r10
push r11
%endmacro %endmacro
%macro pop_regs 0 %macro pop_regs 0
pop r11
pop r10 pop r10
pop r9 pop r9
pop rdi pop rdi
pop rax pop rax
add rsp, SIZE_QWORD
%endmacro %endmacro
; entry: ; entry:
@@ -271,44 +273,40 @@ printf:
.rep_d: .rep_d:
load_arg rsi load_arg rsi
push_regs push_regs
mov rdx, r13 mov rdx, r12
mov rcx, r13
cmp byte [rdi + 1], 'u' cmp byte [rdi + 1], 'u'
je .callUINT2STR je .callUTOA
mov rdi, rsi mov rdi, rsi
mov rsi, r12 mov rsi, 10
call dec2str call itoa
jmp .loadConvertedStr jmp .pr
.callUINT2STR: .callUTOA:
mov rdi, rsi mov rdi, rsi
mov rsi, r12 mov rsi, 10
call udec2str mov r8, 0
.loadConvertedStr: call utoa
.pr:
mov rsi, rax mov rsi, rax
pop_regs pop_regs
jmp .insertString jmp .insertString
;--- '%x' / '%X' ---; ;--- '%x' / '%X' ---;
.rep_x: .rep_x:
push rdi load_arg rsi
load_arg rcx push_regs
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
mov rdx, r12 mov rdx, r12
mov rcx, r13 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 mov rsi, rax
pop r10 pop_regs
pop r9
pop rdx
pop rax
pop rdi
jmp .insertString jmp .insertString
;--- '%b' ---; ;--- '%b' ---;
@@ -316,9 +314,11 @@ printf:
load_arg rsi load_arg rsi
push_regs push_regs
mov rdi, rsi mov rdi, rsi
mov rsi, r12 mov rsi, 2
mov rdx, r13 mov rdx, r12
call bin2str mov rcx, r13
mov r8, 0
call utoa
mov rsi, rax mov rsi, rax
pop_regs pop_regs
jmp .insertString jmp .insertString

View File

@@ -6,294 +6,225 @@ section .bss
cnvtBuff resb 67 cnvtBuff resb 67
cnvtBuffRev resb 67 cnvtBuffRev resb 67
section .text section .text
global dec2str global itoa
global udec2str global utoa
global hex2str
global bin2str
;----- dec2str(int, padLen, bool padZeroes) -----; ;----- itoa(int, base, padLen, bool padZeroes) -----;
; Converts a signed integer to a string (decimal output) ; Converts a signed integer to a string
; Return value: Pointer to string containing the converted integer ; Return value: Pointer to converted string or 0(EOS) if entered base is invalid
; Supported bases: 10 (decimal)
; Used registers: ; Used registers:
; rax* int stored for div >> (ret) pointer to cnvtBuff[] ; rax* num to divide (DIV) >> Copy bytes when reversing string >> (ret) Pointer to converted string
; rcx* Counts length of created string ; rdi* (arg) Integer to convert
; rdx* (arg) padZeroes >> modulo as calculated by div >> character storage for cnvtBuff ; rsi* (arg) Base to convert to
; rdi* (arg) integer to convert to string >> Remembers if num is negative ; rdx* (arg) Padding length >> modulo (DIV)
; rsi* (arg) Padding length ; rcx* (arg) 0=pad spaces, otherwise pad zeroes >> Loop counter
; r8* Dividor for div ; r9* Counts string length
; r9* Points to cnvtBuff[] ; r10* Points to cnvtBuff(Rev)[]
; r10* padZeroes arg (since rdx used by DIV) ; r11* Remembers if number is negative (r11b)
; r12 Remembers if number is negative ; r12 Stores (int)
dec2str: ; 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 push r12
xor r12, r12 push r13
mov r10, ' ' push r14
mov r9, '0' push r15
test rdx, rdx ; Store original arguments
cmovnz r10, r9 mov r12, rdi
lea r9, [rel cnvtBuffRev] mov r13, rsi
mov rax, rdi mov r14, rdx
xor dil, dil mov r15, rcx
xor rcx, 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 test rax, rax
jns .convert jns .convert
mov r11b, 1
neg rax neg rax
mov dil, 1
.convert: .convert:
xor rdx, rdx xor rdx, rdx
mov r8, 10 div r13
div r8
add rdx, '0' add rdx, '0'
mov [r9], dl mov byte [r10], dl
inc r10
inc r9 inc r9
inc rcx
test rax, rax test rax, rax
jnz .convert jnz .convert
test dil, dil ; Adds '-' if needed
jz .makeString cmp r15, '0'
mov r12, 1 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: .makeString:
sub rsi, rcx dec r10 ;don't point to past last character
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:
lea rdi, [rel cnvtBuff] lea rdi, [rel cnvtBuff]
dec r9 mov rcx, r9
xor rax, rax
.makeStringLoop: .makeStringLoop:
mov al, [r9] mov al, byte [r10]
mov [rdi], al mov byte [rdi], al
inc rdi inc rdi
dec r9 dec r10
loop .makeStringLoop loop .makeStringLoop
mov byte [rdi], EOS mov byte [rdi], EOS
.quit: pop r15
lea rax, [rel cnvtBuff] pop r14
pop r13
pop r12 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] lea rax, [rel cnvtBuff]
ret ret
;----- hex2str(uint, bool uppercase, padLen, bool padZeroes) -----; ;----- utoa(int, base, padLen, bool padZeroes, bool upperCase) -----;
; Converts an unsigned integer to a string (hexadecimal output) ; Converts an unsigned integer to a string
; Return value: Pointer to string containing the converted integer ; Return value: Pointer to converted string or 0(EOS) if entered base is invalid
; Supported bases: 2 (binary), 10 (decimal), 16 (hexadecimal)
; Used registers: ; Used registers:
; rax* uint stored for div >> (ret) Pointer to cnvtBuff[] ; rax* num to divide (DIV) >> Copy bytes when reversing string >> (ret) Pointer to converted string
; rdi (arg) Integer to convert ; rbx Stores (upperCase)
; rsi* (arg) 0=convert lowercase, (any other value)=convert uppercase >> Points to cnvtBuff for writing characters ; rdi* (arg) Integer to convert
; rdx* (arg) Padding length >> module as calculated by div ; rsi* (arg) Base to convert to
; rcx* (arg) padZeroes >> Counts length of created string ; rdx* (arg) Padding length >> modulo (DIV)
; r8* Dividor for div ; rcx* (arg) 0=pad spaces, otherwise pad zeroes >> Loop counter
; r9* Store arg rsi (uppercase) ; 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
; r10* Store arg rdx ; r9* Counts string length
; r11* Amount to add to number (for ASCII conversion, lowercase or uppercase) ; r10* Points to cnvtBuff(Rev)[]
; r12 Store arg padZeroes ; r11* Remembers if number is negative (r11b)
hex2str: ; 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 push r12
mov r9, rsi push r13
mov r10, rdx push r14
mov r12, ' ' push r15
mov rsi, '0' ; Store original arguments
test rcx, rcx mov rbx, r8
cmovnz r12, rsi mov r12, rdi
lea rsi, [rel cnvtBuffRev] mov r13, rsi
mov rax, rdi mov r14, rdx
xor rcx, rcx mov r15, rcx
mov r8, 87 ; First, assure 0 <= padLen <= 64 ;(64, even though max signed int64 = 19 characters; enables to pad with base 2)
test r9, r9 mov rdi, rdx
cmovz r11, r8 xor rsi, rsi
test r9, r9 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 jz .convert
mov r11, 55 mov r8, 'A'-10
.convert: .convert:
xor rdx, rdx xor rdx, rdx
mov r8, 16 div r13
div r8 cmp dl, 9
cmp rdx, 10 jle .noLetter
jb .num add dl, r8b
add rdx, r11 jmp .write
jmp .push .noLetter:
.num: add dl, '0'
add rdx, '0' .write:
.push: mov byte [r10], dl
mov [rsi], dl inc r10
inc rsi inc r9
inc rcx
test rax, rax test rax, rax
jnz .convert jnz .convert
sub r10, rcx .checkPadding:
cmp r10, 0 ; Substract length of converted number from padLen
jle .noPadding sub r14, r9
mov r8, rcx cmp r14, 0
push rsi jle .makeString
mov rdi, r10 mov rcx, r14
xor rsi, rsi .addPadding:
mov rdx, 64 mov byte [r10], r15b
call clamp inc r10
pop rsi inc r9
mov rcx, rax loop .addPadding
.paddingLoop:
mov byte[rsi], r12b
inc rsi
inc r8
loop .paddingLoop
mov rcx, r8
.noPadding:
dec rsi
lea rdi, [rel cnvtBuff]
.makeString: .makeString:
mov al, [rsi] dec r10 ;don't point to past last character
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
lea rdi, [rel cnvtBuff] lea rdi, [rel cnvtBuff]
mov rcx, r9
xor rax, rax
.makeStringLoop: .makeStringLoop:
mov al, [r9] mov al, byte [r10]
mov [rdi], al mov byte [rdi], al
inc rdi inc rdi
dec r9 dec r10
loop .makeStringLoop 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] lea rax, [rel cnvtBuff]
ret ret

View File

@@ -31,9 +31,7 @@ extern bin2str
section .rodata section .rodata
TEST_print equ 1 TEST_print equ 1
TEST_puts equ 1 TEST_puts equ 1
TEST_dec2str equ 1 ;includes udec2str TEST_itoa equ 1 ;includes utoa
TEST_hex2str equ 1
TEST_bin2str equ 1
TEST_printf equ 1 TEST_printf equ 1
TEST_strlen equ 1 TEST_strlen equ 1
TEST_strcpy equ 1 TEST_strcpy equ 1
@@ -61,12 +59,8 @@ section .rodata
; puts() ; puts()
msgPuts db NL,"TEST puts()",EOS msgPuts db NL,"TEST puts()",EOS
; START LAZY SECTION ; itoa() / utoa9)
; [u]dec2str() / hex2str() / bin2str() msgItoa db NL,"TEST itoa() / utoa()",NL,TAB,"See printf outputs",NL,EOS
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
; printf() ; printf()
msgPrintf db NL,"TEST printf()",NL,EOS msgPrintf db NL,"TEST printf()",NL,EOS
@@ -241,69 +235,8 @@ _start:
call puts call puts
%endif %endif
;--- %if TEST_itoa
;--- dec2str() / udec2str() lea rdi, [rel msgItoa]
;---
%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]
call print call print
%endif %endif