Informática Numaboa - Tutoriais e Programação
Cap. III - Registradores do Microprocessador
Sab 15 Dez 2007 13:46 |
- Detalhes
- Categoria: MASM + RadASM
- Atualização: Segunda, 01 Março 2010 22:07
- Autor: Alan Moreno
- Acessos: 13228
Masm32+RadASM
Capítulo III: Registradores do Microprocessador
Escrito por: ^A|An M0r3N0^ Conselheiro: RedH@wk Tradução: ~Uglinho~O presente texto foi escrito para fins educacionais e de pesquisa e é de livre distribuição contanto que se preserve o conteúdo e os direitos do autor.
Registradores do Microprocessador
Nosso processador precisa de registradores para armazenar dados que podem ser utilizados livremente. Entre os principais registradores temos:
Registradores de propósito geral
São 4 registradores - EAX, EBX, ECX, EDX - que são empregados para uso geral. Subdividem-se em:
EAX, EBX, ECX, EDX (32 bits) | |
AX, BX, CX, DX (16 bits) | |
AH, BH, CH, DH (8 bits, H = High) | AL, BL, CL, DL (8 bits, L = Low) |
Exemplo:
EAX = 12345678 AX = 5678 AH = 56 AL = 78
O processador 80386 permite o uso destes registradores - EAX, EBX, ECX, EDX - que são de 32 bits.
Registradores de uso geral | Descrição |
EAX (Acumulador) | É utilizado para operações aritméticas (soma, subtração, divisão e multiplicação). Algumas funções, depois de serem utilizadas, devolvem um valor para EAX. |
EBX (Base) | É utilizado para direcionar o acesso a dados situados na memória. Também pode ser utilizado para operações aritméticas. |
ECX (Contador) | É utilizado como contador por algumas instruções. Também é utilizado para operações aritméticas. |
EDX (Dados) | Algumas operações de entrada/saída requerem seu uso e as operações de multiplicação e divisão com algarismos grandes supõem que EDX e EAX trabalhem juntos. Pode usar os registradores para soma e subtração de valores de 8, 16, 32 bits. |
. | |
Registradores de Índice | Descrição |
ESI | Este registrador de índice de 16 bits é requerido por algumas operações com cadeias (de caracteres). |
EDI | Este registrador de índice de destino também é requerido por algumas operações com cadeias de caracteres. |
. | |
Registradores de Bandeiras (Flags) | Descrição |
São usados para registrar a informação de estado e de controle das operações do microprocessador. São 9: CF, OF, ZF, SF, PF, AF, DF, IF, TF. |
Instruções do microprocessador
As instruções são sequências de bits (uns e zeros). Indicam qual operação deve ser feita e com que dados operação deve ser realizada. Por enquanto veremos 11 instruções:
Esta instrução MOV significa mover e se encarrega de passar o conteúdo do operando Fonte para o do Destino. Na programação devemos respeitar as seguintes regras: Destino - Podem ser variáveis e registradores de 8, 16 e 32 bits; Fonte - Podem ser variáveis, registros do Windows e valores inteiros.
A instrução ADD significa Somar. Soma o conteúdo dos dois operandos e o resultado é repassado para o operando Destino.
Destino - Podem ser variáveis e registradores de 8, 16 e 32 bits. Fonte - Podem ser variáveis, registros do Windows e valores inteiros.
A instrução SUB significa Subtrair. Subtrai o conteúdo do operando Fonte do Destino e o resultado é armazenado no operando Destino.
Destino - Podem ser variáveis e registradores de 8, 16 e 32 bits. Fonte - Podem ser variáveis, registros do Windows e valores inteiros.
Estas instruções incrementam e decrementam respectivamente o valor contido no operando Destino. Destino - Podem ser variáveis e registradores de 8, 16 e 32 bits.
PUSH se encarrega de guardar o conteúdo do operando Fonte na Pilha. Fonte - Podem ser variáveis, valores inteiros e registradores de 16 e 32 bits.
Ao contrário de PUSH, esta instrução recupera o conteúdo guardado na pilha. Destino - Podem ser variáveis e registradores de 16 e 32 bits.
Quando guardamos vários valores com a instrução PUSH e quiseremos recuperar estes valores, utilizamos a instrução POP respeitando a seguinte regra:
"O último valor guardado será o primeiro a ser recuperado".
Para instruções lógicas: Utilize a calculadora do Windows (no modo científico) para passar para os sistemas decimal, hexadecimal e binário os valores indicados.
Realiza a operação lógica AND entre os operandos Fonte e Destino, bit a bit, e o resultado é repassado para o operando Destino.
TABELA VERDADE AND | ||
A | B | Resultado |
0 | 0 | 0 |
0 | 1 | 0 |
1 | 0 | 0 |
1 | 1 | 1 |
Exemplo:
1110 (14 decimal ou E hexadecimal) 1101 (13 decimal ou D hexadecimal) ---- 1100 (12 decimal ou C hexadecimal)
Realiza a operação lógica OR entre os operandos, bit a bit, e o resultado é repassado para o operando Destino.
TABELA VERDADE OR | ||
A | B | Resultado |
0 | 0 | 0 |
0 | 1 | 1 |
1 | 0 | 1 |
1 | 1 | 1 |
Exemplo:
1110 (14 decimal ou E hexadecimal) 1101 (13 decimal ou D hexadecimal) ---- 1111 (15 decimal ou F hexadecimal)
A instrução NOT inverte os bit no operando Destino.
TABELA VERDADE NOT | |
A | Resultado |
0 | 1 |
1 | 0 |
Exemplo:
1101 (13 decimal ou D hexadecimal) ---- 0010 (2 decimal ou 2 hexadecimal)
Realiza a operação lógica XOR entre os operandos, bit a bit, e o resultado é repassado para o operando Destino.
TABELA VERDADE XOR | ||
A | B | Resultado |
0 | 0 | 0 |
0 | 1 | 1 |
1 | 0 | 1 |
1 | 1 | 0 |
Exemplo:
1110 (14 decimal ou E hexadecimal) 1101 (13 decimal ou D hexadecimal) ---- 0011 (3 decimal ou 3 hexadecimal)
Todas as operações lógicas que vimos têm a seguinte regra: Fonte - Podem ser variáveis, valores e registradores de 16 e 32 bits; Destino - Podem ser variáveis e registradores de 16 e 32 bits.
Exercícios com instruções
Abrimos o arquivo prog002a com a nossa IDE RadAsm, onde encontramos o seguinte:
Faça o download de prog002a.zip.
No arquivo .INC está declarada a variável Valor_1 do tipo DD.
Quando queremos declarar números em Hexadecimal, devemos escrever o caractere h no final do valor. Se não houver nenhum caractere no final, significa que é decimal.
Quando quisermos declarar números binários, devemos escrever o caractere b no final do valor inteiro. Nas operações lógicas, se quisermos comprovar os resultados, podemos verificar a tabela verdade correspondente a cada operação.
O programa acima é só um exemplo de como usar apropriadamente as instruções. Agora vamos dar sentido ao nosso programinha.
Temos 5 valores inteiros:
1 - 1Ah 2 - 500 3 - 1C2h 4 - 13h 5 - 200
Faremos um programa que faça a seguinte operação:
- 1Ah + 500 = X
- Do resultado X subtraímos 1C2h: X – 1C2h = Y
- Guardamos o resultado Y na Pilha ou numa variável e depois somaremos as quantidades que até agora não utilizamos, desta maneira:
- 13h + 200 = Z
- Recuperamos o resultado Y e dele subtraímos a quantidade do resultado Z. O resultado final deve ser armazenado no registrador EAX.
Solução Nº1 (prog002b)
No arquivo .inc declaramos a variável Y tipo DD.
O resultado final é EAX = 143.
Faça o download de prog002b.zip.
Solução Nº2 (prog002c)
Todos os valores estão declarados no arquivo .inc do nosso programa onde:
Há muitas soluções, não só estas duas. Se vocês desejarem aprender mais, devem desenvolver suas próprias soluções.
Faça o download de prog002c.zip.
Mostrando resultados
No nosso código anterior não é mostrado o resultado da operação aritmética. Para isto devemos conhecer as seguintes funções de conversão da masm32.lib:
Esta função converte cadeias de texto (quantidades decimais) para seu valor inteiro e a quantidade convertida será devolvida para EAX. Exemplo:
Esta função é semelhante à atodw, mas trabalha com quantidades hexadecimais e as converte para o seu valor inteiro. A quantidade convertida será devolvida para EAX.
Esta função converte valores inteiros em cadeias de texto decimal. Seria o contrário da função atodw.
Quantidade - Neste parâmetro se pode utilizar variáveis, valores inteiros e registros do windows. Exemplo:
Esta função possui os mesmos parâmetros da função dwtoa, com a diferença de que o resultado é uma quantidade de texto hexadecimal. É o contrário da função htodw.
Nos exemplos a seguir utilizaremos todas as funções mencionadas. Preste muita atenção em cada detalhe.
1 - No exercício seguinte mostraremos o resultado em decimal e hexadecimal em uma mensagem:
Para assistir ao vídeo, faça o download de prog002d.exe.
2 - Faremos um programa que soma cadeias de texto com quantidades decimal e hexadecimal e que, no final, deve mostrar o resultado:
Para assistir ao vídeo, faça o download de prog003.exe.
No exemplo prog003.exe observamos que tínhamos quantidades em decimal e hexadecimal (cadeias de texto) e depois, para somar estas quantidades, as convertemos para valores inteiros com as funções atodw e htodw para que pudéssemos operar com instruções do processador como a de somar (ADD) e mover (MOV). Depois, para mostrar o resultado, devemos converter os valores inteiros para cadeias de texto com as funções dwtoa e dw2hex respectivamente:
Esquema do trabalho:
Vejamos outro exemplo de conversão. Lembre-se de estar sempre atento a cada detalhe do vídeo:
Para assistir ao vídeo, faça o download de prog003a.exe.
Foi trabalhado diretamente com valores inteiros declarados em nosso arquivo .inc, cujas quantidades foram somadas. Depois, para mostrar o resultado, convertemos para cadeias de texto dwtoa e dw2hex, respectivamente.
Esquema de trabalho:
Assim levamos em conta a conversão de valores inteiros para cadeias e vice-versa.
Nota: Nunca podemos mostrar valores inteiros. Para fazer isto devemos converter os valores para cadeias de texto.
Criando suas próprias funções
1 - Agora criaremos uma função que mostre uma mensagem. Esta função terá um parâmetro para indicar o endereço da etiqueta da mensagem. Dentro da função que vamos criar se encontra a API MessageBox, que será reponsável por mostrar a mensagem.
Para assistir ao vídeo, faça o download de prog004.exe.
Como observamos no vídeo, primeiro declaramos a função que vamos utilizar:
PROC - Esta diretiva serve para definir um procedimento ou chamado que se irá utilizar e sua sintaxe é assim:
Nome_da_Funcao PROC Argumento/s (se tiver um) RET Nome_da_Funcao endp
Se nossa função precisar de um parâmetro, sua sintaxe seria assim:
Nome_da_Funcao PROC Parametro01: Tipo de variável RET Nome_da_Funcao endp
Se nossa função precisar de mais de um parâmetro, é necessário separar com "," (virgulas) cada parâmetro, desta maneira:
Nome_da_Funcao PROC Prmtr01: Tipo de variável, Prmtr02: Tipo de variável, etc. RET Nome_da_Funcao endp
Tipo de variável - Aqui declaramos o comprimento em bytes que se precisa, ou seja: DWORD, WORD, BYTE. Em geral sempre se declara a variável usando o maior comprimento (tamanho) como DWORD.
Nome_da_Funcao - Aqui escrevemos nossa etiqueta para o nome da função. Lembre-se de que esta etiqueta não deve se repetir e que a etiqueta dos parâmetros não deve ser declarada em outra parte do código.
Com esta instrução retornamos do procedimento que chamamos. Também a utilizamos para separar nossos códigos, como no primeiro RET que vem depois da função ExitProcess. O operando Nº Bytes é opcional. Especifica quantos bytes devem retornar.
Outro ponto importante é que, se utilizarmos algumas das variáveis que declaramos nos parâmetros do procedimento da função, como por exemplo MsgT, já não é necessário utilizar addr ou offset. Um exemplo é a variável que foi utilizada no 3º parâmetro da Api MessageBox:
Já criamos nossa função. Se quisermos utilizá-la com a diretiva invoke, ficaria assim - como fizemos no vídeo:
É necessário declarar os protótipos com a diretiva PROTO.
PROTO - Serve para definir os protótipos das funções para que possam ser usadas com invoke. Também informa ao MASM o número de argumentos e o tipo de variável que deve ser usada no momento de se chamar uma função. Sua sintaxe é:
PROTO é semelhante à diretiva PROC porque ambas trabalham em conjunto. A diferença está na declaração dos tipos de variáveis. O número de variáveis que declaramos depende dos parâmetros da função, por exemplo:
É necessário declarar os protótipos com a diretiva PROTO.
PROTO - Serve para definir os protótipos das funções para que possam ser usadas com invoke. Também informa ao MASM o número de argumentos e o tipo de variável que deve ser usada no momento de se chamar uma função. Sua sintaxe é:
PROTO é semelhante à diretiva PROC porque ambas trabalham em conjunto. A diferença está na declaração dos tipos de variáveis. O número de variáveis que declaramos depende dos parâmetros da função, por exemplo:
só contém um parâmetro e o definimos desta maneira:
Se nossa função tiver mais de um parâmetro, declara-se as variáveis separando-as com "," (virgulas). Por exemplo, a função MessageBoxA, que está no arquivo user32.inc, quando utilizada precisa de 4 parâmetros:
Nota - Não se esqueça de que se deve respeitar as maiúsculas e minúsculas quando nos referirmos a qualquer variável ou um nome de função porque, se não o fizermos, na hora de compilar o masm32 nos devolverá erros.
2 - Criaremos uma função que subtraia 2 quantidades e, depois de regressar da função, o resultado deve ser devolvido ao registro EAX. No final deve mostrar o resultado em decimal.
Para assistir ao vídeo, faça o download de prog004a.exe.
Dentro da nossa função Resta, colocamos 2 instruções para poder subtrair quantidades. Já sabemos como estas instruções são utilizadas porque tudo já foi bem explicado. Depois, o resultado é armazenado em EAX e, ao retornar da função, convertemos o valor inteiro em cadeias de texto (recordar que a função de conversão está na biblioteca masm32.lib) para poder mostrar o resultado com a API MessageBox.
Nota - Na função criada pode-se usar valores como também variáveis e registradores de 8, 16, 32 bits por que tudo isto se inclui em DWORD.
Exercícios
- Temos 3 valores - 800, 400, 100 (decimais) - em cadeias de texto e
queremos um programa que faça a seguinte operação:
800 – 450 = X
e deve-se substrair 100 do resultado X para obter Y. Este resultado deve ser mostrado. - Criar um programa que some 5 quantidades e a soma destas quantidades serão reduzidas em 225 decimal. As 5 quantidades podem ser qualquer valor inteiro, desde que sejam em decimal ou hexadecimal. Se quiser mostrar o resultado, faça-o.
- Criar uma função que tenha 2 parâmetros para que mostre uma mensagem
portanto:
O primeiro parâmetro - Aqui se colocará o endereço da etiqueta da Mensagem que se irá mostrar.
O segundo parâmetro - Aqui se colocará o endereço da etiqueta do título da mensagem.
Vocabulário
Pilha ou stack - A pilha é uma área de memória que pode ser utilizada para o armazenamento temporário de dados. Só 2 instruções trabalham com a pilha: são o PUSH (guarda) e o POP (recupera).
Lembrando
Não esquecer de perguntar na lista MASM32-RadASM. As soluções destes exercícios serão enviados para a lista dentro de uma semana. Vocês também podem enviar suas prórias soluções.
Se tiverem dúvidas, sugestões ou outros, faça-as na lista de discussão.
O autor pode ser contactado
eMail: O endereço de e-mail address está sendo protegido de spambots. Você precisa ativar o JavaScript enabled para vê-lo. ou O endereço de e-mail address está sendo protegido de spambots. Você precisa ativar o JavaScript enabled para vê-lo.
Lista de discussão MASM32-RadASM
http://groups.google.es/group/MASM32-RadASM
www
Copyright(c) 2005-2006 RVLCN
Recado da vó
Aqui está o código fonte dos exercícios deste tutorial: