printf: Add padding support for %d, %i, %u, %x, %X

This commit is contained in:
2025-07-12 16:33:07 +02:00
parent b327248e0c
commit efeded5547
3 changed files with 176 additions and 58 deletions

View File

@@ -71,6 +71,8 @@ puts:
; %X Unsigned integer, printed as hexadecimal number (uppercase) ; %X Unsigned integer, printed as hexadecimal number (uppercase)
; %b Unsigned integer, printed as binary number ; %b Unsigned integer, printed as binary number
; %s String ; %s String
; %N* Pad left, N chars (maximum 64). Supported *: d, i, u, x, X, b
; *0N* Pad left with zeroes, N chars (maximum 64). Supported *: d, i, u, x, X, b
; <!> Unsupported specifiers are printed as-is ; <!> Unsupported specifiers are printed as-is
; <!> For all specifiers (except %%) an argument is expected. Mismatch between arguments given and specifiers provided will lead to issues ; <!> For all specifiers (except %%) an argument is expected. Mismatch between arguments given and specifiers provided will lead to issues
; Used registers: ; Used registers:
@@ -236,13 +238,16 @@ printf:
.rep_d: .rep_d:
load_arg rsi load_arg rsi
push_regs push_regs
mov rdx, r13
cmp byte [rdi + 1], 'u' cmp byte [rdi + 1], 'u'
je .callUINT2STR je .callUINT2STR
mov rdi, rsi mov rdi, rsi
mov rsi, r12
call dec2str call dec2str
jmp .loadConvertedStr jmp .loadConvertedStr
.callUINT2STR: .callUINT2STR:
mov rdi, rsi mov rdi, rsi
mov rsi, r12
call udec2str call udec2str
.loadConvertedStr: .loadConvertedStr:
mov rsi, rax mov rsi, rax
@@ -261,8 +266,12 @@ printf:
push rax push rax
push rdx push rdx
push r9 push r9
push r10
mov rdx, r12
mov rcx, r13
call hex2str call hex2str
mov rsi, rax mov rsi, rax
pop r10
pop r9 pop r9
pop rdx pop rdx
pop rax pop rax

View File

