BlogCurso 2000: Assembly esse eterno desconhecido

Aviso aos navegantes: Esta aula é bem mais longa que o normal por que ensino como instalar as ferramentas que vamos usar

Existem alguns conhecimentos que estão ficando raros, como programação de baixo nível, por que raros? Por que alguns julgam sem sequer olhar que é difícil! Ou que tudo nessa vida se resolve com Python e boa vontade! A verdade que nem sempre, quando se quer algo realmente otimizado, uma rotina que tenha que rodar milhões de vezes por segundo, ou mesmo se quer fazer uma rotina embarcada, e se tenha a redução de custo como máxima prioridade, só resta o Assembly para nos salvar. (Tem uso na criação de compiladores também, mas isso fica pro futuro)

Mas todo Assembly é igual?

Infelizmente não, mas todos seguem a mesma lógica, como cada processador tem capacidades diferentes, e suas limitações especificas, os comandos são espelho do que os processadores conseguem fazer.

Um exemplo que mostra como as lógicas se coincidem, bastando apenas ver os detalhes e nomes dos comandos:

Mover o valor 123 na “variável principal do processador”:

  • Intel 8086: MOV AX, 123
  • Intel x86: MOV EAX, 123
  • Intel x86-64: MOV RAX, 123
  • ARM: MOV R0, #123

Mas mas mas o que é um processador?

Basicamente o processador de um computador é uma calculadora metida a besta, em uma visão simplista, a única diferença pra uma calculadora comum é o fato do processador fazer comparações e tomar ações baseado nessas comparações, além de poder pular para quaisquer trecho de código diretamente podendo gerar repetições.

E como posso aprender como funciona isso?

Eu vou fazer uma pequena série de tutoriais para ensinar o básico de como programar em Assembly, para isso vou escolher um processador bem simples, o 8086 de 16bits, que é base dos processadores modernos do PC, infelizmente o código gerado para este processador não roda diretamente nos computadores mais novos pois o processador 64bits quebrou a compatibilidade da execução direta de código 16bits, mas não se preocupe a base de conhecimento adquirido, servirá para facilmente aprender a codificar em assembly para processadores mais novos, apenas estudando um material mais simples sobre esses processadores.

Como vou rodar esse código do 8086 no meu computador novo?

Muito simples, existe um emulador chamado DOSBOX, que pode ser baixado e instalado muito facilmente através de sua página de Download.

Como usar o DOSBOX?

Após instalado ele criará um atalho no Menu Iniciar do Windows/Pasta Aplicativos do Mac/Menu Applications do Gnome/(Insira o local onde seu sistema operacional guarda os atalhos aqui), abrindo este atalho voce verá uma tela parecida com esta:

DOSBOX

Assim que o DOSBOX abre ele vem sem se associar a nenhuma pasta do seu computador, este emulador simula um HD virtual associado ao conteúdo de uma pasta, então o que você colocar nesta pasta aparecerá para o DOSBOX, para se associar basta usar o comando MOUNT, por exemplo para montar a pasta meus documentos no C: virtual dele:

Windows:

MOUNT C: c:\Usuários\Humberto\Documentos\

MacOS:

MOUNT C: /Users/humberto/Documents/

Linux:

MOUNT C: /home/humberto/Documentos/

Guarde este comando por será necessário toda vez que iniciar o emulador, mais pra frente vou ensinar como fazer o DOSBOX já iniciar na pasta escolhida.

E agora o que eu faço?

Vamos baixar o “Compilador” do Assembly, que se chama Assembler ou Montador, com ele que vamos converter nosso código Assembly em arquivos executáveis e dominar o mundo MWAHAHAHAHA, tá sem essa ultima parte.

Vamos usar o NASM, aproveitando que estaremos usando o emulador DOSBOX, vamos para facilitar baixar a versão que roda nele, mas alternativamente pode instalar a versão nativa para o seu sistema operacional favorito.

