SJANI/codigo/advinha.asm

248 lines
7.7 KiB
NASM
Raw Normal View History

;------------------------------------------------------------------------------
;
; Programação em Baixo Nível (PBN)
;------------------------------------------------------------------------------
; Projeto final de curso: advinha.asm
; Data: 23/08/2025
; Autor: Daniel Ramos Gonçalves
; E-mail: daniel@drginfo.com.br
; Professor/Instrutor/Mentor: Blau Araujo (MUITO FERA)
;
; Proposta: Criar um programa em Assembly, jogo de advinhação.
; O programa deve gerar um número aleatório, e você deve advinhar.
; Entrar com um número inteiro entre 1 e 100. Deve ter críticas
; de Maior / Menor / Igual. Deve aceitar somente números, e qualquer
; entrada diferente deve ser decartada e encerrar o programa com
; uma mensagem de erro.
2025-08-23 16:42:35 -03:00
;------------------------------------------------------------------------------
; Montagem e Linkedição (arqquivo no formato ELF64 GNU/Linux):
;
2025-08-23 16:42:35 -03:00
; nasm -g -felf64 advinha.asm
; ld advinha.o -o advinha
;------------------------------------------------------------------------------
;------------------------------------------------------------------------------
; difinições de pré-processamento padronizadas
;------------------------------------------------------------------------------
%define SYS_READ 0
%define SYS_STDIN 0
%define SYS_WRITE 1
%define SYS_STDOUT 1
%define SYS_TIME 201
%define SYS_EXIT 60
%define SYS_OK 0
%define SYS_ERR 1
%define BUF_SIZE 2048
%define BUF_COUNT 5
;------------------------------------------------------------------------------
section .rodata
;------------------------------------------------------------------------------
; mensagens que serão exibidas na tela...
msg_ini db "Digite um número entre 1 e 100: ", 0
len_msg_ini equ $-msg_ini
; com a mensagem entre crases, ela aceita caracteres de controle como '\n'
msg_maior db `Muito acima! Tente novamente...\n`, 0
len_msg_maior equ $-msg_maior
msg_menor db `Muito abaixo! Tente novamente...\n`, 0
len_msg_menor equ $-msg_menor
msg_ok_ini db "Você acertou com: ", 0
len_msg_ok_ini equ $-msg_ok_ini
msg_ok_end db " Tentativas!", 10, 0
len_msg_ok_end equ $-msg_ok_end
; mensagem de uso...caso não digite nada ou digitação inválida...
msg_uso db "Você deve digitar um numero inteiro entre 1 e 100.", 10, 0
len_msg_uso equ $-msg_uso
;------------------------------------------------------------------------------
section .bss
buffer resb BUF_SIZE
tentativas resb BUF_COUNT
;------------------------------------------------------------------------------
; seção do codigo em si...
;------------------------------------------------------------------------------
section .text
global _start
_start:
;------------------------------------------------------------------------------
; gera um número inteiro randômico de 0..100 e salva resultado em r9
; registradores: eax, edx, ebx, r9
; resultado: r9
;------------------------------------------------------------------------------
_num_rand:
mov eax, SYS_TIME
mov edx, 0
syscall
mov ebx, 100
div ebx
add edx, 1
mov r9d, edx
;--------------------------------------------------------
; rdi rsi rdx
; | | |
; syscall: i64 read(int fd, void *buf[.count], u64 size)
; |
; rax -> quantidade de bytes lidos (-1 = erro)
;--------------------------------------------------------
_msg_ini:
mov rax, SYS_WRITE ; sys_write = 1
mov rdi, SYS_STDOUT ; fd=1 (stdout)
mov rsi, msg_ini ; Mensagem Inicial
mov rdx, len_msg_ini ; Tamanho da mensagem
syscall
mov rax, SYS_READ ; sys_read = 0
mov rdi, SYS_STDIN ; fd=0 (stdin)
mov rsi, buffer ; buffer da leitura (armazenamento)
mov rdx, BUF_SIZE ; máximo caracteres a ler
syscall ; retorna quantidade de bytes lidos em rax
;--------------------------------------------------------
; conversão de string para inteiro...
; registradores: rax, rbx, rcx, r8
;--------------------------------------------------------
_convert_strtoint:
dec rax
mov byte [buffer + rax], 0 ; garante terminador nulo '\0'
mov rbx, 10 ; multiplicador (x10)
xor rcx, rcx ; contador = 0
xor rax, rax ; resultados da conversão
.digit_loop:
mov r8b, byte [buffer + rcx] ; caractere em buf[rcx]
cmp r8b, '0' ; caractere < 0x30?
jl _done ; se menor, termina
cmp r8b, '9' ; caractere > 0x39?
jg _done ; se maior, termina
sub r8b, 0x30 ; converte de ASCII para numero
mul rbx ; rdx:rax = rax * 10 (rbx = 10)
add rax, r8 ; armazena dígito em rax
inc rcx ; incrementa para receber o próximo byte
jmp .digit_loop
;--------------------------------------------------------
; conversão de inteiro para string...
; registradores: rax(int), rbx, rcx, r12, r15
;--------------------------------------------------------
_convert_inttostr:
mov rcx, tentativas ; buffer para receber o inteiro
mov rbx, 10 ; divisor
mov r12, 0 ; contador de dígitos
.proximo_digito:
xor rdx, rdx ; limpa rdx para divisão
div rbx ; divide rdx:rax/rbx = rax / 10, resto em rdx
add rdx, '0' ; converte o resto(digito) para seu caracter ASCII
push rdx ; salva rdx na pilha
inc r12 ; incrementa contador de dígitos
cmp rax, 0 ; verifica se o quociente é zero
jnz .proximo_digito ; se não, continua o loop
.print_str:
cmp r12, 0 ; verifica se ainda há digitos para desempilhar
jz _str_final ; se não, pula para o final
pop rax ; desempilha o caractere do dígito em rax
mov [rcx], al
inc rcx
dec r12
jmp .print_str
_str_final:
mov rsi, tentativas ; Endereço do buffer com a string
mov rdx, rcx ; Endereço do final da string
sub rdx, rsi ; Calcula o tamanho da string (final - início)
ret
;--------------------------------------------------------------------
; compara o numero digitado que está em 'rax' com o numero gerado
; pelo systema 'random' 'r9' ( rax < r9 ?)
;--------------------------------------------------------------------
_compara:
cmp rax, 0 ; se rax == 0, erro
je _exit_err ; pula para saida de erro
cmp rax, 0x64 ; se maior que 100, erro
ja _exit_err ; pula para saida de erro
cmp rax, r9 ; compara os numeros
je .igual ; se for igual, pula para '.igual'
jb .menor ; se for menor pula para '.menor'
ja .maior ; se for mais alto pula para '.maior'
.menor:
mov rsi, msg_menor
mov rdx, len_msg_menor
call _print
call _msg_ini
.maior:
mov rsi, msg_maior
mov rdx, len_msg_maior
call _print
call _msg_ini
.igual:
; primeira parte da mensagem...
mov rsi, msg_ok_ini
mov rdx, len_msg_ok_ini
call _print
; quantidade de tentativas...
mov rax, r15 ; copia qtd tentativas para rax
mov rsi, tentativas ; buffer de tentativas
call _convert_inttostr
call _print
; final da mensagem...
mov rsi, msg_ok_end
mov rdx, len_msg_ok_end
call _print
call _exit_ok
_done:
inc r15 ; incrementa contador
jmp _compara
;----------------------------------------------------
; Imprime a mensagem na saída padrão STD_OUT FD = 1
;----------------------------------------------------
_print:
mov rax, SYS_WRITE
mov rdi, SYS_STDOUT
syscall
ret
;--------------------------------------------------------
; saída em caso de erro...
;--------------------------------------------------------
_exit_err:
mov rsi, msg_uso
mov rdx, len_msg_uso
call _print
mov rax, SYS_EXIT
mov rdi, SYS_ERR
syscall
;--------------------------------------------------------
; saída em caso de sucesso...
;--------------------------------------------------------
_exit_ok:
mov rax, SYS_EXIT
mov rdi, SYS_OK
syscall