My colleague asked me if there is a printf
-like function in C/C++ which would provide him a way of printing an array of various values according to some format line. No function has been found so far, but aren't we DEVELOPERS ourselves?
There's a System V 64-bit ABI compatible function which takes a format string
, list of arguments, and passes them into the libc sprintf
function.
Not safe for work.
The code below is dangerous and should NEVER be used not only in the production environment, but also not 50 miles closer to any of the social infrastructure objects.
Weird 64-bit ABI may be a headache: where have those old cdecl times gone when we could put everything on stack and let nature do the rest?
.text
.globl lsprintf
.type lsprintf, @function
lsprintf:
# Arguments parsing
# rdi Stores output string address
# rsi Stores format string address
mov %rdx, %rax # list pointer
mov %rcx, %r10 # number of arguments
push %rbx
push %r12
mov %rcx, %rbx # Callee-saved register, we need this
# to clear stack in accordance with cdecl convension
# Let the party start!
cmp $0, %r10
je do_call
cmp $1, %r10
jl do_call
mov 0(%rax), %rdx
add $8, %rax
cmp $2, %r10
jl do_call
mov 0(%rax), %rcx
add $8, %rax
cmp $3, %r10
jl do_call
mov 0(%rax), %r8
add $8, %rax
cmp $4, %r10
jl do_call
mov 0(%rax), %r9
add $8, %rax
cmp $5, %r10
jl do_call
sub $4, %r10 # Do not count arguments saved in registers
mov %rcx, %r11 # We need this rcx register
mov %r10, %rcx
mov %rax, %r12 # We will multiply!
mov $8, %rax
push %rdx
mul %rcx # rax contains number of bytes to the end of arguments list
pop %rdx
add %rax, %r12
sub $8, %r12
mov %r12, %rax
start_loop:
push 0(%rax)
sub $8, %rax
loop start_loop
mov %r11, %rcx
do_call:
mov $0, %rax # Number of floating point arguments passed
call sprintf
cmp $5, %rbx
jl f_end
sub $4, %rbx
mov %rax, %r9
mov %rbx, %rax
mov $8, %rdx
push %rdx
mul %rdx # 64-bit values
pop %rdx
add %rax, %rsp
mov %r9, %rax
f_end:
pop %r12
pop %rbx
ret