Skip to content

Commit

Permalink
Reduce outputted instructions for printf call
Browse files Browse the repository at this point in the history
The entire printf was a macro so all the code would be inlined.
Now the macro is only a wrapper. And it will jump to the one
implementation.

This makes the final binary size smaller and the stepping with gdb more
straightforward.
  • Loading branch information
ChillerDragon committed Aug 9, 2024
1 parent 07796e4 commit 48a94bc
Show file tree
Hide file tree
Showing 4 changed files with 60 additions and 39 deletions.
2 changes: 2 additions & 0 deletions src/bss/buffers.asm
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,5 @@ printf_arg_6_buf resb 8
printf_arg_7_buf resb 8
printf_arg_8_buf resb 8

printf_num_args resb 4

93 changes: 56 additions & 37 deletions src/printf.asm
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
%define MAX_PRINTF_ARGS 8

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

%macro printlnf 1-*
printf %{1:-1}
call print_newline
Expand All @@ -16,41 +19,51 @@
%xdefine num_args %count(%{1:-1})
%assign num_args (num_args-1)

; rax = is null terminated format str
str_to_stack %1

%if num_args == 0
_printf_args %1, 0
mov dword [printf_num_args], 0
call _printf_args
%elif num_args == 1
mov qword [printf_arg_1_buf], %{2:2}
_printf_args %1, 1
mov dword [printf_num_args], 1
call _printf_args
%elif num_args == 2
mov qword [printf_arg_1_buf], %{2:2}
mov qword [printf_arg_2_buf], %{3:3}
_printf_args %1, 2
mov dword [printf_num_args], 2
call _printf_args
%elif num_args == 3
mov qword [printf_arg_1_buf], %{2:2}
mov qword [printf_arg_2_buf], %{3:3}
mov qword [printf_arg_3_buf], %{4:4}
_printf_args %1, 3
mov dword [printf_num_args], 3
call _printf_args
%elif num_args == 4
mov qword [printf_arg_1_buf], %{2:2}
mov qword [printf_arg_2_buf], %{3:3}
mov qword [printf_arg_3_buf], %{4:4}
mov qword [printf_arg_4_buf], %{5:5}
_printf_args %1, 4
mov dword [printf_num_args], 4
call _printf_args
%elif num_args == 5
mov qword [printf_arg_1_buf], %{2:2}
mov qword [printf_arg_2_buf], %{3:3}
mov qword [printf_arg_3_buf], %{4:4}
mov qword [printf_arg_4_buf], %{5:5}
mov qword [printf_arg_5_buf], %{6:6}
_printf_args %1, 5
mov dword [printf_num_args], 5
call _printf_args
%elif num_args == 6
mov qword [printf_arg_1_buf], %{2:2}
mov qword [printf_arg_2_buf], %{3:3}
mov qword [printf_arg_3_buf], %{4:4}
mov qword [printf_arg_4_buf], %{5:5}
mov qword [printf_arg_5_buf], %{6:6}
mov qword [printf_arg_6_buf], %{7:7}
_printf_args %1, 6
mov dword [printf_num_args], 6
call _printf_args
%elif num_args == 7
mov qword [printf_arg_1_buf], %{2:2}
mov qword [printf_arg_2_buf], %{3:3}
Expand All @@ -59,7 +72,8 @@
mov qword [printf_arg_5_buf], %{6:6}
mov qword [printf_arg_6_buf], %{7:7}
mov qword [printf_arg_7_buf], %{8:8}
_printf_args %1, 7
mov dword [printf_num_args], 7
call _printf_args
%elif num_args == 8
mov qword [printf_arg_1_buf], %{2:2}
mov qword [printf_arg_2_buf], %{3:3}
Expand All @@ -69,7 +83,8 @@
mov qword [printf_arg_6_buf], %{7:7}
mov qword [printf_arg_7_buf], %{8:8}
mov qword [printf_arg_8_buf], %{9:9}
_printf_args %1, 8
mov dword [printf_num_args], 8
call _printf_args
%else
jmp %%error_many_args
%endif
Expand All @@ -88,6 +103,10 @@
exit 1

%%okay_many_args:

; frees stack string
mov rsp, rbp

