Allow printing prefixes for %x,%X,%b and %o (pass ~base to udec)
This commit is contained in:
@@ -70,8 +70,9 @@ puts:
|
||||
; %b Unsigned integer, printed as binary number
|
||||
; %o Unsigned integer, printed as octal number
|
||||
; %s String
|
||||
; %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
|
||||
; %#{x} Use prefix for printed number (non-decimal). Supported specifiers: x, X, b, o. Works in combination with width specifier (see below)
|
||||
; %[#]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
|
||||
; <!> 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)
|
||||
; r13 Padding: zeroes (=1) or spaces (=0)
|
||||
; 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:
|
||||
%macro load_arg 1
|
||||
cmp r14, 4
|
||||
@@ -124,7 +127,13 @@ printf:
|
||||
load_arg rsi
|
||||
push_regs
|
||||
mov rdi, rsi
|
||||
test r15, r15
|
||||
jz %%baseNormal
|
||||
mov rsi, ~%1
|
||||
jmp %%args
|
||||
%%baseNormal:
|
||||
mov rsi, %1
|
||||
%%args:
|
||||
mov rdx, r12
|
||||
mov rcx, r13
|
||||
mov r8, %2
|
||||
@@ -140,7 +149,7 @@ printf:
|
||||
push r12
|
||||
push r13
|
||||
push r14
|
||||
sub rsp, SIZE_QWORD
|
||||
push r15
|
||||
|
||||
cmp byte [rdi], EOS
|
||||
je .emptyStr
|
||||
@@ -156,6 +165,7 @@ printf:
|
||||
xor r10, r10
|
||||
xor r11, r11
|
||||
xor r14, r14
|
||||
xor r15, r15
|
||||
|
||||
.process:
|
||||
cmp byte [rdi], EOS
|
||||
@@ -206,6 +216,14 @@ printf:
|
||||
je .wrapup
|
||||
cmp byte [rdi + 1], '%'
|
||||
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
|
||||
mov r12, 1
|
||||
cmp byte [rdi + 1], '0'
|
||||
@@ -384,7 +402,7 @@ printf:
|
||||
xor rax, rax
|
||||
|
||||
.quit:
|
||||
add rsp, SIZE_QWORD
|
||||
pop r15
|
||||
pop r14
|
||||
pop r13
|
||||
pop r12
|
||||
|
@@ -30,8 +30,13 @@ itoa:
|
||||
; Before doing anything, check if base is valid
|
||||
cmp rsi, 10
|
||||
je .ok
|
||||
|
||||
cmp rsi, ~10
|
||||
je .negBase
|
||||
xor rax, rax
|
||||
ret
|
||||
.negBase:
|
||||
not rsi
|
||||
.ok:
|
||||
push r12
|
||||
push r13
|
||||
@@ -122,24 +127,54 @@ itoa:
|
||||
|
||||
;----- 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
|
||||
; 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)
|
||||
; Used registers:
|
||||
; 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
|
||||
; rdi* (arg) Integer to convert >> base (positive) >> pointer to cnvtBuff[]
|
||||
; *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 padding character >> used for inserting prefix
|
||||
; r9* Counts string length
|
||||
; r10* Points to cnvtBuff(Rev)[]
|
||||
; r11* Remembers if number is negative (r11b)
|
||||
; *r11 Stores padZeroes
|
||||
; r12 Stores (int)
|
||||
; r13 Stores (base)
|
||||
; r14 Stores (padLen)
|
||||
; r15 Stores (padZeroes)
|
||||
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
|
||||
cmp rsi, 2
|
||||
je .ok
|
||||
@@ -149,8 +184,19 @@ utoa:
|
||||
je .ok
|
||||
cmp rsi, 16
|
||||
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
|
||||
ret
|
||||
.negBase:
|
||||
not rsi
|
||||
.ok:
|
||||
push rbx
|
||||
push r12
|
||||
@@ -174,8 +220,13 @@ utoa:
|
||||
mov rdx, '0'
|
||||
test r15, r15
|
||||
cmovnz rdi, rdx
|
||||
mov r15, rdi
|
||||
mov r11, rdi
|
||||
; Prepare for conversion
|
||||
mov rdi, r13
|
||||
test r13, r13
|
||||
jns .continuePrepare
|
||||
not rdi
|
||||
.continuePrepare:
|
||||
mov rax, r12
|
||||
xor r9, r9
|
||||
lea r10, [rel cnvtBuffRev]
|
||||
@@ -186,7 +237,7 @@ utoa:
|
||||
mov r8, 'A'-10
|
||||
.convert:
|
||||
xor rdx, rdx
|
||||
div r13
|
||||
div rdi
|
||||
cmp dl, 9
|
||||
jle .noLetter
|
||||
add dl, r8b
|
||||
@@ -199,17 +250,31 @@ utoa:
|
||||
inc r9
|
||||
test rax, rax
|
||||
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:
|
||||
; Substract length of converted number from padLen
|
||||
sub r14, r9
|
||||
cmp r14, 0
|
||||
jle .makeString
|
||||
jle .checkPrefix
|
||||
mov rcx, r14
|
||||
.addPadding:
|
||||
mov byte [r10], r15b
|
||||
mov byte [r10], r11b
|
||||
inc r10
|
||||
inc r9
|
||||
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:
|
||||
dec r10 ;don't point to past last character
|
||||
lea rdi, [rel cnvtBuff]
|
||||
|
@@ -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
|
||||
printf13 db TAB,"printf(",DQUO,"%o | %8o | %08o\n",DQUO,", 1500, 1500, 1500): ",NL,TAB,TAB,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()
|
||||
msgStrlen db NL,"TEST strlen()",NL,EOS
|
||||
@@ -383,6 +385,17 @@ _start:
|
||||
mov rdx, 1500
|
||||
mov rcx, 1500
|
||||
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
|
||||
|
||||
;---
|
||||
|
Reference in New Issue
Block a user