@@ -11,26 +11,27 @@ section .text
global hex2str global hex2str
global bin2str global bin2str
;----- dec2str(int) -----; ;----- dec2str(int, padLen, bool padZeroes) -----;
; Converts a signed integer to a string (decimal output) ; Converts a signed integer to a string (decimal output)
; Return value: Pointer to string containing the converted integer ; Return value: Pointer to string containing the converted integer
; Used registers: ; Used registers:
; rax* int stored for div >> (ret) pointer to cnvtBuff[] ; rax* int stored for div >> (ret) pointer to cnvtBuff[]
; rcx* Counts length of created string ; rcx* Counts length of created string
; rdx* modulo as calculated by div >> character storage for cnvtBuff ; rdx* (arg) padZeroes >> modulo as calculated by div >> character storage for cnvtBuff
; rdi* (arg) integer to convert to string >> Remembers if num is negative ; rdi* (arg) integer to convert to string >> Remembers if num is negative
; rsi* Points to cnvtBuff for writing characters ; rsi* (arg) Padding length
; r8* Dividor for div ; r8* Dividor for div
; r9* Points to cnvtBuff[]
; r10* padZeroes arg (since rdx used by DIV)
; r12 Remembers if number is negative
dec2str: dec2str:
lea rsi, [rel cnvtBuffRev] push r12
test rdi, rdi xor r12, r12
jnz .notZero mov r10, ' '
lea rsi, [rel cnvtBuff] mov r9, '0'
mov byte [rsi], '0' test rdx, rdx
mov byte [rsi+1], EOS cmovnz r10, r9
jmp .quit lea r9, [rel cnvtBuffRev]
.notZero:
mov rax, rdi mov rax, rdi
xor dil, dil xor dil, dil
xor rcx, rcx xor rcx, rcx
@@ -43,51 +44,78 @@ dec2str:
mov r8, 10 mov r8, 10
div r8 div r8
add rdx, '0' add rdx, '0'
mov [rsi], dl mov [r9], dl
inc rsi inc r9
inc rcx inc rcx
test rax, rax test rax, rax
jnz .convert jnz .convert
test dil, dil test dil, dil
jz .makeString jz .makeString
mov [rsi], byte '-' mov r12, 1
inc rcx
inc rsi
.makeString: .makeString:
sub rsi, rcx
cmp rsi, rcx
jl .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 rsi dec r9
.makeStringLoop: .makeStringLoop:
mov al, [rsi] mov al, [r9]
mov [rdi], al mov [rdi], al
inc rdi inc rdi
dec rsi dec r9
loop .makeStringLoop loop .makeStringLoop
mov byte [rdi], EOS mov byte [rdi], EOS
.quit: .quit:
lea rax, [rel cnvtBuff] lea rax, [rel cnvtBuff]
pop r12
ret ret
;----- udec2str(uint) -----; ;----- udec2str(uint, padLen, bool padZeroes) -----;
; Converts an unsigned integer to a string (decimal output) ; Converts an unsigned integer to a string (decimal output)
; Return value: Pointer to string containing the converted integer ; Return value: Pointer to string containing the converted integer
; Used registers: ; Used registers:
; rax* uint stored for div >> (ret) pointer to cnvtBuff[] ; rax* uint stored for div >> (ret) pointer to cnvtBuff[]
; rcx* Counts length of created string ; rcx* Counts length of created string
; rdx* modulo as calculated by div >> character storage for cnvtBuff ; rdx* (arg) padZeroes >> modulo as calculated by div
; rdi* (arg) integer to convert to string ; rdi* (arg) integer to convert to string
; rsi* Points to cnvtBuff for writing characters ; rsi* (arg) padLen
; r8* Dividor for div ; r8* Dividor for div
; r9* Points to cnvtBuff for writing characters
; r10* padZeroes arg (since rdx used by DIV)
udec2str: udec2str:
lea rsi, [rel cnvtBuffRev] mov r10, ' '
test rdi, rdi mov r9, '0'
jnz .notZero test rdx, rdx
lea rsi, [rel cnvtBuff] cmovnz r10, r9
mov byte [rsi], '0' lea r9, [rel cnvtBuffRev]
mov byte [rsi+1], EOS
jmp .quit
.notZero:
mov rax, rdi mov rax, rdi
xor rcx, rcx xor rcx, rcx
.convert: .convert:
@@ -95,18 +123,34 @@ udec2str:
mov r8, 10 mov r8, 10
div r8 div r8
add rdx, '0' add rdx, '0'
mov [rsi], dl mov [r9], dl
inc rsi inc r9
inc rcx inc rcx
test rax, rax test rax, rax
jnz .convert jnz .convert
sub rsi, rcx
cmp rsi, rcx
jl .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] lea rdi, [rel cnvtBuff]
dec rsi dec r9
.makeStringLoop: .makeStringLoop:
mov al, [rsi] mov al, [r9]
mov [rdi], al mov [rdi], al
inc rdi inc rdi
dec rsi dec r9
loop .makeStringLoop loop .makeStringLoop
mov byte [rdi], EOS mov byte [rdi], EOS
@@ -114,33 +158,31 @@ udec2str:
lea rax, [rel cnvtBuff] lea rax, [rel cnvtBuff]
ret ret
;----- hex2str(uint, bool uppercase) -----; ;----- hex2str(uint, bool uppercase, padLen, bool padZeroes) -----;
; Converts an unsigned integer to a string (hexadecimal output) ; Converts an unsigned integer to a string (hexadecimal output)
; Return value: Pointer to string containing the converted integer ; Return value: Pointer to string containing the converted integer
; Used registers: ; Used registers:
; rax* uint stored for div >> (ret) Pointer to cnvtBuff[] ; rax* uint stored for div >> (ret) Pointer to cnvtBuff[]
; rdi (arg) Integer to convert ; rdi (arg) Integer to convert
; rsi* (arg) 0=convert lowercase, (any other value)=convert uppercase >> Points to cnvtBuff for writing characters ; rsi* (arg) 0=convert lowercase, (any other value)=convert uppercase >> Points to cnvtBuff for writing characters
; rdx* module as calculated by div ; rdx* (arg) Padding length >> module as calculated by div
; rcx* Counts length of created string ; rcx* (arg) padZeroes >> Counts length of created string
; r8* Dividor for div ; r8* Dividor for div
; r9* Store arg rsi (uppercase) ; r9* Store arg rsi (uppercase)
; r10* Store arg rdx
; r11* Amount to add to number (for ASCII conversion, lowercase or uppercase) ; r11* Amount to add to number (for ASCII conversion, lowercase or uppercase)
; r12 Store arg padZeroes
hex2str: hex2str:
push r12
mov r9, rsi mov r9, rsi
mov r10, rdx
mov r12, ' '
mov rsi, '0'
test rcx, rcx
cmovnz r12, rsi
lea rsi, [rel cnvtBuffRev] lea rsi, [rel cnvtBuffRev]
test rdi, rdi
jnz .notZero
lea rsi, [rel cnvtBuff]
mov word [rsi], '0x'
mov byte [rsi + 2], '0'
mov byte [rsi + 3], EOS
jmp .quit
.notZero:
mov rax, rdi mov rax, rdi
xor rcx, rcx xor rcx, rcx
mov r8, 87 mov r8, 87
test r9, r9 test r9, r9
cmovz r11, r8 cmovz r11, r8
@@ -163,10 +205,25 @@ hex2str:
inc rcx inc rcx
test rax, rax test rax, rax
jnz .convert jnz .convert
sub r10, rcx
mov word [rsi], 'x0' cmp r10, rcx
jl .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 rsi
add rcx, 2 inc r8
loop .paddingLoop
mov rcx, r8
.noPadding:
dec rsi
lea rdi, [rel cnvtBuff] lea rdi, [rel cnvtBuff]
.makeString: .makeString:
mov al, [rsi] mov al, [rsi]
@@ -178,6 +235,7 @@ hex2str:
.quit: .quit:
lea rax, [rel cnvtBuff] lea rax, [rel cnvtBuff]
pop r12
ret ret
;----- bin2str(uint, padLen, bool padZeroes) -----; ;----- bin2str(uint, padLen, bool padZeroes) -----;
@@ -223,14 +281,10 @@ bin2str:
cmp rsi, rcx cmp rsi, rcx
jl .noPadding jl .noPadding
mov r8, rcx mov r8, rcx
push rsi
push rdx
mov rdi, rsi mov rdi, rsi
xor rsi, rsi xor rsi, rsi
mov rdx, 64 mov rdx, 64
call clamp call clamp
pop rdx
pop rsi
mov rcx, rax mov rcx, rax
.paddingLoop: .paddingLoop:
mov byte [r9], r10b mov byte [r9], r10b

