253 lines
7.7 KiB
NASM
253 lines
7.7 KiB
NASM
|
;------------------------------------------------------------------------------
|
||
|
;
|
||
|
; 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.
|
||
|
;
|
||
|
;------------------------------------------------------------------------------
|
||
|
|
||
|
|
||
|
;------------------------------------------------------------------------------
|
||
|
; 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
|
||
|
|
||
|
;----------------------------------------------------
|
||
|
; Imprime a mensagem na saída padrão se acertou
|
||
|
;----------------------------------------------------
|
||
|
;_print_ok:
|
||
|
; mov rax, SYS_WRITE
|
||
|
; mov rdi, r15
|
||
|
; syscall
|
||
|
;jmp _exit_ok
|
||
|
|
||
|
;--------------------------------------------------------
|
||
|
; 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
|