Informática Numaboa - Tutoriais e Programação
Assembly e Registradores
Ter 21 Abr 2009 15:20 |
- Detalhes
- Categoria: Assembly Numaboa (antigo oiciliS)
- Atualização: Terça, 21 Abril 2009 16:05
- Autor: vovó Vicki
- Acessos: 25531
Registradores são áreas de trabalho especiais dentro do processador que são mais rápidas que operandos de memória. Estas áreas foram projetadas para trabalharem com códigos operacionais.
Os registradores de um processador Intel ou compatível representam um recurso muito limitado quando se escreve em assembly. Existem apenas 8 registradores de uso geral: EAX, EBX, ECX, EDX, ESI, EDI, ESP e EBP. Na maioria dos casos, ESP e EBP não deveriam ser utilizados porque são usados principalmente para entrada e saída de procedimentos.
Na prática, isto significa que você possui apenas 6 registradores de 32 bits para escrever seu código, além de outras localizações de memória que sejam úteis ao procedimento. ESI e EDI podem ser usados normalmente na maior parte das vezes, porém nem um dos dois pode ser acessado em nível de BYTE. Você pode fazer a leitura do WORD menos significativo (baixo) de ESI como SI e do WORD menos significativo de EDI como DI.
É muito importante entender o tamanho dos registradores e os dados que eles podem armazenar. Um processador de 32 bits (Intel ou compatível) tem três tamanhos nativos de dados que podem ser utilizados pelas instruções normais com números inteiros: BYTE, WORD e DWORD que correspondem a 8 bits, 16 bits e 32 bits.
Isto pode ser mostrado através da notação HEXAdecimal.
BYTE 00 WORD 00 00 DWORD 00 00 00 00
Em termos de registradores, isto corresponde aos três tamanhos que podem ser endereçados com os registradores normais para números inteiros. Os processadores Intel são compatíveis com código mais antigo que ainda usa registradores de 8 e 16 bits. Esta compatibilidade é obtida acessando qualquer um dos registradores de uso geral de três modos diferentes. Usando o registrador EAX como exemplo:
AL ou AH = 8 bits AX = 16 bits EAX = 32 bits
Este é o esquema de um registrador de 32 bits de uso geral. Considerando o registrador EAX como exemplo:
Este esquema é mais fácil de entender em nível de bit. Lendo da direita para a esquerda, você tem 32 bits no registrador (bit 0 a 31). Devido à posição dos bits de cada porção de dados que pode ser acessada num registrador de 32 bits, AL é chamado de byte menos significativo ou baixo (LOW byte), AH é chamado de byte mais significativo ou alto (HIGH byte) e AX é chamado de palavra (WORD) menos significativa (LOW word).
Existem também oito registradores de 80 bits que são utilizados para ponto flutuante e para a execução de instruções MMX de 64 bits. Processadores mais atuais também possuem oito registradores XMM de 128 bits XMM capazes de utilizar plenamente as instruções SSE e SSE2.
Como usar os registradores
Algumas instruções usam determinados registradores para realizar tarefas em particular; algumas instruções são mais rápidas se determinados registradores forem usados; em processadores mais antigos nem todos os registradores podem realizar todas as tarefas que os registradores de processadores mais atuais são capazes de realizar. Estes três fatores, associados ao uso tradicional que os programadores estabeleceram ao longo dos anos, acabaram ditando o modo como os registradores devem ser utilizados. Não é lei, são regras que podem ajudar muito. Veja abaixo:
- Use EAX para passar dados para um procedimento e para retornar dados do procedimento para o código que fez a chamada. As APIs do Windows também usam EAX para retornar um valor para o chamador. AL, AX e EAX também deveriam ser usados, na medida do possível, para receber e para transferir dados de e para a memória, por que são ligeiramente mais rápidos que outros registradores. Por exemplo, use MOV AL,[ESI] ao invés de MOV DL,[ESI]. Também nos casos de ADD, AND, ADC, CMP, MOV, OR, SUB, TEST, XCHG, XOR com um valor imediato (isto é, um número como MOV AL,23h), se possível, use AL, AX ou EAX, por que o número de códigos operacionais destas instruções é menor do que se usadas com outros registradores.
- Use o registrador EDX como um "estepe" para EAX se este estiver em uso.
- Use o registrador ECX como contador. JECXZ é uma instrução especial que indica se o valor de ECX é zero e a série de instruções LOOP, SCAS e MOVS usam ECX como contador.
- Use EBX para armazenar dados em geral ou para endereços de memória, por exemplo MOV EAX,[EBX] ou MOV [EBX],EDX.
- Use ESI quando precisar ler a memória, por exemplo MOV EAX,[ESI], e EDI quando precisar escrever na memória, por exemplo MOV [EDI],EAX. Isto é consistente com as instruções LODSD, STOSD e MOVSD.
- Use qualquer um dos registradores como base ou registrador index em instruções de memória complexas, por exemplo MOV EAX,[MemPtr+ESI*4+ECX].
- Nunca use ESP para outra coisa que não seja um ponteiro da pilha, a não ser que sua rotina não tenha absolutamente nenhuma atividade de pilha. Neste caso você pode salvar o valor de ESP na memória e restaurá-lo antes de voltar para a rotina chamadora.
- Tradicionalmente o EBP é usado para endereçar dados locais na pilha em rotinas de callback. O EBP e seu componente de 16 bits BP podem ser usados como um registrador geral na programação Windows, mas você deve tomar muito cuidado se estiver usando frames de pilha (stack frames - FRAME no GoAsm) ou dados locais (LOCAL no GoAsm). Isto porque parâmetros de frames de pilha e dados locais são endereçados usando o valor positivo ou negativo de EBP. Depois do EBP ter sido alterado, os parâmetros e os dados locais não podem ser acessados até que o valor original de EBP tenha sido restaurado.
- CS, DS e SS ainda são utilizados pelo Windows, mesmo se o código for de 32 bits, por isso não devem ser usados. Atualmente, nem ES, FS ou GS podem ser utilizados. Depois do Windows 98 isto gera uma exceção.
- Se precisar usar os registradores comuns para armazenar uma informação de 64 bits use EDX:EAX, onde EDX guarda os bits mais significativos. Isto está de acordo com as instruções shift de 64 bits SHLD e SHRD, como também com CDQ.
Algumas dicas
Para ler o primeiro BYTE do registrador (bits 0 a 7), use mov valorDoByte, al para mover o valor do tamanho do 1o. byte para uma variável.
Para ler o segundo BYTE do registrador (bits 8 a 15), use mov valorDoByte, ah para mover o valor do tamanho do 2o. byte para uma variável.
Se você quiser ler a primeira palavra (WORD) do registrador (bits 0 a 15), use mov valorDoWord, ax para mover o valor do 1o. word para uma variável.
Para obter os bits 16 a 31, você precisa rodar (rotate) os bits no registrador para que possam ser acessados pela instrução acima. Rodando um registrador de 32 bits em qualquer direção em 16 bits vai deslocar os 16 bits de LOW para HIGH e os 16 bits de HIGH para LOW. Use rol eax, 16 para rodar EAX para a esquerda em 16 bits ou ror eax, 16 para rodar EAX para a direita em 16 bits.
Você precisa usar os tamanhos corretos de dados para colocá-los num registrador e não pode misturar tamanhos diferentes de registradores. Por exemplo, mov eax, cl não funciona porque eax é de 32 bits e cl é de 8 bits.
Se você precisar por o valor de CL em um registrador de 32 bits, primeiro precisa converter este valor usando várias técnicas diferentes: movzx eax, cl move um inteiro zero estendido sem sinal e movsx eax, cl move um inteiro estendido com sinal.
Em alguns casos você pode usar xor eax, eax para zerar (limpar) eax e mov al, cl para copiar cl para al.
E ainda existem alguns mnemônicos mais antigos que farão a conversão: mov al, cl copia cl para al, cbw converte o BYTE em AL para um WORD em AX e cwde converte um WORD em AX para um DWORD em EAX.