Allow printing prefixes for %x,%X,%b and %o (pass ~base to udec)

This commit is contained in:
2025-07-15 16:31:52 +02:00
parent 87fd5d815a
commit 70ab8b19c3
3 changed files with 111 additions and 15 deletions

View File

@@ -70,8 +70,9 @@ puts:
; %b Unsigned integer, printed as binary number ; %b Unsigned integer, printed as binary number
; %o Unsigned integer, printed as octal number ; %o Unsigned integer, printed as octal number
; %s String ; %s String
; %N* Pad left, N chars (maximum 64). Supported specifiers: d, i, u, x, X, b, o ; %#{x} Use prefix for printed number (non-decimal). Supported specifiers: x, X, b, o. Works in combination with width specifier (see below)
; *0N* Pad left with zeroes, N chars (maximum 64). Supported specifiers: d, i, u, x, X, b, o ; %[#]n* Pad left, n chars (maximum 64). Supported specifiers: d, i, u, x, X, b, o
; *[#]0n* Pad left with zeroes, n chars (maximum 64). Supported specifiers: d, i, u, x, X, b, o
; <!> 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
; ;
@@ -91,6 +92,8 @@ puts:
; r12 Padding for numbers (0=nopadding, >0=padding w/ spaces, NOT >0=padding w/ zeroes) ; r12 Padding for numbers (0=nopadding, >0=padding w/ spaces, NOT >0=padding w/ zeroes)
; r13 Padding: zeroes (=1) or spaces (=0) ; r13 Padding: zeroes (=1) or spaces (=0)
; r14 Keeps track of amount of processed format specifiers ; r14 Keeps track of amount of processed format specifiers
; r15 Include prefix for specifiers (1=yes, 0=no)
;<!> TODO: Keep r13 and r15 in one register (use bitmasking to determine whether to pad with zeroes or spaces and whether to include prefix)
printf: printf:
%macro load_arg 1 %macro load_arg 1
cmp r14, 4 cmp r14, 4
@@ -124,7 +127,13 @@ printf:
load_arg rsi load_arg rsi
push_regs push_regs
mov rdi, rsi mov rdi, rsi
test r15, r15
jz %%baseNormal
mov rsi, ~%1
jmp %%args
%%baseNormal:
mov rsi, %1 mov rsi, %1
%%args:
mov rdx, r12 mov rdx, r12
mov rcx, r13 mov rcx, r13
mov r8, %2 mov r8, %2
@@ -140,7 +149,7 @@ printf:
push r12 push r12
push r13 push r13
push r14 push r14
sub rsp, SIZE_QWORD push r15
cmp byte [rdi], EOS cmp byte [rdi], EOS
je .emptyStr je .emptyStr
@@ -156,6 +165,7 @@ printf:
xor r10, r10 xor r10, r10
xor r11, r11 xor r11, r11
xor r14, r14 xor r14, r14
xor r15, r15
.process: .process:
cmp byte [rdi], EOS cmp byte [rdi], EOS
@@ -206,6 +216,14 @@ printf:
je .wrapup je .wrapup
cmp byte [rdi + 1], '%' cmp byte [rdi + 1], '%'
je .rep_pct je .rep_pct
; Include specifier (r15=1) or not (r15=0)
xor r15, r15
cmp byte [rdi + 1], '#'
jne .argGetPadZeroes
inc rdi
mov r15, 1
; Padding: zeroes (r13=1) or spaces (r13=0)
.argGetPadZeroes:
xor r13, r13 xor r13, r13
mov r12, 1 mov r12, 1
cmp byte [rdi + 1], '0' cmp byte [rdi + 1], '0'
@@ -384,7 +402,7 @@ printf:
xor rax, rax xor rax, rax
.quit: .quit:
add rsp, SIZE_QWORD pop r15
pop r14 pop r14
pop r13 pop r13
pop r12 pop r12

View File

@@ -30,8 +30,13 @@ itoa:
; Before doing anything, check if base is valid ; Before doing anything, check if base is valid
cmp rsi, 10 cmp rsi, 10
je .ok je .ok
cmp rsi, ~10
je .negBase
xor rax, rax xor rax, rax
ret ret
.negBase:
not rsi
.ok: .ok:
push r12 push r12
push r13 push r13
@@ -122,24 +127,54 @@ itoa:
;----- utoa(int, base, padLen, bool padZeroes, bool upperCase) -----; ;----- utoa(int, base, padLen, bool padZeroes, bool upperCase) -----;
; Converts an unsigned integer to a string ; Converts an unsigned integer to a string
; Return value: Pointer to converted string or 0(EOS) if entered base is invalid ; Return value: Pointer to converted string or 0(EOS) if entered base is invalid.
; <!> To use prefix (ie 0x, 0b or 0o), pass ~base instead of base
; Supported bases: 2 (binary), 8, (octal), 10 (decimal), 16 (hexadecimal) ; Supported bases: 2 (binary), 8, (octal), 10 (decimal), 16 (hexadecimal)
; Used registers: ; Used registers:
; rax* num to divide (DIV) >> Copy bytes when reversing string >> (ret) Pointer to converted string ; rax* num to divide (DIV) >> Copy bytes when reversing string >> (ret) Pointer to converted string
; rbx Stores (upperCase) ; rbx Stores (upperCase)
; rdi* (arg) Integer to convert ; rdi* (arg) Integer to convert >> base (positive) >> pointer to cnvtBuff[]
; rsi* (arg) Base to convert to ; *rsi (arg) Base to convert to
; rdx* (arg) Padding length >> modulo (DIV) ; *rdx (arg) Padding length >> modulo (DIV)
; rcx* (arg) 0=pad spaces, otherwise pad zeroes >> Loop counter ; *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 ; *r8 (arg) 0=lowercase letters (for bases using letters, ie 16), uppercase otherwise >> Stores padding character >> used for inserting prefix
; r9* Counts string length ; r9* Counts string length
; r10* Points to cnvtBuff(Rev)[] ; r10* Points to cnvtBuff(Rev)[]
; r11* Remembers if number is negative (r11b) ; *r11 Stores padZeroes
; r12 Stores (int) ; r12 Stores (int)
; r13 Stores (base) ; r13 Stores (base)
; r14 Stores (padLen) ; r14 Stores (padLen)
; r15 Stores (padZeroes) ; r15 Stores (padZeroes)
utoa: utoa:
%macro insert_prefix 0
xor r8, r8
xor rsi, rsi
mov r8, 'x0'
cmp rdi, 16
cmove rsi, r8
je %%insert
mov r8, 'o0'
cmp rdi, 8
cmove rsi, r8
je %%insert
cmp rdi, 2
jne %%continue
mov rsi, 'b0'
%%insert:
mov word [r10], si
add r10, 2
add r9, 2
%%continue:
;nop
%endmacro
;;
;; ENTRY
;;
; Before doing anything, check if base is valid ; Before doing anything, check if base is valid
cmp rsi, 2 cmp rsi, 2
je .ok je .ok
@@ -149,8 +184,19 @@ utoa:
je .ok je .ok
cmp rsi, 16 cmp rsi, 16
je .ok je .ok
cmp rsi, ~16
je .ok
cmp rsi, ~10
je .negBase
cmp rsi, ~8
je .ok
cmp rsi, ~2
je .ok
xor rax, rax xor rax, rax
ret ret
.negBase:
not rsi
.ok: .ok:
push rbx push rbx
push r12 push r12
@@ -174,8 +220,13 @@ utoa:
mov rdx, '0' mov rdx, '0'
test r15, r15 test r15, r15
cmovnz rdi, rdx cmovnz rdi, rdx
mov r15, rdi mov r11, rdi
; Prepare for conversion ; Prepare for conversion
mov rdi, r13
test r13, r13
jns .continuePrepare
not rdi
.continuePrepare:
mov rax, r12 mov rax, r12
xor r9, r9 xor r9, r9
lea r10, [rel cnvtBuffRev] lea r10, [rel cnvtBuffRev]
@@ -186,7 +237,7 @@ utoa:
mov r8, 'A'-10 mov r8, 'A'-10
.convert: .convert:
xor rdx, rdx xor rdx, rdx
div r13 div rdi
cmp dl, 9 cmp dl, 9
jle .noLetter jle .noLetter
add dl, r8b add dl, r8b
@@ -199,17 +250,31 @@ utoa:
inc r9 inc r9
test rax, rax test rax, rax
jnz .convert jnz .convert
; Insert prefix if needed
test r13, r13 ;prefix needed? (MSB not set)
jns .checkPadding
test r15, r15 ;prefix now? (padding with spaces; r15 is zero)
jnz .checkPadding
insert_prefix
.checkPadding: .checkPadding:
; Substract length of converted number from padLen ; Substract length of converted number from padLen
sub r14, r9 sub r14, r9
cmp r14, 0 cmp r14, 0
jle .makeString jle .checkPrefix
mov rcx, r14 mov rcx, r14
.addPadding: .addPadding:
mov byte [r10], r15b mov byte [r10], r11b
inc r10 inc r10
inc r9 inc r9
loop .addPadding loop .addPadding
; Insert prefix if needed
.checkPrefix:
test r13, r13 ;prefix needed? (MSB not set)
jns .makeString
test r15, r15 ;prefix now? (padding with zeroes; r15 is not zero)
jz .makeString
insert_prefix
.makeString: .makeString:
dec r10 ;don't point to past last character dec r10 ;don't point to past last character
lea rdi, [rel cnvtBuff] lea rdi, [rel cnvtBuff]

View File

@@ -99,6 +99,8 @@ section .rodata
printf12Str db "\nRAX\t%064b\nEAX\t\t\t\t\t%032b\n AX\t\t\t\t\t\t\t%016b\n AH\t\t\t\t\t\t\t%08b\t\n AL\t\t\t\t\t\t\t\t%08b\n",EOS printf12Str db "\nRAX\t%064b\nEAX\t\t\t\t\t%032b\n AX\t\t\t\t\t\t\t%016b\n AH\t\t\t\t\t\t\t%08b\t\n AL\t\t\t\t\t\t\t\t%08b\n",EOS
printf13 db TAB,"printf(",DQUO,"%o | %8o | %08o\n",DQUO,", 1500, 1500, 1500): ",NL,TAB,TAB,EOS printf13 db TAB,"printf(",DQUO,"%o | %8o | %08o\n",DQUO,", 1500, 1500, 1500): ",NL,TAB,TAB,EOS
printf13Str db "%o | %8o | %08o\n",EOS printf13Str db "%o | %8o | %08o\n",EOS
printf14 db TAB,"printf(",DQUO,"%#b | %#08b | %#x | %#8X\n | %#o",DQUO,", 8, 8, 0xABCDEF, 0x12345678, 15): ",NL,TAB,TAB,EOS
printf14Str db "%#b | %#08b | %#x | %#8X | %#o\n",EOS
; strlen() ; strlen()
msgStrlen db NL,"TEST strlen()",NL,EOS msgStrlen db NL,"TEST strlen()",NL,EOS
@@ -383,6 +385,17 @@ _start:
mov rdx, 1500 mov rdx, 1500
mov rcx, 1500 mov rcx, 1500
call printf call printf
; TEST 14
lea rdi, [rel printf14]
call print
lea rdi, [rel printf14Str]
mov rsi, 8
mov rdx, 8
mov rcx, 0xABCDEF
mov r8, 0x12345678
mov r9, 15
call printf
%endif %endif
;--- ;---