Skip to content

Commit

Permalink
Support passing registers to printf
Browse files Browse the repository at this point in the history
  • Loading branch information
ChillerDragon committed Aug 8, 2024
1 parent 8cd5504 commit 0cb7e3d
Show file tree
Hide file tree
Showing 3 changed files with 29 additions and 86 deletions.
4 changes: 4 additions & 0 deletions src/bss/buffers.asm
Original file line number Diff line number Diff line change
@@ -1,2 +1,6 @@
generic_buffer_512 resb 512

printf_arg_1_buf resb 8
printf_arg_2_buf resb 8
printf_arg_3_buf resb 8

104 changes: 18 additions & 86 deletions src/printf.asm
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,12 @@
%xdefine num_args %count(%{2:-1})

%if num_args == 1
printf_args_1 %1, %{2:-1}
mov qword [printf_arg_1_buf], %{2:2}
printf_args_2 %1, 1
%elif num_args == 2
printf_args_2 %1, %{2:-1}
mov qword [printf_arg_1_buf], %{2:2}
mov qword [printf_arg_2_buf], %{3:3}
printf_args_2 %1, 2
%else
jmp %%error_many_args
%endif
Expand All @@ -37,88 +40,9 @@
pop_registers
%endmacro

; ARGS 1

%macro printf_args_1 2
; printdf [format str] [int]
push_registers

; TODO: do not segfault when we write out of those bounds
%define MAX_PRINTF_LEN 2048

; rax = is null terminated format str
str_to_stack %1

sub rsp, MAX_PRINTF_LEN
; r10 is index in final output string
mov r10, 0
; r11 is pointer to start of output string
lea r11, [rbp-MAX_PRINTF_LEN]

mov rcx, 0
%%printf_fmt_char_loop:
mov r9b, byte [rax+rcx]
inc rcx

; copy one letter from the format string
; to the output buffer
mov byte [r11+r10], r9b
inc r10

cmp r9b, '%'
jne %%printf_fmt_char_loop_check_repeat

%%printf_fmt_char_loop_got_percentage:
mov r9b, byte [rax+rcx]
cmp r9b, 'd'
jne %%printf_fmt_char_loop_check_repeat

%%printf_fmt_char_loop_got_fmt_d:

; overwrite the %d
dec r10
inc rcx

push rax
push rdi

mov rax, %2
lea rdi, [r11+r10]
call int32_to_str
add r10, rax

pop rdi
pop rax
%%printf_fmt_char_loop_check_repeat:

cmp r9b, 0
jne %%printf_fmt_char_loop

; print output buffer
dec r10
printn r11, r10

; frees stack string
; and copy buffer
mov rsp, rbp

; TODO: support \n escape sequence
call print_newline

pop_registers
%endmacro

; ARGS 2

; this is basically a copy of args 1
; there has to be a neater way to do this
;
; if it wasnt a macro but a function
; it could partially replace only one argument at a time
; and then it could be called recursively

%macro printf_args_2 3
; printdf [format str] [int] [int]
%macro printf_args_2 2
; printdf [format str] [num args]
; needs the labels [printf_arg_1_buf] and [printf_arg_2_buf] to be filled
push_registers

; TODO: do not segfault when we write out of those bounds
Expand Down Expand Up @@ -178,14 +102,14 @@
exit 1

%%printf_fmt_char_loop_got_fmt_d_arg_1:
mov rax, %{2:2}
mov rax, [printf_arg_1_buf]
lea rdi, [r11+r10]
call int32_to_str
add r10, rax
jmp %%printf_fmt_char_loop_got_fmt_d_arg_end

%%printf_fmt_char_loop_got_fmt_d_arg_2:
mov rax, %{3:3}
mov rax, [printf_arg_2_buf]
lea rdi, [r11+r10]
call int32_to_str
add r10, rax
Expand All @@ -210,6 +134,14 @@
; TODO: support \n escape sequence
call print_newline

cmp r8, %2
je %%printf_args_end

puts "error: printf number of args does not match number of args in format string"
exit 1

%%printf_args_end:

pop_registers
%endmacro

7 changes: 7 additions & 0 deletions tests/printf_test.asm
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,11 @@
_start:
printf "hello %d world", 10
printf "%d %d foo bar", 777, -1

mov rcx, 0
printf "rcx=%d (should be zero)", rcx

mov rcx, 1
printf "rcx=%d (should be one)", rcx

exit 0

0 comments on commit 0cb7e3d

Please sign in to comment.