Para baixar clique neste link, baixará um ZIP diretamente do site do NASM, e descompacte na mesma pasta que voce escolher para programar, de forma que os arquivos que voce vai codificar fiquem juntos aos arquivos do compilador, no caso o que vamos usar é o NASM.EXE e o CWSDPMI.EXE, sendo os outros arquivos opcionais para este momento.

Já tenho o DOSBOX aberto na pasta e dentro dela tenho o NASM/CWSDPMI, e agora?

Agora estamos prontos finalmente pra começar a brincadeira.

No seu editor favorito (Recomendo o VSCode com a extensão x86 and x86_64 Assembly instalada), crie um arquivo em branco de texto chamado AULA1.ASM, caso não consiga personalizar a extensão do arquivo para .ASM também servirá a .TXT, bastando adaptar os próximos passos. (Cuidado no Windows que ele tem a mania de adicionar a extensão .TXT ao final dos arquivos de texto quando usado o Bloco de Notas, ficando AULA1.ASM.TXT)

Neste arquivo que criou cole o conteúdo abaixo:


ORG 0x100

MOV AX, 1 

CALL videotxt_imprime_numero_em_ax

RET

; Rotinas de impressão na tela

videotxt_imprime_texto:
    push si
    push ax
    push bx
    mov ah, 0xe
    mov bx, 0x7
    .caractere:
        lodsb
        cmp al, 0
        je .fim
        int 0x10
        jmp .caractere
    .fim:
    pop bx
    pop ax
    pop si
    ret

videotxt_imprime_numero_em_ax:
    push ax
    push bx
    push cx
    push dx
    mov bx, 10
    xor dx, dx
    div bx
    cmp ax, 0
    je .fim
        call videotxt_imprime_numero_em_ax
    .fim:
    mov al, dl
    add al, '0'
    mov ah, 0xe
    int 0x10
    pop dx
    pop cx
    pop bx
    pop ax
    ret

Socorro que código complicado!!!!

Calma, tenha fé, vou explicar aos poucos, e inicialmente só iremos ver as 2 primeiras linhas, deixando o resto para o futuro.

Salvando o arquivo corretamente, vá no DOSBOX e digite o comando abaixo para monta-lo em um executável:

NASM -f bin - o aula1.com aula1.asm

O comando recebe alguns parâmetros, que vou explicar brevemente abaixo:

-f bin

Este parâmetro acima informa ao NASM o formato que queremos que ele gere, no caso formato binário.

-o aula1.com

Este informa ao NASM o arquivo que será gerado.

aula1.asm

Informa ao NASM o nome do arquivo de origem.

Agora, fazendo tudo certinho você poderá executar ele com o comando:

AULA1.COM

Ficará igual a imagem abaixo:

Resultado

Uhullll imprimiu “1”, mas mas porque imprimiu “1”????

Vamos olhar o código, e ver o que ele faz:

Na primeira linha existe o comando ORG igual abaixo, ele avisa ao NASM como o Sistema Operacional espera que o código encontre suas variáveis e rotinas, neste caso informando que há um afastamento de 0x100 Bytes do inicio da memória do aplicativo para o inicio da primeira linha de código do aplicativo.

Abstrato? Confuso? Calma, relaxe, imagina que quando o Sistema Operacional carrega seu aplicativo para a memória ele deixe uma folguinha entes dele para gravar informações gerais sobre o que será executado, por exemplo os argumentos que o usuário digitou, esses argumentos tem que ficar em algum lugar então o sistema operacional, empurra o seu aplicativo 256 bytes (Equivalente decimal a 0x100 bytes) pra frente de onde deveria ficar pra caber essa informação, assim para o programa que você fez saber que existe essa folguinha, você tem que avisa-lo, com este comando.

ORG 0x100

