oicìliS ©|
A linguagem Assembly utilizada depende essencialmente do processador à qual se destina, ou seja, é dependente da arquitetura da CPU. A seguir estão as instruções da Intel (e família) mais utilizadas. Lembramos que, para que possam ser entendidas perfeitamente, é preciso ter uma boa noção da arquitetura do microprocessador. Em caso de dúvidas, refira-se a "ARQUITETURA INTEL 8086 / 80186 / 80286 / 80386 / 80486". |
| AND |
Há 5 modos diferentes de se ANDar dois números: 1. AND dois registradores 2. AND um registrador com uma variável 3. AND uma variável com um registrador 4. AND um registrador com uma constante 5. AND uma constante com um registrador Ou seja: variável1 db ? variável2 dw ? and cl, dh and al, variável1 and variável2, si and dl, 0C2h and variável1, 01001011b Observe que as constantes em notação hexadecimal e binária, as únicas aceitas porque 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:
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) será zerada. Se não houverem 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 abos 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. |
| CMP |
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: cmp eax, variável1 cmp variável2, TRUE |
| DEC |
|
Decrementa o valor de um registrador ou de uma variável em 1. dec eax dec variável1 |
| INC |
|
Incrementa o valor de um registrador ou de uma variável em 1. inc eax inc variável1 |
| JUMPS |
|
Apenas os principais tipos de salto (jump) estão na tabela abaixo:
|
| MOV |
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. |
| 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: 1 -> 0 0 -> 1
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: neg eax neg variável1 é 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. |
| OR |
OR retorna 0 quando ambos os operandos forem 0, senão retorna 1, conforme a tabela abaixo:
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 dl, 10000000b ; ativa o bit da posição 7 (as posições dos 8 bits
são de 0 a 7, em ordem inversa)
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: or ebx, ebx ; ebx é igual a zero ? jz ... |
| POP |
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. |
| PUSH |
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. |
| 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:
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). |
| 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: scasb scasw scas BYTE PTR ES:[DI] scas WORD PTR ES:[DI] |
| SHL |
O destino pode ser um registro ou um endereço de memória. As "vezes" podem ser valores ou CL.
|
| SHR |
O destino pode ser um registro ou um endereço de memória. As "vezes" podem ser valores ou CL.
|
| SUB |
Ambos os operandos podem ser bytes ou words e ambos também podem ser números binários com ou sem sinal. |
| TEST |
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. test ebx,ebx ; EBX é zero ? jz ... ; se sim, então salta 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 al,00100010b ; filtre os bits 1 e 5
jz UM_CINCO_OFF ; se o bit 1 ou o bit 5 estiverem setados, o resultado será
diferente de zero
...
AMBOS_NAO_OFF:
...
UM_CINCO_OFF:
...
TEST oferece as mesmas possibilidades que AND: variável1 db ? variável2 dw ? test cl, dh test al, variável1 test variável2, si test dl, 0C2h test variável1, 01001011b 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:
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. test dl, 10000000b ; está piscando ? test dl, 00010000b ; tem azul no fundo ? test dl, 00000100b ; a cor do caracter é vermelho ? 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.
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. |
| XOR |
XOR retorna 1 quando ambos os operandos forem diferentes, senão retorna 0, conforme a tabela abaixo:
O OU-Exclusivo Lógico (XOR), portanto, significa que o resultado SÓ É VERDADEIRO SE UMA DAS CONDIÇÕES FOR FALSA. 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 ;-) |