Projeto em Assembly
Projeto em Assembly
Projeto em Assembly
RELATÓRIO PROJETO
A princípio foi um desafio trabalhar com essa linguagem, visto que estávamos
acostumados a programar em linguagens de mais alto nível, como Python, logo,
tivemos que procurar entender a sintaxe do Assembly. Além de que trabalhar com
memória e registradores como o Assembly faz foi algo inusitado do ponto de vista
acadêmico. Assim, decidim noos que trabalharíamos com um compilador online
visto que tive dificuldades em baixar o Nasm.
Esse código definitivamente não é fácil, pois só o fato de termos que usar os
registradores dificulta muito o processo.
Section Directives:
section .data: Esta diretiva define a seção de dados do programa, onde são
armazenadas as variáveis e constantes que serão utilizadas durante a execução.
section .bss: Esta diretiva define a seção BSS (Block Started by Symbol), onde são
armazenadas variáveis não inicializadas, que serão inicializadas durante a
execução do programa.
Assim, a próxima etapa é usar uma linguagem mais baixo nível, como C.
(https://pt.wikipedia.org/wiki/Torre_de_Hanói)
Começamos, claro, com “section .data” e depois criamos strings que serão
chamadas posteriormente, entre elas a “pergunta” que vai acompanhada da diretiva
db que pega bytes para serem usados, depois a mensagem e o “0” que significa bit
0, término da mensagem. Isso se repete até “coluna_origem” db “A” que chama a
primeira coluna de “A”, isso também se repete ate “quebra_de_linha” que usa o
número 10 da tabela de ASCII para indicar um backspace.
Tivemos que usar a declaração “.bss” para descrever para qual memória
cada string iria e como armazenaria. A “entrada”, por exemplo, usa a diretiva “resb”
(reserva de bytes), e aloca 3 bytes. Mas por que 3 bytes? Primeiro, a entrada,
segundo as instruções, pode receber até 2 dígitos, e além disso, o enter funciona
com espaço, digamos assim. Logo, cada caracter é 1 byte. A “quant_disc” se refere
ao caracter de discos, só podendo de 1 dígito. E o “len_buffer” recebe 2 bytes de
memória para alocar o comprimento de uma string.
Após isso, chama “call torre_de_hanoi” de forma recursiva, e com “pop word
[coluna_C]”, desempilha o valor da coluna_C. e faz isso para todas as colunas
depois, e, depois disso, desempilha a quantidade de discos da pilha. Em “mov ecx,
movimento1”, ele move o valor do movimento 1 para o registrador ecx. Após isso,
ele chama “printar_ecx_0” para imprimir o conteúdo do registrador ecx.
Com “inc byte [quant_disc]”, incrementamos 1 ao valor da quantidade de
discos, chamamos a função de printar para mostrar a quantidade de discos e
depois, em “dec byte [quant_disc]”, diminuímos em 1 a quantidade de discos. Após
isso, fazemos uma série de movimentos para o registrador ecx tanto do movimento3
quanto das colunas assim como seria para apenas um disco. Após quebrar uma
linha, movemos o valor da coluna_B para o registrador dx, e isso também para a
coluna_A para o cx. Depois movemos o valor do registrador dx para a coluna_A e o
mesmo do cx para a coluna_B, após isso chamamos recursivamente a função
torre_de_hanoi e com o “ret”,em uma seção fim, terminamos essa parte do código.
Aqui, move o terceiro valor para o registrador “cl”, em “cmp cl, 0x0a” ele
compara o valor do registrador “cl” com o valor de “newline” da tabela ASCII. Após
isso, ele, caso o valor for menor ou igual, não tem mais de dois algarismos,
verificando se é um caractere vazio ou se tem mais de 2. Caso não seja, será
considerada inválida.
Aqui fazemos a validação da quantidade de caracteres, em “mov al,
entrada[0]”, ele move o primeiro caractere da entrada para o registrador “al”, depois
disso, compara esse caractere com o valor “0x31” da tabela ASCII do número 1 em
decimal em formato de string. Após isso, caso for menor, ele será considerado
inválido. Depois compara o valor no registrador “al” o valor “0x39” que na tabela
ASCII é 9, e caso seja maior será inválido. Após isso, ele move o segundo valor da
entrada para o registrador “dl” e faz a mesma coisa, tendo em “0x0a” uma
comparação com “newline” e caso for, vai para um algarismo de validação. O resto é
igual.
Nesse caso vemos a questão da validação tendo em “jmp valido” para caso o
valor seja válido ele pule o processo. No entanto, caso não seja, ele faz isso:
movendo o registrador da mensagem para “ecx”, e chama “call printar_ecx_0” para
printar. Após isso, ele move para “ecx” a quebra_de_linha e printa. Após isso, ele
reinicia. Caso for válido, ele chama o “ret”.
section .data
pergunta db 'Digite o Número de Discos', 0
movimento_1 db 'Mova o Disco ', 0
movimento_2 db ' até a coluna ', 0
movimento_3 db ' da coluna ', 0
concluido db ' Concluído! ', 0
entrada_invalida db 'Sua entrada é inválida, digite novamente.', 0
coluna_A db 'A', 0
coluna_B db 'B', 0
coluna_C db 'C', 0
quebra_de_linha db 10, 0
section .bss
entrada resb 3
quant_disc resb 1
len_buffer resb 2
section .text
global _start
_start:
inicio:
mov ecx, pergunta
call printar_ecx_0
mov ecx, entrada
call ler_3_2
call avaliar_entrada
call converter_string_int
mov [quant_disc], edx
call torre_de_hanoi
mov ecx, concluido
call printar_ecx_0
mov eax, 1
xor ebx, ebx
int 0x80
torre_de_hanoi:
cmp byte [quant_disc], 1
je disco_unico
jmp mais_discos
disco_unico:
mov ecx, movimento_1
call printar_ecx_0
call printar_n_discos
mov ecx, movimento_3
call printar_ecx_0
mov ecx, coluna_A
call printar_ecx_0
mov ecx, movimento_2
call printar_ecx_0
mov ecx, coluna_C
call printar_ecx_0
mov ecx, quebra_de_linha
call printar_ecx
jmp fim
mais_discos:
dec byte [quant_disc]
push word [quant_disc]
push word [coluna_A]
push word [coluna_B]
push word [coluna_C]
call torre_de_hanoi
call torre_de_hanoi
fim:
ret
converter_string_int:
mov edx, entrada[0]
sub edx, '0'
mov eax, entrada[1]
um_algarismo:
ret
printar_ecx:
mov eax, 4
mov ebx, 1
mov edx, 1
int 0x80
ret
printar_ecx_0:
printar_loop:
mov al, [ecx]
cmp al, 0
je printar_exit
call printar_ecx
inc ecx
jmp printar_loop
printar_exit:
ret
ler_3_2:
mov eax, 3
mov ebx, 0
mov edx, 2
int 0x80
ret
avaliar_entrada:
mov cl, entrada[2]
cmp cl, 0x0a
jle quantidade_caracteres_valida
jmp invalido
quantidade_caracteres_valida:
mov al, entrada[0]
cmp al, 0x31
jl invalido
cmp al, 0x39
jg invalido
um_algarismo_validacao:
jmp valido
invalido:
mov ecx, entrada_invalida
call printar_ecx_0
mov ecx, quebra_de_linha
call printar_ecx
jmp inicio
valido:
ret
converter_int_string:
dec edi
xor edx, edx
mov ecx, 10
div ecx
add dl, '0'
mov [edi], dl
test eax, eax
jnz converter_int_string
ret
printar_n_discos:
movzx eax, byte [quant_disc]
lea edi, [len_buffer + 2]
call converter_int_string
mov eax, 4
mov ebx, 1
lea ecx, [edi]
lea edx, [len_buffer + 2]
sub edx, ecx
int 0x80
ret