View File

@@ -92,6 +92,16 @@ section .rodata
printf5Str db "%x|%X , %x|%X",NL,EOS printf5Str db "%x|%X , %x|%X",NL,EOS
printf6 db TAB,"printf(",DQUO,"%b | %8b | %08b\n",DQUO,", 5, 5, 5): ",NL,TAB,TAB,EOS printf6 db TAB,"printf(",DQUO,"%b | %8b | %08b\n",DQUO,", 5, 5, 5): ",NL,TAB,TAB,EOS
printf6Str db "%b | %8b | %08b",NL,EOS printf6Str db "%b | %8b | %08b",NL,EOS
printf7 db TAB,"printf(",DQUO,"%d | %8d | %08d\n",DQUO,", -234, -234, -234): ",NL,TAB,TAB,EOS
printf7Str db "%d | %8d | %08d",NL,EOS
printf8 db TAB,"printf(",DQUO,"%i | %8i | %08i\n",DQUO,", -234, -234, -234): ",NL,TAB,TAB,EOS
printf8Str db "%i | %8i | %08i",NL,EOS
printf9 db TAB,"printf(",DQUO,"%u | %8u | %08u\n",DQUO,", -234, -234, -234): ",NL,TAB,TAB,EOS
printf9Str db "%u | %8u | %08u",NL,EOS
printf10 db TAB,"printf(",DQUO,"%x | %8x | %08x\n",DQUO,", 0xAB0F, -0xAB0F, 0xAB0F): ",NL,TAB,TAB,EOS
printf10Str db "%x | %8x | %08x",NL,EOS
printf11 db TAB,"printf(",DQUO,"%X | %8X | %08X\n",DQUO,", 0xAB0F, -0xAB0F, 0xAB0F): ",NL,TAB,TAB,EOS
printf11Str db "%X | %8X | %08X",NL,EOS
; strlen() ; strlen()
msgStrlen db NL,"TEST strlen()",NL,EOS msgStrlen db NL,"TEST strlen()",NL,EOS
@@ -350,6 +360,51 @@ _start:
mov rdx, 5 mov rdx, 5
mov rcx, 5 mov rcx, 5
call printf call printf
; TEST 7
lea rdi, [rel printf7]
call print
lea rdi, [rel printf7Str]
mov rsi, -234
mov rdx, -234
mov rcx, -234
call printf
; TEST 8
lea rdi, [rel printf8]
call print
lea rdi, [rel printf8Str]
mov rsi, -234
mov rdx, -234
mov rcx, -234
call printf
; TEST 9
lea rdi, [rel printf9]
call print
lea rdi, [rel printf9Str]
mov rsi, -234
mov rdx, -234
mov rcx, -234
call printf
; TEST 10
lea rdi, [rel printf10]
call print
lea rdi, [rel printf10Str]
mov rsi, 0xAB0F
mov rdx, 0xAB0F
mov rcx, 0xAB0F
call printf
; TEST 11
lea rdi, [rel printf11]
call print
lea rdi, [rel printf11Str]
mov rsi, 0xAB0F
mov rdx, 0xAB0F
mov rcx, 0xAB0F
call printf
%endif %endif
;--- ;---