Mas sempre será ORG 0x100????? Apenas nos aplicativos para DOS, que será o que vamos ver nesse tutorial, quando for para Windows tem sua própria regrinha, mas isso é algo que se aprende uma vez e se repete sempre em todos os programas, relaxe.

Agora vamos para a ação!! Esta linha Move para AX o valor de 1, mas o que é mover? E o que é AX?!?!?

MOV AX, 1

Vamos pelo básico, o Comando que você usará para pegar um valor e jogar em algum lugar é sempre o MOV, e sempre que você ler ele, tente ler mentalmente MOVe para AX o valor de 1, assim ficando mais fácil de entender.

Mas o que seria o AX, e por que movi pra ele?

Fácil, os processadores tem suas variáveis para uso temporário e rápido, essas variáveis se chamam Registradores, normalmente são poucos registradores que tem no processador, e você usa eles para guardar o valor que você vai usar naquele momento, guardando em sua variável posteriormente.

Quais são esses tais de registradores???

Abaixo vou listar os principais do 8086, nas próximas aulas vou mostrar outros, conforme for ensinando a usa-los, principalmente quando chegarmos em Strings.

Temos 4 registradores principais:

  • AX - Acumulador
  • BX - Base
  • CX - Contador
  • DX - Dados

Todos eles servem para uso geral, mas tem alguns comandos que usam especialmente um deles, você pode imaginar a partir do nomes deles, mas tenha tranquilidade que aos poucos vou mostrando como melhor usa-los.

Vamos focar inicialmente no nosso primeiro, o AX.

O AX é melhor usado em contas, sendo algumas como Divisão e Multiplicação tem o uso dele como praticamente obrigatório, mas como usa-lo?

Vamos começar pelo simples e vamos adicionando mais informações, por exemplo no código que acabamos de ver mude o numero 1 para o número que você desejar, e execute os dois comandos que já expliquei para montar o executável e roda-lo.

Socorro!!!!! Deu erro!!! Depois que alterei o número!!!! Júro que só fiz isso!!!!

Normal, se você colocou um número qualquer, por exemplo 1234567890, e deu erro ao executar o NASM, é previsível, como estamos trabalhando com um processador 16bits, ele só aceita números em 16bits, mas o que isso quer dizer? Só caberá números de 0 a 65535, então tende mudar para um número dentro desta faixa e tente novamente.

Mas 65mil é muito limitado!

Sim sim, é limitado, mas é sempre bom começarmos com coisas simples, processadores simples, antes de irmos para processadores mais poderosos, o x86-64 ou o ARM que provavelmente você está usando neste momento dependendo do cálculo podem conseguir trabalhar até com 128 bits ou mesmo 256 bits em cálculos bem especificos, mas também tem itens mais complexos fora do nosso contexto de aprendizado.

Agora vamos ver o que mais podemos fazer com o AX

Fora mover um valor para o AX podemos fazer continhas com ele, por exemplo temos os comandos abaixo que devem substituir a linha do MOV do arquivo que está fazendo:

MOV AX, 5
ADD AX, 10
SUB AX, 1

O que esses comandos fazem??

Se você conhece um pouco de inglês pode imaginar, mas vamos abaixo:

  • MOV - Move um valor
  • ADD - Adiciona um valor
  • SUB - Subtrai um valor

Fazendo de cabeça imagino que 5 + 10 - 1 seja 14, correto? Vamos ver, salva, monta e executa esse programa editado com essas três linhas no lugar da linha original “MOV AX, 1”, vai ficar parecido com o abaixo:

Código montado

E ao executar vai ficar assim:

Resultado

Agora tente brincar de alterar os valores mudar a ordem dos comandos para testar, hoje ficamos por aqui, amanhã continuamos com mais comandos e mostrando como usar mais registradores, assim fazendo continhas mais complicadas.

Esta aula ficou bastante longa devido a explicação inicial, nas próximas vamos tem mais conteúdo do Assembly dentro de uma aula.

Inté =)