Aula Prática 01: Introdução
à Linguagem Assembly
1. Introdução aos Registros do Processador 8088
A CPU tem 16 registros internos, cada um com 16 bits. Os 4 primeiros: AX, BX, CX e DX são registros de uso geral e podem ser usados como registros de 8 bits. Se usados em tal modo, é necessário referencia-los por exemplo como: AH e AL, que são os bytes altos e baixo do registros AX. Esta nomenclatura é também aplicável aos registros BX, CX e DX.
Os registros são conhecidos pelos seus nomes específicos:
O Debug fornece um conjunto de comandos que deixa você executar
um número de operações úteis. Alguns dos comandos
do Debug estão apresentados na tabela abaixo.
|
|
|
|
Imprime os comandos do Debug na tela | ? |
|
Permite montar o programa (translação das instruções Assembly em linguagem de máquina) | a [end] |
|
Apresenta o conteúdo de uma área de memória | d [end] |
|
Permite entrar o dado em uma memória | e [end] |
|
Executa um programa na memória | g [end-ini] [end-fin] |
|
Calcula a soma e a diferença de dois valores hexadecimais | h [valorl] [valor2] |
|
Carrega um programa do disco na memória | l |
|
Define um nome para o programa | n [nome.ext] |
|
Permite abandonar o programa Debug | q |
|
Apresenta o conteúdo de um ou mais registradores | r |
|
Realiza o "Trace" de um programa (executa 1 comando) | t |
|
Permite desassemblar o código de máquina em código simbólico | u [end-ini] [end-fin] |
|
Permite escrever o programa em disco | w |
Para iniciar o trabalho com Debug, digite o seguinte comando no seu
computador:
C:/>Debug [Enter]
-
Na próxima linha um traço aparecerá, ele é
o prompt do Debug, neste momento as instruções do debug podem
ser introduzidas. Por exemplo,
é possível visualizar os valores dos registros internos
da CPU usando o seguinte comando:
-r[Enter]
AX=0000 BX=0000 CX=0446 DX=0000 SP=FFFE BP=0000 SI=0000 DI=0000
DS=1175 ES=1175 SS=1175 CS=1175 IP=0100 NV UP EI PL NZ NA PO NC
6897:0100 58 POP BX
Todos os conteúdos dos registros internos da CPU serão apresentados. Observe que, embora o seu computador apresente outros valores, os valores armazenados nos arquivos CS, DS, SS, ES são idênticos, assim todos os quatro segmentos têm o mesmo endereço de base (são mapeados no mesmo bloco de memória), características dos programas .COM.
É possível alterar os valores dos registros usando o comando "r". Veja exemplo abaixo:
-rbx[Enter]
BX 0000
:
Esta instrução apresentará o conteúdo do registro BX e o indicador Debug é mudado de "-" para ":". Quando o prompt é igual a ":", é possível mudar o valor do registro definido no parâmetro de entrada. Por exemplo, digite um número e digite [Enter]. Verifique novamente o valor dos registros utilizando o comando "r".
3. Estrutura Assembler
Linhas de código Assembly tem duas partes, a primeira é o nome da instrução que será executada, e a segunda são os parâmetros do comando. Por exemplo: MOV AL, 25. Aqui "MOV" é um comando a ser executado, no caso uma transferência de dados, e "AL" e "25" são os parâmetros. O nome das instruções na linguagem é feita de dois, três ou quatro letras. Estas instruções são chamadas de mnemônicos ou códigos de operação, desde que eles representam uma função que o processador executará.
Algumas instruções são usadas da seguinte forma: ADD AL, [170]. Os colchetes no segundo parâmetro indica-nos que nós estamos trabalhando com o conteúdo da célula de memória de número 170 e não com o valor 170. Isto é conhecido como endereçamento direto.
4. Criando um Programa Assembly Básico
O primeiro passo para ser criar um programa Assembly é iniciar o Debug, este passo consiste em digitar Debug[Enter] no prompt do DOS. Para montar um programa no Debug, o comando "a" (assemble) é usado. O endereço inicial do programa pode ser entrado como parâmetro, se este parâmetro é omitido a montagem será iniciada na localização especificada por CS:IP, tipicamente o deslocamento (IP) é 0100h, que é a localidade onde programas com a extensão .COM devem ser iniciados. Neste momento não é necessário dar ao comando "a" um parâmetro, isto é recomendável para evitar problemas desde que os registros CS:lP são utilizados, portanto nós digitamos:
a [Enter]
mov ax, 0002[Enter]
mov bx, 0004[Enter]
add ax, bx[Enter]
nop[Enter][Enter]
O que este programa faz? Move o valor 0002 para o registro AX, move o valor 0004 para o registro BX, adiciona os conteúdos dos registros AX e BX e armazena o resultado em AX. Finalmente, a instrução não operação (nop) é para notificar o fim do programa.
Após digitado (corretamente) este código, aparecerá na tela algo parecido com as seguintes linhas:
-a
1175:0100 mov ax,0002
1175:0103 mov bx,0004
1175:0106 add ax,bx
1175:0108 nop
1175:0109
Como já apresentado o comando "a" permite montar o programa de máquina. Debug monta o programa linha a linha. Por exemplo, quando nós digitalmos o [Enter] após a instrução mov ax,0002, debug automaticamente translada a linguagem simbólica em código de máquina. Caso nós digitarmos alguma instrução inválida, o debug indicará o erro após digitarmos [Enter]. Tente por exemplo armazenar a instrução MOV AZ,2 a partir da memória 200h.
Os números que antecedem a instrução indica a localização em memória onde o código de máquina correspondente será armazenado. Por exemplo, a instrução add ax,bx está armazenada a partir de 1175:0106 (o primeiro número é o endereço base do segmento de código e o segundo é o deslocamento neste segmento). O número de byte que ocupa uma instrução é dependente do tipo de instrução e de seus operandos. É fácil observar que a instrução mov ax,0002 ocupa 3 bytes (100h a 102h), pois ela está armazenada do endereço 1175:1175:0100 até 1175:0102. Como nós trataremos apenas programas .COM, nós podemos por simplificação eliminar o endereço de base do segmento de código e indicar unicamente o offset. Assim podemos dizer que a instrução nop tem um tamanho de 1 byte e está armazenada em 108.
Para ver o código de máquina gerado por nosso programa nós podemos utilizar a instrução "u". Esta instrução desassembla uma certa região de memória indicada nos parâmetros. Como nosso programa está armazenado entre 100h e 108h, passamos estes dois endereços como parâmetro da instrução "u".
-a
1175:0100 B80200 MOV AX,0002
1175:0103 BB0400 MOV BX,0004
1175:0106 01D8 ADD AX,BX
1175:0108 90 NOP
Aqui podemos ver, por exemplo, que o código de máquina gerado pela instrução MOV AX,0002 são os 3 bytes B8.02.00. Para ver o código de máquina em memória sem ver o correspondente simbólico é somente usar o comando "d 100 108".
5. Teste do Programa
O Debug permite depurar programas através da execução passo-a-passo do programa. Isto é poderemos testar o programa executando instrução a instrução. Assim podemos acompanhar os valores dos registros e dos conteúdos das memórias envolvidas.
Inicialmente, antes de executarmos o passo-a-passo, você deve verificar se o valor do IP é 100h. Isto pois este registro, como vimos anteriormente, indica a próxima instrução a ser executada. Verifique então o valor de IP e se necessário atualize o valor para 100h. Após isso Ddigite o comando "t" (trace), para executar passo-a-passo este programa, assim:
-t
AX=0002 BX=0000 CX=0000 DX=0000 SP=FFFE BP=0000 SI=0000 DI=0000
DS=1175 ES=1175 SS=1175 CS=1175 IP=0103 NV UP EI PL NZ NA PO NC
6897:0100 BB0400 MOV BX,0004
Você pode ver que o valor 2 é movido para o registro AX. Note também que o valor de IP passa de 0100 para 0103, isto é, ele passa a apontar para a próxima instrução a ser executada. Digite o comando "t" novamente e você verá a segunda instrução se executar.
-t
AX=0002 BX=0004 CX=0000 DX=0000 SP=FFFE BP=0000 Sl=0000 Dl=0000
DS=l175 ES=l175 SS=l175 CS=1175 IP=0106 NV UP EI PL NZ NA PO NC
6897:0100 01D8 ADD AX,BX
Digite o comando "t" novamente para ver a instrução adição ser executada, você verá a seguinte linha:
-t
AX=0006 BX=0004 CX=0000 DX=0000 SP=FFFE BP=0000 Sl=0000 Dl=0000
DS=1175 ES=1175 SS=1175 CS=1175 IP=0108 NV UP EI PL NZ NA PO NC
6897:0100 90 NOP
Existe a possibilidade de que os registros contenham valores diferentes dos apresentados, mas AX e BX deverão ter os mesmos valores, desde que eles são os únicos que nós modificamos.A instrução NOP não realiza nenhuma operação, ela foi colocada aqui para indicar o fim de nosso programa.
Para sair do Debug use o comando "q" (quit)
6. Acesso a Memória
Na memória, cada byte tem um endereço único que vai de 00000h a FFFFFh. Dois bytes consecutivos são chamados de palavra (word) e poderá começar em endereço par ou impar da memória. Uma regra definida pela Intel (construtora do 8088), o byte mais significativo de um work é armazenado no endereço maior e o byte menos significativo no endereço menor. Execute o programa abaixo e veja as alterações na memória e registro.
Teste o programa abaixo.
MOV AH,[200] ; Movimenta o byte contido em 200h
para o registro AH
SUB AH,2 ; Subtrai de
2 o valor do registro AH
MOV [201],AH ; Armazena conteúdo de AH
na memória DS:201h
MOV AX,[200] ; Movimenta o word contido em 200h
para o registro AH
INC AX ;
Incrementa de 1 o valor do registro AH
MOV [205],AX ; Armazena conteúdo de AH
na memória DS:205h
7. Exercício
Faça um programa em assembly que realize as seguintes operacoes matemática: