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: 52142
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