; ------------------------------------------------------------
; print_utils.asm
; Sub-rotinas:
;   - print_char(rdi = caractere)
;   - print_str(rdi = ptr string \0-terminated)
;   - print_int(rax = inteiro, sem newline)
; Macros:
; - SAVE_REGS: salva registradores voláteis
; - RESTORE_REGS: restaura registradores salvos
; ------------------------------------------------------------

%macro SAVE_REGS 0
	push rax
	push rbx
	push rcx
	push rdx
	push rsi
	push rdi
	push r8
	push r9
	push r10
	push r11
%endmacro

%macro RESTORE_REGS 0
	pop r11
	pop r10
	pop r9
	pop r8
	pop rdi
	pop rsi
	pop rdx
	pop rcx
	pop rbx
	pop rax
%endmacro

section .bss
	int_buf resb 22      ; buffer para int e char

section .text
global print_char
global print_str
global print_int

; ------------------------------------------------------------
; void print_char(rdi = caractere)
; ------------------------------------------------------------
print_char:
	push rbp
	mov rbp, rsp

	SAVE_REGS

	mov al, dil              ; coloca o caractere em al (parte baixa de rax)
	mov byte [int_buf], al   ; usa o mesmo buffer global

	mov rax, 1               ; syscall write
	mov rdi, 1               ; stdout
	lea rsi, [int_buf]
	mov rdx, 1
	syscall

	RESTORE_REGS

	mov rsp, rbp
	pop rbp
	ret

; ------------------------------------------------------------
; void print_str(rdi = ptr string \0-terminated)
; ------------------------------------------------------------
print_str:
	push rbp
	mov rbp, rsp

	SAVE_REGS
	
	mov rsi, rdi            ; ponteiro string
	xor rcx, rcx

.count_loop:
	cmp byte [rsi + rcx], 0
	je .write
	inc rcx
	jmp .count_loop

.write:
	mov rax, 1              ; syscall write
	mov rdi, 1              ; stdout
	mov rdx, rcx            ; tamanho string
	syscall

	RESTORE_REGS
	
	mov rsp, rbp
	pop rbp
	ret

; ------------------------------------------------------------
; void print_int(rax = inteiro, sem newline)
; ------------------------------------------------------------
print_int:
	push rbp
	mov rbp, rsp

	SAVE_REGS

	mov rdi, rax
	lea rsi, [int_buf + 21] ; aponta para o fim do buffer
	mov byte [rsi], 0       ; opcional: zero-termina

	cmp rdi, 0
	jne .convert

	; zero
	dec rsi
	mov byte [rsi], '0'
	jmp .write

.convert:
	mov rax, rdi
	mov rbx, 10
	xor rcx, rcx

	cmp rdi, 0
	jge .conv_loop

	neg rax
	mov rcx, 1              ; sinal negativo

.conv_loop:
	xor rdx, rdx
	div rbx
	add dl, '0'
	dec rsi
	mov [rsi], dl
	test rax, rax
	jnz .conv_loop

	test rcx, rcx
	jz .write

	dec rsi
	mov byte [rsi], '-'

.write:
	mov rax, 1              ; syscall write
	mov rdi, 1              ; stdout
	mov rdx, int_buf + 21
	sub rdx, rsi
	syscall

	RESTORE_REGS
	
	mov rsp, rbp
	pop rbp
	ret
 