pop_registers
%endmacro

Expand Down Expand Up @@ -116,36 +135,36 @@ _printf_fill_arg:
pop rax
ret

%macro _printf_args 2
_printf_args:
; _printf_args [format str] [num args]
; rax = format string
; needs the labels
;
; [printf_num_args]
;
; [printf_arg_1_buf]
; [printf_arg_2_buf]
; ...
;
; to be filled. The amount depends on num_args.
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

; r8 is the arg index
; we increment before compare
; so 1 = is the first
; but it will be %2 because %1 is the fmt string
mov r8, 0

mov rbp, rsp
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:
.__printf_fmt_char_loop:
mov r9b, byte [rax+rcx]
inc rcx

Expand All @@ -155,69 +174,69 @@ _printf_fill_arg:
inc r10

cmp r9b, '%'
je %%printf_fmt_char_loop_got_percentage
je .__printf_fmt_char_loop_got_percentage
cmp r9b, '\'
je %%printf_fmt_char_loop_got_backslash
je .__printf_fmt_char_loop_got_backslash

jmp %%printf_fmt_char_loop_check_repeat
jmp .__printf_fmt_char_loop_check_repeat

%%printf_fmt_char_loop_got_backslash:
.__printf_fmt_char_loop_got_backslash:
; \n newline
mov r9b, byte [rax+rcx]
cmp r9b, 'n'
dec r10
mov byte [r11+r10], 0xa
inc r10
inc rcx
jmp %%printf_fmt_char_loop_check_repeat
jmp .__printf_fmt_char_loop_check_repeat

%%printf_fmt_char_loop_got_percentage:
.__printf_fmt_char_loop_got_percentage:
mov r9b, byte [rax+rcx]
cmp r9b, 'd'
je %%printf_fmt_char_loop_got_fmt_d
je .__printf_fmt_char_loop_got_fmt_d
cmp r9b, 'p'
je %%printf_fmt_char_loop_got_fmt_p
je .__printf_fmt_char_loop_got_fmt_p

puts "error: printf got invalid format character"
exit 1

%%printf_fmt_char_loop_got_fmt_d:
.__printf_fmt_char_loop_got_fmt_d:
mov rsi, int32_to_str
call _printf_fill_arg
jmp %%printf_fmt_char_loop_check_repeat
jmp .__printf_fmt_char_loop_check_repeat

%%printf_fmt_char_loop_got_fmt_p:
.__printf_fmt_char_loop_got_fmt_p:
mov rsi, ptr_to_str
call _printf_fill_arg
jmp %%printf_fmt_char_loop_check_repeat
jmp .__printf_fmt_char_loop_check_repeat

%%printf_fmt_char_loop_check_repeat:
.__printf_fmt_char_loop_check_repeat:

cmp r9b, 0
jne %%printf_fmt_char_loop
jne .__printf_fmt_char_loop

; print output buffer
dec r10
printn r11, r10

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

cmp r8, %2
je %%printf_args_end
cmp r8d, [printf_num_args]
je .__printf_args_end

puts "error: printf number of args does not match number of args in format string"
print " expected args: "
mov rax, %2
mov rax, 0
mov eax, [printf_num_args]
call println_int32
print " got args: "
mov rax, r8
call println_int32
exit 1

%%printf_args_end:
.__printf_args_end:

pop_registers
%endmacro
ret

2 changes: 1 addition & 1 deletion src/teeworlds_asmr.asm
Original file line number Diff line number Diff line change
Expand Up @@ -120,8 +120,8 @@ section .bss
section .text

%include "src/macros.asm"
%include "src/printf.asm"
%include "src/syscalls.asm"
%include "src/printf.asm"
%include "src/logger.asm"
%include "src/hex.asm"
%include "src/terminal.asm"
Expand Down
2 changes: 1 addition & 1 deletion tests/assert.asm
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,8 @@ section .bss
section .text

%include "src/macros.asm"
%include "src/printf.asm"
%include "src/syscalls.asm"
%include "src/printf.asm"
%include "src/logger.asm"
%include "src/hex.asm"
%include "src/udp.asm"
Expand Down

0 comments on commit 48a94bc

Please sign in to comment.