Informática Numaboa - Tutoriais e Programação
Instruções assembly mais comuns
|
Sex 19 Jun 2009 14:29 |
- Detalhes
- Categoria: Assembly Numaboa (antigo oiciliS)
- Atualização: Sábado, 20 Junho 2009 16:42
- Autor: vovó Vicki
- Acessos: 52701
A linguagem Assembly a ser utilizada depende essencialmente do processador ao qual se destina, ou seja, é dependente da arquitetura da CPU. A seguir estão algumas das instruções mais utilizadas para processadores da família Intel. Para que possam ser entendidas perfeitamente, é preciso ter uma boa noção da arquitetura do microprocessador. Caso tenha dúvidas, leia antes "Arquitetura Intel".
Instrução AND
| AND | |
|---|---|
| Sintaxe | and destino,fonte |
| Lógica | destino <- destino AND fonte |
| Descrição | AND realiza uma operação lógica AND bit a bit nos seus operandos e põe o resultado no destino. |
| Flags | CF <- 0 OF <- 0 CF OF PF SF ZF (AF indefinido) |
Há 5 modos diferentes de se ANDar dois números:
- AND dois registradores
- AND um registrador com uma variável
- AND uma variável com um registrador
- AND um registrador com uma constante
- AND uma constante com um registrador
Ou seja:
Observe que as constantes estão em notação hexadecimal e binária, as únicas aceitas por que são o único meio de expressar números bit a bit. É claro que a notação hexadecimal precisa ser convertida em 4 dígitos binários. AND retorna 1 quando ambos os operandos forem 1, senão retorna zero, conforme a tabela abaixo:
| Operando 1 | Operando 2 | Resultado |
|---|---|---|
| 1 | 1 | 1 |
| 1 | 0 | 0 |
| 0 | 1 | 0 |
| 0 | 0 | 0 |
Pode-se verificar se um registrador está zerado utilizando a instrução AND, como em and ecx,ecx. Caso algum bit em ecx estiver setado (valor 1), este mesmo bit estará setado no resultado e a flag zero (ZF) estará zerada (valor falso). Se não houver bits setados, o resultado também não terá bits setados e a flag zero (ZF) recebe o valor 1. Nenhum bit será alterado e ecx mantém o seu valor original. Este é o modo padrão de se checar valores zerados. Uma alternativa para este teste é usando a instrução TEST.
Também é possível testar uma variável com uma constante (fazer AND em duas variáveis dá erro!). No caso de and variável1, 11111111b testa-se todos os bits da variável1 com bits setados. Se algum bit da variável1 estiver setado, aparece setado no resultado e ZF = 0; se todos estiverem zerados, continuam zerados no resultado e ZF = 1. O valor da variável1, em ambos os casos, não é alterado.
AND também é utilizado em máscaras. Caso se queira testar o bit na posição 0 do registrador ecx, podemos utilizar a instrução and ecx, 00000001b. O estado deste bit (setado ou zerado) será transportado para o resultado enquanto todos os outros serão zerados.
Instrução CMP
| CMP | |
|---|---|
| Sintaxe | CMP destino, fonte |
| Flags | AF CF OF PF SF ZF |
| Descrição | Subtrai a fonte do destino, atualiza as flags porém não armazena o resultado. |
A fonte pode ser um registrador, um endereço de memória ou um valor. O destino pode ser um registrador ou um endereço de memória. Exemplos:
Instrução DEC
| DEC |
|---|
| Decrementa o valor de um registrador ou de uma variável em 1. |
Exemplos:
Instrução INC
| INC |
|---|
| Incrementa o valor de um registrador ou de uma variável em 1. |
Exemplos:
Instruções de salto
Apenas os principais tipos de salto (jump) estão na tabela abaixo:
| Asm | Hexa | Descrição |
|---|---|---|
| ja | 77 ou 0F87 | salte se acima (jump if above) |
| jae | 73 ou 0F83 | salte se acima ou igual (jump if above or equal) |
| jb | 72 ou 0F82 | salte se abaixo (jump if below) |
| jbe | 76 ou 0F86 | salte se abaixo ou igual (jump if below or equal) |
| je | 74 ou 0F84 | salte se igual (jump if equal) |
| jg | 7F ou 0F8F | salte se maior (jump if greater) |
| jge | 7D ou 0F8D | salte se maior ou igual (jump if greater or equal) |
| jl | 7C ou 0F8C | salte se menor (jump if less) |
| jle | 7E ou 0F8E | salte se menor ou igual (jump if less or equal) |
| jmp | EB ou E9 | salto incondicional |
| jna | 76 ou 0F86 | salte se não acima (jump if not above) |
| jnae | 72 ou 0F82 | salte se não acima ou igual (jump if not above or equal) |
| jnb | 73 ou 0F83 | salte se não abaixo (jump if not below) |
| jnbe | 77 ou 0F87 | salte se não abaixo ou igual (jump if not below or equal) |
| jne | 75 ou 0F85 | salte se não igual (jump if not equal) |
| jng | 7E ou 0F8E | salte se não maior (jump if not greater) |
| jnge | 7C ou 0F8C | salte se não maior ou igual (jump if not greater or equal) |
| jnl | 7D ou 0F8D | salte se não menor (jump if not less) |
| jnle | 7F ou 0F8F | salte se não menor ou igual (jump if not less or equal) |
| jnz | 75 ou 0F85 | salte se não zero (jump if not sero) |
| jz | 74 ou 0F84 | salte se zero (jump if zero) |
Instrução MOV
| MOV | |
|---|---|
| Sintaxe | MOV destino, fonte |
| Flags | nenhuma |
| Descrição | Copia um byte ou word do operando fonte para o operando destino. |
A instrução MOV transfere (MOVe) o conteúdo da fonte para o destino. Ao se executar a transferência, o conteúdo da fonte fica preservado e o conteúdo do destino é substituído pelo conteúdo da fonte.
Instruções NEG e NOT
NOT é uma operação lógica e NEG é uma operação aritmética. Ambas são descritas em conjunto para que as diferenças fiquem claras. NOT alterna o valor de cada bit individual:
| ||||||||||||||||||||
NEG subtrai o operando destino de 0 e retorna o resultado a este mesmo destino. O efeito é um complemento de dois do operando. O operando também pode ser um byte ou um word. NEG nega o valor do registrador ou da variável numa operação COM sinal.
NEG executa (0 - número), ou seja:
é o mesmo que (0 - EAX) e (0 - variável1) respectivamente. NEG atualiza as flags da mesma maneira que (0 - número). Se o operando for 0 (zero), a flag de carry (CF) é zerada. Em todos os outros casos, a CF é setada para 1.
Instrução OR
| OR | |
|---|---|
| Sintaxe | or destino,fonte |
| Lógica | destino <- destino OR fonte |
| Descrição | OR realiza uma operação lógica OR INCLUSIVE bit a bit nos seus operandos e põe o resultado no destino. Todos os bits ativos em qualquer dos operandos estará ativo no resultado. |
| Flags | CF OF PF SF ZF (AF indefinido) |
OR retorna 0 quando ambos os operandos forem 0, senão retorna 1, conforme a tabela abaixo:
| Operando 1 | Operando 2 | Resultado |
|---|---|---|
| 1 | 1 | 1 |
| 1 | 0 | 1 |
| 0 | 1 | 1 |
| 0 | 0 | 0 |
OR é usado para ativar bits específicos. No exemplo a seguir, apenas o bit da posição 7 é ativado e os restantes não sofrem alteração:
OR também pode ser utilizado para checar se um registrador está zerado ou não porque o resultado atualiza o estado da flag de zero (ZF). Por exemplo:
Instrução POP
| POP | |
|---|---|
| Sintaxe | POP destino |
| Descrição | OR Transfere o word do topo da pilha (SS:SP) para o destino e incrementa SP em dois para apontar para o novo topo da pilha. CS não é um destino válido. |
| Flags | nenhuma |
O destino pode ser um registrador ou um endereço de memória. A pilha é uma área de memória que armazena dados temporariamente. O registrador SP (stack pointer) sempre contém o endereço da localização que corresponde ao topo da pilha. O princípio de funcionamento da pilha é "último a entrar - primeiro a sair". A pilha é utilizada principalmente pelas instruções push, pop, call e return.
Instrução PUSH
| PUSH | |
|---|---|
| Sintaxe | PUSH fonte PUSH valor (apenas para 80188+) |
| Descrição | Decrementa SP pelo tamanho do operando (dois ou quatro, valores byte são estendidos por sinal) e transfere um word da fonte para o topo da pilha (SS:SP). |
| Flags | nenhuma |
A fonte pode ser um registrador, um endereço de memória ou um valor literal. A pilha é uma área de memória que armazena dados temporariamente. O registrador SP (stack pointer) sempre contém o endereço da localização que corresponde ao topo da pilha. O princípio de funcionamento da pilha é "último a entrar - primeiro a sair". A pilha é utilizada principalmente pelas instruções push, pop, call e return.
Instruções REP, REPE e REPNE
| REP / REPE / REPNE | ||
|---|---|---|
| REP (repeat / repetir), REPE (repeat if equal / repetir se igual) e REPNE (repeat if not equal / repetir se não for igual) são prefixos para instruções string que forçarão a repetição das instruções de acordo com as seguintes condições: | ||
| Prefixo | ECX | Efeito |
| rep | decrementa ecx | repetir se ecx não for zero |
| repe | decrementa ecx | repetir se ecx não 0 e ZF = 1 |
| repz | decrementa ecx | repetir se ecx não 0 e ZF = 1 |
| repne | decrementa ecx | repetir se ecx não 0 e ZF = 0 |
| repnz | decrementa ecx | repetir se ecx não 0 e ZF = 0 |
REPE e REPZ (repeat if zero / repetir se zero) têm o mesmo efeito. O mesmo acontece com REPNE e REPNZ (repeat if not zero / repetir se diferente de zero).
Instrução SCAS
| SCAS |
|---|
| SCAS compara AL (ou AX) com o byte (ou word) apontado por ES:[DI] e incrementa (ou decrementa) DI dependendo do valor de DF, a flag de direção. O incremento ou decremento é feito de 1 em 1 para bytes e de 2 em 2 para words. OVERRIDES NÃO SÃO PERMITIDOS. |
As formas permitidas são:
Instrução SHL
| SHL | |
|---|---|
| Uso | SHL destino, vezes |
| Descrição | Desloca os bits do destino para a esquerda as "vezes" indicadas com zeros colocados à direita. A flag de carry conterá o valor do último bit deslocado. |
| Flags | CF OF |
O destino pode ser um registro ou um endereço de memória. As "vezes" podem ser valores ou CL.
| ... | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | Descrição | Carry |
|---|---|---|---|---|---|---|---|---|---|---|
| ... | 1 | 1 | 1 | 1 | 0 | 0 | 0 | 0 | ||
| ... | 1 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | SHL eax,1 | 1 |
| ... | 1 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | SHR eax,2 | 1 |
| ... | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | SHR eax,2 | 0 |
Instrução SHR
| SHR | |
|---|---|
| Uso | SHR destino, vezes |
| Descrição | Desloca os bits do destino para a direita as "vezes" indicadas com zeros colocados à esquerda. A flag de carry conterá o valor do último bit deslocado. |
| Flags | CF OF |
O destino pode ser um registro ou um endereço de memória. As "vezes" podem ser valores ou CL.
| ... | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | Descrição | Carry |
|---|---|---|---|---|---|---|---|---|---|---|
| ... | 1 | 1 | 1 | 1 | 0 | 0 | 0 | 0 | ||
| ... | 0 | 1 | 1 | 1 | 1 | 0 | 0 | 0 | SHR eax,1 | 0 |
| ... | 0 | 0 | 0 | 1 | 1 | 1 | 1 | 0 | SHR eax,2 | 0 |
| ... | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 1 | SHR eax,2 | 1 |
Instrução SUB
| SUB | |
|---|---|
| Sintaxe | SUB destino, fonte |
| Lógica | destino <- destino - fonte |
| Descrição | Subtrai a fonte do destino e o resultado é armazenado no destino. |
| Flags | AF CF OF PF SF ZF |
Ambos os operandos podem ser bytes ou words e ambos também podem ser números binários com ou sem sinal.
Instrução TEST
| TEST | |
|---|---|
| Sintaxe | TEST destino, fonte |
| Lógica | (destino AND fonte) |
| Descrição | TEST realiza uma operação lógica AND bit a bit nos seus operandos sem alterá-los. Apenas modifica as flags. |
| Flags | CF <- 0 OF <- 0 CF OF PF SF ZF (AF indefinido) |
Esta instrução é uma variação da instrução AND. TEST faz exatamente o mesmo que AND, apenas descarta os resultados obtidos. Não modifica o destino. Isto significa que pode checar coisas específicas sem alterar os dados. Em outras palavras, TEST faz um AND lógico em seus dois operandos e atualiza as flags sem modificar o destino e a fonte.
Para otimizar a velocidade, quando comparar um valor num registrador com 0, use o comando TEST. Use TEST quando for comparar o resultado de um comando lógico AND com uma constante imediata se o registrador utilizado for EAX. Também pode ser usado para testar se determinado valor é zero (exemplo: test ebx,ebx seta a flag zero (ZF) se EBX for zero).
TEST é muito útil para examinar o status de bits individuais. Por exemplo, o snippet abaixo passará o controle para UM_CINCO_OFF se ambos os bits 1 e 5 do registrador AL estiverem zerados (lembre-se de que os bits são numerados de 0 a 7 em ordem inversa). O status de todos os outros bits será ignorado.
TEST oferece as mesmas possibilidades que AND:
Um bom exemplo é para a placa de vídeo. Em modo texto, a tela tem 80 x 25 pixels, perfazendo 2000 células. Cada célula possui um byte de caracter e um byte de atributos. O byte do caracter é o valor ASCII do mesmo. O byte de atributos indica a cor do caracter, a cor de fundo, se o caracter está em alta ou baixa intensidade ou se está piscando. Um byte de atributos tem a seguinte aparência:
| 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
| X | R | G | B | I | R | G | B |
Os bits 0, 1 e 2 (RGB) indicam a cor do caracter. 2 é vermelho (Red), 1 é verde (Green) e 0 é azul (Blue). Os bits 4, 5 e 6 (RGB) contém a cor de fundo do caracter, onde 6 é vermelho (Red), 5 é verde (Green) e 4 é azul (Blue). O bit 3 indica alta intensidade e o bit 7 é piscante. Se o bit estiver setado (valor 1), o componente correspondente está ativado. Se o bit estiver zerado, o componente correspondente está desativado.
A primeira coisa que chama a atenção é o quanto de memória é economizado pelo fato das informações estarem todas juntas. Claro que seria possível usar um byte para cada uma das características, mas a memória requerida seria de 8 x 2 000 bytes = 16 000 bytes. Se adicionarmos os 2 000 bytes referentes aos caracteres, o total já seria 18 000 bytes. Da forma explicada acima, obtém-se o mesmo resultado com apenas 4 000 bytes, ou seja, uma economia de 75%. Como há quatro telas (páginas) diferentes numa placa com cores, os totais seriam 72 000 (18 000 x 4) contra 16 000 (4 000 x 4).
Imagine agora que um dos bytes de atributos esteja no registrador DL - pode-se achar quais os bits que estão setados, bastando para isto fazer um TEST DL com um padrão de bits específico. Se a flag zero (ZF) for setada, significa que o resultado é zero e que o bit estava zerado.
A flag zero (ZF) indica se o componente está ativo ou desativo. Esta flag não vai mostrar se a cor de fundo é azul, porque o vermelho e o verde do fundo também podem estar setados. Apenas um dos componentes pode ser testado em cada test. E lembre-se: TEST não altera os valores da fonte ou do destino, apenas atualiza as flags.
Máscaras
Usaremos o byte de atributos do monitor para exemplificar o uso de máscaras.
| 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
| X | R | G | B | I | R | G | B |
Os bits 0, 1 e 2 (RGB) indicam a cor do caracter. 2 é vermelho (Red), 1 é verde (Green) e 0 é azul (Blue). Os bits 4, 5 e 6 (RGB) contém a cor de fundo do caracter, onde 6 é vermelho (Red), 5 é verde (Green) e 4 é azul (Blue). O bit 3 indica alta intensidade e o bit 7 é piscante. Se o bit estiver setado (valor 1), o componente correspondente está ativado. Se o bit estiver zerado, o componente correspondente está desativado.
Caso se queira ativar ou desativar determinados bits, sem alterar o valor dos outros, podemos lançar mão de uma máscara AND: and byte_do_video, 10001111b. Lembrando que a instrução AND retorna 1 apenas quando ambos os bits estiverem setados (tiverem valor 1), sabemos que neste caso os bits 4, 5 e 6 serão zerados enquanto que os outros permanecem inalterados. Como os bits zerados correspondem à cor de fundo, esta operação tornou a cor de fundo preta.
Se quisermos definir a cor de fundo, precisamos de duas operações. A primeira, uma operação de máscara AND como descrito acima, para fazer a cor de fundo preta zerando os bits desejados sem modificar os restantes. A segunda, uma operação de máscara OR, para ativar os bits desejados sem alterar os restantes (cor de fundo azul):
and byte_de_video, 10001111b or byte_de_video, 00010000b
As constantes binárias utilizadas para fazer o AND e o OR são chamadas de máscaras. Estas constantes podem estar no formato binário ou hexadecimal. Por exemplo, and byte_de_video, 10001111b é o mesmo que and byte_de_video, 8Fh e or byte_de_video, 00010000b é o mesmo que or byte_de_vídeo, 10h.
Reveja as instruções AND e OR caso ainda tenha alguma dúvida.
Instrução XOR
| XOR | |
|---|---|
| Sintaxe | XOR destino, fonte |
| Lógica | destino <- destino XOR fonte |
| Descrição | XOR realiza uma operação lógica OR EXCLUSIVE bit a bit nos seus operandos e põe o resultado no destino. |
| Flags | CF OF PF SF ZF (AF indefinido) |
XOR retorna 1 quando os operandos forem diferentes, senão retorna 0, conforme a tabela abaixo:
| Operando 1 | Operando 2 | Resultado |
|---|---|---|
| 1 | 1 | 0 |
| 1 | 0 | 1 |
| 0 | 1 | 1 |
| 0 | 0 | 0 |
| Decimal | Binário | |
|---|---|---|
| 77 | 01001101 | |
| XOR | 25 | 00011001 |
| Resultado | 84 | 01010100 |
O OU-Exclusivo Lógico (XOR) significa que o resultado SÓ É VERDADEIRO SE AS CONDIÇÕES FOREM DIFERENTES. Falso e verdadeiro também podem indicar o estado de bits, portanto, podemos efetuar uma operação de OU-Exclusivo Lógico entre dois bits (como na tabela acima) ou numa sequência de bits. Tomemos como exemplo a operação 77 XOR 25. Como sabemos que a operação lógica XOR também é feita bit a bit, precisamos dos valores binários desses dois números para efetuar a operação:
Observe que apenas nas posições onde os bits são diferentes o resultado possui bits com valor 1, portanto, 77 XOR 25 = 84. Um aspecto interessante da operação XOR é que ela é reversível: se fizermos um XOR do resultado com o primeiro operando, obtemos o valor do segundo operando. Da mesma forma, se fizermos um XOR do resultado com o segundo operando, o resultado é o primeiro operando. Outra característica é que, fazendo o XOR de um número com ele mesmo, o resultado sempre será zero. Faça os testes e verifique 


