********************************************** ********** LIN1 - Trabalho Assembly ********** ********************************************** Data : 27/03/2002 Versão : 04/07/2007 Professor: Wagner Toscano Autor : Leandro Salvador ( leandrosalvador.com.br ) *********************************************************** * Índice 1 - Integrantes 2 - História da Linguagem 2.1 - Linguagem Original 2.1.1 - Sintaxe 2.1.3 - Comentários ???2.2.1 - Inventor(es) ???2.2.2 - Ano 2.2.3 - Objetivo 2.3 - Área de Utilização 3 - Descrição dos Elementos 3.1 - Declaração 3.2 - Atribuição 3.3 - Palavras Chaves 3.4 - Estruturas de Controle 3.4.1 - Seqüencial 3.4.2 - Transferências Condicionais 3.4.3 - Repetitivo 3.4.4 - Saída do Controle 3.4.5 - Transferências Incondicionais 3.5 - Tipos 3.5.1 - String 3.6 - Operadores 3.6.1 - Aritméticos 3.6.2 - Relacionais 3.6.3 - Lógicos 3.6.4 - Comparação 3.7 - Variável 3.8 - Constante 4 - Estrutura Mínima 5 - Exemplos 5.1 - Exemplos de Programas com DEBUG 5.2 - Exemplos de Programas com TASM 6 - Descrição de um Sistema Computacional 7 - Bibliografias *********************************************************** *********************************************************** 1 - Integrantes - Leandro Salvador - Sandro Valentine Faculdade: Tancredo Neves Curso : Ciências da Computação Professor: Wagner Toscano Data: 27/03/2002 *********************************************************** *********************************************************** 2 - História da Linguagem - Assembly é uma linguagem de baixo nível que pode ser usada para dar aos programas maior velocidade em tarefas ditas "baixas". - Isto basicamente consiste de indicações que representam instruções em linguagem de máquina, e como isto está muito próximo do código de máquina, isto é rápido. - Antes de surgirem os processadores 8086 programas não era uma tarefa fácil. - Quando os primeiros computadores foram desenvolvidos, a programação era feita em código de máquina, o que não era uma tarefa fácil, então a linguagem Assembly nasceu. *********************************************************** *********************************************************** 2.1 - Linguagem Original - A linguagem Assembly originou-se da linguagem de máquina, também conhecida como binária, com o objetivo de facilitar a tarefa de programar. *********************************************************** *********************************************************** 2.1.1 - Sintaxe * Instruções de Transferência - São usadas para mover o conteúdo dos operadores. - Cada instrução pode ser usada com diferentes modos de endereçamento. - Comandos MOV MOVS (MOVSB) (MOVSW) - MOV - Propósito: Transferência de dados entre células de Memória, registradores e o acumulador. - Sintaxe: MOV Destino,Fonte - Destino é o lugar para onde o dado será movido - Fonte é o lugar onde o dado está. - Os diferentes movimentos de dados permitidos para esta instrução são: *Destino: Memória. Fonte: acumulador *Destino: acumulador. Fonte: Memória *Destino: registrador de segmento. Fonte: Memória/registrador *Destino: Memória/regitrador. Fonte: registrador de segmento *Destino: registrador. Fonte: registrador *Destino: registrador. Fonte: Memória *Destino: Memória. Fonte: registrador *Destino: registrador. Fonte: dado imediato *Destino: Memória. Fonte: dado imediato - Exemplo: MOV AX,0006h MOV BX,AX MOV AX,4C00h INT 21h - Este pequeno programa move o valor 0006h para o registrador AX, então ele move o conteúdo de AX (0006h) para o registrador BX, e finalmente move o valor 4C00h para o registrador AX para terminar a execução com a opção 4C da interrupção 21h. - MOVS (MOVSB) (MOVSW) - Propósito: Mover byte ou cadeias de palavra da fonte, endereçada por SI, para o destino endereçado por DI. - Sintaxe: MOVS - Este comando não necessita de parâmetros uma vez que toma como endereço fonte o conteúdo do registrador SI e como destino o conteúdo de DI. A seguinte seqüência de instruções ilustra isso: - Exemplo: MOV SI, OFFSET VAR1 MOV DI, OFFSET VAR2 MOVS - Primeiro inicializamos os valores de SI e DI com os endereços das variáveis VAR1 e VAR2 respectivamente, então após a execução de MOVS o conteúdo de VAR1 é copiado para VAR2. - As instruções MOVSB e MOVSW são usadas do mesmo modo que MOVS, a primeira move um byte e a segunda move uma palavra. * Instruções de Carga - São instruções específicas para registradores, usadas para carregar bytes ou cadeias de bytes num registrador. - Comandos LODS (LODSB) (LODSW) LAHF LDS LEA LES - LODS (LODSB) (LODSW) - Propósito: Carregar cadeias de um byte ou uma palavra para o acumulador. - Sintaxe: LODS - Esta instrução toma a cadeia encontrada no endereço especificado por SI, a carrega para o registrador AL (ou AX) e adiciona ou subtrai, dependendo do estado de DF, para SI se é uma transferência de bytes ou de palavras. - Exemplo: MOV SI, OFFSET VAR1 LODS - Na primeira linha vemos a carga do endereço de VAR1 em SI e na segunda é tomado o conteúdo daquele local para o registrador AL. - Os comandos LODSB e LODSW são usados do mesmo modo, o primeiro carrega um byte e o segundo uma palavra (usa todo o registrador AX). - LAHF - Propósito: Transferir o conteúdo dos flags para o registrador AH. - Sintaxe: LAHF - Esta instrução é útil para verificar o estado dos flags durante a execução do nosso programa. - Os flags são deixados na seguinte ordem dentro do registrador: SF ZF ?? AF ?? PF ?? CF - O "??" significa que haverá um valor indefinido naqueles bits. - LDS - Propósito: Carregar o registrador de segmento de dados. - Sintaxe: LDS destino,fonte - O operador fonte deve ser uma double word na Memória. A palavra associada com o maior endereço é transferida para DS, em outras palavras isto é tomado como o endereço de segmento. A palavra associada com o menor endereço é o endereço de deslocamento e é depositada no registrador indicado como destino. - LEA - Propósito: Carregar o endereço do operador fonte. - Sintaxe: LEA destino,fonte - O operador fonte deve estar localizado na Memória, e seu deslocamento‚ colocado no registrador de índice ou ponteiro especificado no destino. - Para ilustrar uma das facilidades que temos com este comando, vejamos: MOV SI,OFFSET VAR1 - É equivalente a: LEA SI,VAR1 - É muito provável que para o programador é muito mais fácil criar programas grandes usando este último formato. - LES - Propósito: Carregar o registrador de segmento extra - Sintaxe: LES destino,fonte - O operador fonte deve ser uma palavra dupla na Memória. O conteúdo da palavra com endereço maior é interpretado como o endereço do segmento e é colocado em ES. A palavra com endereço menor é o endereço do deslocamento e é colocada no registrador especificado no parâmetro de destino. * Instruções de Manipulação da Pilha - Estas instruções permitem usar a pilha para armazenar ou recuperar dados. - Comandos POP POPF PUSH PUSHF - POP - Propósito: Recuperar uma parte de informação da pilha. - Sintaxe: POP destino - Esta instrução transfere o último valor armazenado na pilha para o operador de destino, e incrementa de 2 o registrador SP. - Este incremento é duplo pelo fato de que a pilha do mais alto endereço de Memória para o mais baixo, e a pilha trabalha apenas com palavras, 2 bytes,logo deve ser 2 o incremento de SP, na realidade 2 está sendo subtraído do tamanho real da pilha. - POPF - Propósito: Extrair os flags armazenados na pilha. - Sintaxe: POPF - Este comando transfere os bits da palavra armazenada na parte mais alta da pilha para registrador de flag. - O modo da transferência é como se segue: BIT FLAG 0 CF 2 PF 4 AF 6 ZF 7 SF 8 TF 9 IF 10 DF 11 OF - Os locais dos bits são os mesmos para o uso da instrução PUSHF. - Uma vez feita a transferência o registrador SP é incrementado de 2, conforme vimos anteriormente. - PUSH - Propósito: Coloca uma palavra na pilha. - Sintaxe: PUSH fonte - A instrução PUSH decrementa de dois o valor de SP e então transfere o conteúdo do operador fonte para o novo endereço resultante no registrador recém modificado. - O decremento no endereço é duplo pelo fato de que quando os valores são adicionados à pilha, que cresce do maior para o menor endereço, logo quando subraímos de 2 o registrador SP o que fazemos é incrementar o tamanho da pilha em dois bytes, que é a única quantidade de informação que a pilha pode manusear em cada entrada e Saída. - PUSHF - Propósito: Colocar os valores dos flags na pilha. - Sintaxe: PUSHF - Este comando decrementa de 2 o valor do registrador SP e então o conteúdo do registrador de flag é transferido para a pilha, no endereço indicado por SP. - Os flags são armazenados na Memória da mesma forma que o comando POPF. *********************************************************** *********************************************************** 2.1.3 - Comentários - usa-se ; (ponto-e-vírgula) para fazer comentários em programas assembly - exemplo ; comentário *********************************************************** *********************************************************** 2.2.1 - Inventor(es) Taí uma informação difícil, se não impossível, de se descobrir. Se alguém souber por gentileza nos envie essa informação para que possamos adicioná-la nesse campo. *********************************************************** *********************************************************** 2.2.2 - Ano Taí outra informação tão difícil de se descobrir quanto a anterior. *********************************************************** *********************************************************** 2.2.3 - Objetivo - Conhecer melhor o funcionamento do PC, o que permite o desenvolvimento de programas de forma mais consistente. *********************************************************** *********************************************************** 2.3 - Área de Utilização - Controle total sobre o PC ao fazer uso do assembler. - Programas assembly são mais rápidos, menores e mais poderosos do que os criados com outras linguagens. - A linguagem assembly é muito utilizada na criação de rotinas que exigem muita rapidez, como Sistemas Operacionais e Sistemas de Missão Crítica. *********************************************************** *********************************************************** 3 - Descrição dos Elementos - Os elementos em Assembly são descritos, basicamente, da seguinte forma - Declaração - Atribuição - Palavras Chaves - Estruturas de Controle - Tipos - Operadores - Variável - Constante *********************************************************** *********************************************************** 3.1 - Declaração - Declaração em Assembly é muito específica. - Exemplo Soma Proc Near ; Declaração do Procedimento Mov BX, 0 ; Conteúdo do Procedimento... Mov BL, AH Mov AH, 00 Add BX, AX Ret ; Diretiva de retorno Soma EndP ; Fim do Procedimento - Funcionamento - Na declaração, a primeira palavra, Soma, corresponde ao nome do procedimento. - Proc declara-o e a palavra Near indica que o procedimento é do tipo intrasegment, ou seja, no mesmo segmento. - A diretiva Ret carrega IP com o endereço armazenado na pilha para retornar ao programa que chamou. - Finalmente, Soma EndP indica o fim do procedimento. - Para declarar um procedimento inter segment, basta substituir a palavra Near para FAR. - A chamada deste procedimento é feito de modo idêntico: Call Soma - Macros oferecem uma grande flexibilidade na programação, comparadas aos procedimentos. *********************************************************** *********************************************************** 3.2 - Atribuição - Atribuição em Assembly é feita através do comando MOV. - Exemplo em que um valor localizado em "Fonte" é atribuído a "Destino" MOV Destino,Fonte MOV AX,0006h MOV BX,AX MOV AX,4C00h *********************************************************** *********************************************************** 3.3 - Palavras Chaves - Exemplos MOV MOVS (MOVSB) (MOVSW) LODS (LODSB) (LODSW) LAHF LDS LEA LES POP POPF PUSH PUSHF LOOP LOOPE LOOPNE DEC INC JMP JA (JNBE) JAE (JNBE) JB (JNAE) JBE (JNA) JE (JZ) JNE (JNZ) JG (JNLE) JGE (JNL) JL (JNGE) JLE (JNG) JC JNC JNO JNP (JPO) JNS JO JP (JPE) JS ADC ADD DIV IDIV MUL IMUL SBB SUB AND NEG NOT OR TEST XOR CMP CMPS (CMPSB) (CMPSW) CLC CLD CLI CMC STC STD STI *********************************************************** *********************************************************** 3.4 - Estruturas de Controle - Existem diferentes tipos de estruturas de controle em Assembly - Seqüencial - Transferências Condicionais (if) - Repetitivo (loop) - Saída do Controle (exit) - Transferências Incondicionais (goto) *********************************************************** *********************************************************** 3.4.1 - Seqüencial - A estrutura seqüencial em Assembly é dada pelo método "top-down", ou seja, o programa é escrito do começo ao fim sem qualquer desvio, loop ou transferência - Exemplo a 100[enter] mov ax,0002[enter] mov bx,0004[enter] add ax,bx[enter] nop[enter][enter] *********************************************************** *********************************************************** 3.4.2 - Transferências Condicionais - Comandos JA (JNBE) JAE (JNBE) JB (JNAE) JBE (JNA) JE (JZ) JNE (JNZ) JG (JNLE) JGE (JNL) JL (JNGE) JLE (JNG) JC JNC JNO JNP (JPO) JNS JO JP (JPE) JS - JA (JNBE) - Propósito: Salto condicional. - Sintaxe: JA símbolo - Após uma comparação este comando salta se não é igual. - Isto quer dizer que o salto só é feito se o flag CF ou o flag ZF estão desativados, ou seja, se um dos dois for zero. - JAE (JNB) - Propósito: Salto condicional. - Sintaxe: JAE símbolo - A instrução salta se está up, se está equal ou se está not down. - O salto é feito se CF está desativado. - JB (JNAE) - Propósito: Salto condicional. - Sintaxe: JB símbolo - A instrução salta se está down, se está not up ou se está equal. - O salto é feito se CF está ativado. - JBE (JNA) - Propósito: Salto condicional. - Sintaxe: JBE símbolo - A instrução salta se está down, se está equal ou se está not up. - O salto é feito se CF ou ZF estão ativados, ou seja, se um deles for 1. - JE (JZ) - Propósito: Salto condicional. - Sintaxe: JE símbolo - A instrução salta se está equal ou se está zero. - O salto é feito se ZF está ativado. - JNE (JNZ) - Propósito: Salto condicional. - Sintaxe: JNE símbolo - A instrução salta se está not equal ou se está zero. - O salto é feito se ZF está desativado. - JG (JNLE) - Propósito: Salto condicional, e o sinal é tomado. - Sintaxe: JG símbolo - A instrução salta se está larger, se está not larger ou se está equal. - O salto ocorre se ZF = 0 ou se OF = SF. - JGE (JNL) - Propósito: Salto condicional, e o sinal é tomado. - Sintaxe: JGE símbolo - A instrução salta se está larger, se está less than ou se está equal. - O salto é feito se SF = OF. - JL (JNGE) - Propósito: Salto condicional, e o sinal é tomado. - Sintaxe: JL símbolo - A instrução salta se está less than, se está not larger than ou se está equal. - O salto é feito se SF é diferente de OF. - JLE (JNG) - Propósito: Salto condicional, e o sinal é tomado. - Sintaxe: JLE símbolo - A instrução salta se está less than, se está equal ou se está not larger. - O salto é feito se ZF = 1 ou se SF é diferente de OF. - JC - Propósito: Salto condicional, e os flags são tomados. - Sintaxe: JC símbolo - A instrução salta se há carry. - O salto é feito se CF = 1. - JNC - Propósito: Salto condicional, e o estado dos flags é tomado. - Sintaxe: JNC símbolo - A instrução salta se não há carry. - O salto é feito se CF = 0. - JNO - Propósito: Salto condicional, e o estado dos flags é tomado. - Sintaxe: JNO símbolo - A instrução salta se não há overflow - O salto é feito se OF = 0. - JNP (JPO) - Propósito: Salto condicional, e o estado dos flags é tomado. - Sintaxe: JNP símbolo - A instrução salta se não há paridade ou se a paridade é ímpar. - O salto é feito se PF = 0. - JNS - Propósito: Salto condicional, e o estado dos flags é tomado. - Sintaxe: JNP símbolo - A instrução salta se o sinal está desativado. - O salto é feito se SF = 0. - JO - Propósito: Salto condicional, e o estado dos flags é tomado. - Sintaxe: JO símbolo - A instrução salta se há overflow. - O salto é feito se OF = 1. - JP (JPE) - Propósito: Salto condicional, e o estado dos flags é tomado. - Sintaxe: JP símbolo - A instrução salta se há paridade ou se a paridade é par. - O salto é feito se PF = 1. - JS - Propósito: Salto condicional, e o estado dos flags é tomado. - Sintaxe: JS símbolo - A instrução salta se o sinal está ativado. - O salto é feito se SF =1. - A linguagem Assembly suporta while-loops (enquanto) a until-loops - Comandos .WHILE, .ENDW --> while-loop .REPEAT, .UNTIL --> until-loop *********************************************************** *********************************************************** 3.4.3 - Repetitivo * Instruções para Laços - Estas instruções transferem a execução do processo, condicional ou incondicionalmente, para um destino, repetindo a ação até o contador ser zero. - Comandos LOOP LOOPE LOOPNE - LOOP - Propósito: Gerar um laço no programa. - Sintaxe: LOOP símbolo - A instrução LOOP decrementa CX de 1 e transfere a execução do programa para o símbolo que é dado como operador, caso CX ainda não seja 1. - LOOPE - Propósito: Gerar um laço no programa, considerando o estado de ZF. - Sintaxe: LOOPE símbolo - Esta instrução decrementa CX de 1. Se CX é diferente de zero e ZF é igual a 1, então a execução do programa é transferida para o símbolo indicado como operador. - LOOPNE - Propósito: Gerar um laço no programa, considerando o estado de ZF. - Sintaxe: LOOPNE símbolo - Esta instrução decrementa CX de 1 e transfere a execução do programa apenas se ZF é diferente de 0. * Instruções Contadoras - Estas instruções são usadas para decrementar ou incrementar o conteúdo de contadores. - Comandos DEC INC - DEC - Propósito: Decrementar o operador. - Sintaxe: DEC destino - Esta instrução subtrai 1 do operador destino e armazena o novo valor no mesmo operador. - INC - Propósito: Incrementar o operador. - Sintaxe: INC destino - Esta instrução adiciona 1 ao operador destino e mantém o resultado no mesmo operador. *********************************************************** *********************************************************** 3.4.4 - Saída do Controle - Diretivas que podem ser usadas para interromper repetições - Padrão .BREAK .CONTINUE - Diretivas mais legíveis - Padrão '.BREAK .IF ' '.CONTINUE .IF ' - Exemplo .WHILE 1 mov ah, 07h ; Lê a tecla pressionada int 21h .BREAK .IF al == 1Bh ; Termina se a tecla ESC for pressionada .CONTINUE .IF (al < 30h) || (al > 39h) ; Não imprime se o caracter não é um dígito mov dl, al mov ah, 02h ; Imprime caracter int 21h .ENDW - Outras diretivas - Padrão .ENDIF .ENDW .EXIT 0 END ENDS *********************************************************** *********************************************************** 3.4.5 - Transferências Incondicionais - Saltos incondicionais na escrita de programas em linguagem assembly são dados pela instrução jmp - Em outras linguagens de programação comumente saltos incondicionais são dados pela instrução goto - Um salto é usado para modificar a sequência da execução das instruções de um programa, enviando o controle ao endereço indicado, ou seja, o registrador contador de programa recebe este novo endereço. - Usadas para transferir o processo de execução do programa para o operador indicado. - Comandos JMP - JMP - Propósito: Salto incondicional. - Sintaxe: JMP destino - Esta instrução é usada para desviar o curso do programa sem tomar em conta as condições atuais dos flags ou dos dados. *********************************************************** *********************************************************** 3.5 - Tipos - BYTE - Abreviação --> db - Tamanho --> 8 bits - Descrição --> inteiro, caracter, string - WORD - Abreviação --> dw - Tamanho --> 16 bits - Descrição --> inteiro, ponteiro curto de 16 bits - DWORD - Abreviação --> dd - Tamanho --> 32 bits - Descrição --> inteiro, pointeiro longo de 32 bits - FWORD - Abreviação --> df - Tamanho --> 48 bits - Descrição --> ponteiro longo de 48 bits - QWORD - Abreviação --> dq - Tamanho --> 64 bits - Descrição --> número inteiro - TBYTE - Abreviação --> dt - Tamanho --> 10 bytes - Descrição --> número decimal em código BCD - REAL4 - Abreviação --> dd - Tamanho --> 4 bytes - Descrição --> número real de precisão simples - REAL8 - Abreviação --> dq - Tamanho --> 8 bytes - Descrição --> número real com precisão dupla - REAL10 - Abreviação --> dt - Tamanho --> 10 bytes - Descrição --> número real longo de 80 bits *********************************************************** *********************************************************** 3.5.1 - String - Em Assembly pode-se escrever uma String de caracteres através de '' (aspas simples). - Exemplo MOV AH,01 ;Função 1 (lê caractere do teclado) INT 21 ;Chama interrupção do DOS CMP AL,0D ;Compara se o caractere lido é um ENTER JNZ 0100 ;Se não é, lê um outro caractere MOV AH,02 ;Função 2 (escreve um caractere na tela) *********************************************************** *********************************************************** 3.6 - Operadores - Existem diferentes tipos de operadores, cada um deles específico para uma função - Tipos - Aritméticos - Relacionais - Lógicos - Relacionais *********************************************************** *********************************************************** 3.6.1 - Aritméticos - São usadas para realizar operações aritméticas nos operadores. - Comandos ADC ADD DIV IDIV MUL IMUL SBB SUB - ADC - Propósito: Efetuar a soma entre dois operandos com carry. - Sintaxe: ADC destino,fonte - Esta instrução efetua a soma entre dois operandos, mais o valor do flag CF, existente antes da operação. Apenas o operando destino e os flags são afetados. - O resultado é armazenado no operador de destino. - ADD - Propósito: Adição de dois operadores. - Sintaxe: ADD destino,fonte - Esta instrução adiciona dois operadores e armazena o resultado no operador destino. - DIV - Propósito: Divisão sem sinal. - Sintaxe: DIV fonte - O divisor pode ser um byte ou uma palavra e é o operador que é dado na instrução. - Se o divisor é de 8 bits, o registrador AX de 16 bits é tomado como dividendo e se o divisor é de 16 bits, o par de registradores DX:AX será tomado como dividendo, tomando a palavra alta de DX e a baixa de AX. - Se o divisor for um byte, então o quociente ser armazenado no registrador AL e o resto em AH. Se for uma palavra, então o quociente é armazenado em AX e o resto em DX. - IDIV - Propósito: Divisão com sinal. - Sintaxe: IDIV fonte - Consiste basicamente como a instrução DIV, diferencia-se apenas por realizar a operação com sinal. - Para os resultados são usados os mesmos registradores da instrução DIV. - MUL - Propósito: Multiplicação com sinal. - Sintaxe: MUL fonte - Esta instrução realiza uma multiplicação não sinalizada entre o conteúdo do acumulador AL ou AX pelo operando-fonte, devolvendo o resultado no acumulador AX caso a operação tenha envolvido AL com um operando de 8 bits, ou em DX e AX caso a operação tenha envolvido AX e um operando de 16 bits. - IMUL - Propósito: Multiplicção de dois números inteiros com sinal. - Sintaxe: IMUL fonte - Esta instrução faz o mesmo que a anterior, difere apenas pela inclusão do sinal. - Os resultados são mantidos nos mesmos registradores usados pela instrução MUL. - SBB - Propósito: Subtração com carry. - Sintaxe: SBB destino,fonte - Esta instrução subtrai os operadores e subtrai um do resultado se CF está ativado. - O operador fonte é sempre subtraído do destino. - Este tipo de subtração é usado quando se trabalha com quantidades de 32 bits. - SUB - Propósito: Subtração. - Sintaxe: SUB destino,fonte - Esta instrução subtrai o operador fonte do destino. *********************************************************** *********************************************************** 3.6.2 - Relacionais - Operadores == --> igual != --> não igual (diferente) > --> maior que < --> menor que >= --> maior ou igual que <= --> menor ou igual que & --> teste de bit ! --> NOT lógico && --> AND lógico || --> OR lógico *********************************************************** *********************************************************** 3.6.3 - Lógicos - São usadas para realizar operações lógicas nos operadores. - Comandos AND NEG NOT OR TEST XOR - AND - Propósito: Realiza a conjunção de operadores bit a bit. - Sintaxe: AND destino,fonte - Com esta instrução a operação lógica "y" para ambos os operadores é usada como na tabela: Fonte Destino | Destino ----------------------------- 1 1 | 1 1 0 | 0 0 1 | 0 0 0 | 0 - O resultado desta operação é armazenado no operador de destino. - NEG - Propósito: Gera o complemento de 2. - Sintaxe: NEG destino - Esta instrução gera o complemento de 2 do operador destino e o armazena no mesmo operador. Por exemplo, if AX armazena o valor 1234H, então: NEG AX - Isto fará com o que o valor EDCCH fique armazenado no registrador AX. - NOT - Propósito: Faz a negação do operador de destino bit a bit. - Sintaxe: NOT destino - O resultado é armazenado no mesmo operador de destino. - OR - Propósito: Realiza um OU lógico. - Sintaxe: OR destino,fonte - A instrução OR, faz uma disjunção lógica bit a bit dos dois operadores: Fonte Destino | Destino ----------------------------------- 1 1 | 1 1 0 | 1 0 1 | 1 0 0 | 0 - TEST - Propósito: Compara logicamente os operadores. - Sintaxe: TEST destino,fonte - Realiza uma conjunção, bit a bit, dos operadores, mas difere da instrução AND, uma vez que não coloca o resultado no operador de destino. - Tem efeito sobre o registrador de flag. - XOR - Propósito: Realiza um OU exclusivo. - Sintaxe: XOR destino,fonte - Esta instrução realizxa uma disjunção exclusiva de dois operadores bit a bit. Fonte Destino | Destino ----------------------------------- 1 1 | 0 0 0 | 1 0 1 | 1 0 0 | 0 *********************************************************** *********************************************************** 3.6.4 - Comparação - Quase todas as instruções de comparação são baseadas na informação contida no registrador de flag. - Normalmente os flags do registrador que podem ser manuseados diretamente pelo programador são os da direção de dados DF, usado para definir as operações sobre cadeias. - Um outro que pode também ser manuseado é o flag IF através das instruções sti e cli, para ativar e desativar as interrupções. - Estas instruções são usadas para comparar os operadores, e elas afetam o conteúdo dos flags. - Comandos CMP CMPS (CMPSB) (CMPSW) - CMP - Propósito: Comparar os operadores. - Sintaxe: CMP destino,fonte - Esta instrução subtrai o operador fonte do destino, mas não armazena o resultado da operação, apenas afeta o estado dos flags. - CMPS (CMPSB) (CMPSW) - Propósito: Comparar cadeias de um byte ou uma palavra. - Sintaxe: CMP destino,fonte - Esta instrução compara efetuando uma subtração entre o byte ou palavra endereçado por DI, dentro do segmento extra de dados, e o byte ou palavra endereçado por SI dentro do segmento de dados, afetando o registrador de flags, mas sem devolver o resultado da subtração. - A instrução automaticamente incrementa ou decrementa os registradores de índice SI e DI, dependendo do valor do flag DF, de modo a indicar os próximos dois elementos a serem comparados. - O valor de incremento ou decremento é uma de uma ou duas unidades, dependendo da natureza da operação. - Diante desta instrução, pode-se usar um prefixo para repetição, de modo a comparar dois blocos de Memória entre si, repetindo a instrução de comparação at‚ que ambos se tornem iguais ou desiguais. *********************************************************** *********************************************************** 3.7 - Variável - Instruções de flag. - Estas instruções afetam diretamente o conteúdo dos flags. - Comandos CLC CLD CLI CMC STC STD STI - CLC - Propósito: Limpar o flag de carry. - Sintaxe: CLC - Esta instrução desliga o bit correspondente ao flag de carry. - Em outras palavras, ela o ajusta para zero. - CLD - Propósito: Limpar o flag de endereço. - Sintaxe: CLD - Esta instrução desliga o bit correspondente ao flag de endereço. - CLI - Propósito: Limpar o flag de interrupção. - Sintaxe: CLI - Esta instrução desliga o flag de interrupções, desabilitando, deste modo, interrupções mascaráveis. - Uma interrupção mascarável é aquela cujas funções são desativadas quando IF=0. - CMC - Propósito: Complementar o flag de carry. - Sintaxe: CMC - Esta instrução complementa o estado do flag CF. - Se CF = 0 a instrução o iguala a 1. - Se CF = 1, a instrução o iguala a 0. - Poderíamos dizer que ela apenas inverte o valor do flag. - STC - Propósito: Ativar o flag de carry. - Sintaxe: STC - Esta instrução ajusta para 1 o flag CF. - STD - Propósito: Ativar o flag de endereço. - Sintaxe: STD - Esta instrução ajusta para 1 o flag DF. - STI - Propósito: Ativar o flag de insterrupção. - Sintaxe: STI - Esta instrução ativa o flag IF, e habilita interrupções externas mascar veis (que só funcionam quando IF = 1). *********************************************************** *********************************************************** 3.8 - Constante - Binário - Especificador --> Y(y) ou B(b) - Exemplo --> 101b = 5 - Octal - Especificador --> Q(q) ou O(o) - Exemplo --> 33Q = 27 - Hexadecimal - Especificador --> H(h) - Exemplo --> 12h = 18 *********************************************************** *********************************************************** 4 - Estrutura Mínima - Nas linhas do código em Linguagem Assembly há duas partes: - a primeira é o nome da instrução a ser executada; - a segunda, os parâmetros do comando. - Por exemplo: add ah bh - "add" é o comando a ser executado, neste caso uma adição; - "ah" bem como "bh" são os parâmetros. - Por exemplo: mov al, 25 - No exemplo acima, estamos usando a instrução mov, que significa mover o valor 25 para o registrador al. - O nome das instruções nesta linguagem é constituído de 2, 3 ou 4 letras. - Estas instruções são chamadas mnemônicos ou códigos de operação, representando a função que o processador executará. - Às vezes instruções aparecem assim: add al,[170] - Os colchetes no segundo parâmetro indica-nos que vamos trabalhar com o conteúdo da célula de Memória de número 170, ou seja, com o valor contido no endereço 170 da Memória e não com o valor 170, isto é conhecido como "endereçamento direto". *********************************************************** *********************************************************** 5 - Exemplos * DEBUG X ASM - Para a criação de um programa em assembler existem 2 opções: DEBUG e TASM * Usando o DEBUG, que podemos encontrar em qualquer PC com o MS-DOS. - Debug pode apenas criar arquivos com a extensão .COM, e por causa das características deste tipo de programa, eles não podem exceder os 64 Kb, e também devem iniciar no endereço de Memória 0100H dentro do segmento específico. - É importante observar isso, pois deste modo os programas .COM não são relocáveis. - Os principais comandos do programa debug são: A Montar instruções simbólicas em código de m quina D Mostrar o conteúdo de uma rea da Memória E Entrar dados na Memória, iniciando num endereço específico G Rodar um programa executável na Memória N Dar nome a um programa P Proceder, ou executar um conjunto de instruções relacionadas Q Sair do programa debug R Mostrar o conteúdo de um ou mais registradores T Executar passo a passo as instruções U Desmontar o código de m quina em instruções simbólicas W Gravar um programa em disco - Para montar um programa no Debug, é usado o comando "a" (assemble); - Quando usamos este comando, podemos especificar um endereço inicial para o nosso programa como o parâmetro, mas é opcional. - No caso de omissão, o endereço inicial é o especificado pelos registradores CS:IP, geralmente 0100h, o local em que programas com extensão .COM devem iniciar. - E será este o local que usaremos, uma vez que o Debug só pode criar este tipo de programa. - Embora neste momento não seja necessário darmos um parâmetro ao comando "a", isso é recomendável para evitar problemas. * Usando o TASM - Turbo Assembler da Borland - Para que possamos criar um programa, precisamos de algumas ferramentas: - Primeiro de um editor para criar o programa fonte. - Segundo de um montador, um programa que irá transformar nosso fonte num programa objeto. - E, terceiro, de um linker (ligador) que irá gerar o programa executável a partir do programa objeto. - O editor pode ser qualquer um que dispusermos. - O montador será o TASM macro assembler da Borland - O linker será o TLINK, também da Borland. - Nós devemos criar os programas fonte com a extensão .ASM para que o TASM reconheça e o transforme no programa objeto, um "formato intermediário" do programa, assim chamado porque ainda não é um programa executável e tão pouco um programa fonte. - O linker gera a partir de um programa .OBJ, ou da combinação de vários deles, um programa executável, cuja extensão é normalmente .EXE, embora possa ser .COM dependendo da forma como for montado e ligado. - Para construirmos os programas com o TASM, devemos estruturar o fonte de forma diferenciada ao que fazíamos com o programa debug. - É importante incluir as seguintes diretivas assembly: .MODEL SMALL Define o melo de Memória a usar em nosso programa .CODE Define as instruções do programa, relacionado ao segmento de código .STACK Reserva espa‡o de Memória para as instruções de programa na pilha END Finaliza um programa assembly *********************************************************** *********************************************************** 5.1 - Exemplos de Programas com DEBUG * Procedimento - Nesta seção forneceremos alguns programas feitos no debug do DOS. - Você pode executar cada programa assembly usando o comando "g" (go), para ver o que cada programa faz. - Passo 1 - Carregar o programa exemplo C:\>debug -n one.com -l -u 100 109 0D80:0100 B80600 MOV AX,0006 0D80:0103 BB0400 MOV BX,0004 0D80:0106 01D8 ADD AX,BX 0D80:0108 CD20 INT 20 - Nota: -n one.com - Dar nome ao programa a ser carregado -l - Carregá-lo -u 100 109 - Desmontar o código do endereço inicial ao final especificado - Passo 2 - Rodar o programa executável na Memória - Digite o comando g -g - Program terminated normally * Exemplo 1 a 100[enter] mov ax,0002[enter] mov bx,0004[enter] add ax,bx[enter] nop[enter][enter] - O que o programa faz? - Move o valor 0002 para o registrador ax - Move o valor 0004 para o registrador bx - Adiciona o conteúdo dos registradores ax e bx, guardando o resultado em ax - E finalmente a instrução nop (nenhuma operação) finaliza o programa. - No programa debug, a tela se parecerá com: C:\>debug -a 100 0D62:0100 mov ax,0002 0D62:0103 mov bx,0004 0D62:0106 add ax,bx 0D62:0108 nop 0D62:0109 - Entramos com o comando "t" para executar passo a passo as instruções: -t AX=0002 BX=0000 CX=0000 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000 DS=0D62 ES=0D62 SS=0D62 CS=0D62 IP=0103 NV UP EI PL NZ NA PO NC 0D62:0103 BB0400 MOV BX,0004 - Vemos o valor 0002 no registrador AX. - Teclamos "t" para executar a segunda instrução: -t AX=0002 BX=0004 CX=0000 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000 DS=0D62 ES=0D62 SS=0D62 CS=0D62 IP=0106 NV UP EI PL NZ NA PO NC 0D62:0106 01D8 ADD AX,BX - Teclando "t" novamente para ver o resultado da instrução add: -t AX=0006 BX=0004 CX=0000 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000 DS=0D62 ES=0D62 SS=0D62 CS=0D62 IP=0108 NV UP EI PL NZ NA PE NC 0D62:0108 90 NOP - A possibilidade dos registradores conterem valores diferentes existe, mas AX e BX devem conter os mesmos valores acima descritos. - Para sair do Debug usamos o comando "q" (quit). - Armazenando e carregando os programas. - Não seria prático ter que digitar o programa cada vez que iniciássemos o Debug. - Ao invés disso, podemos armazená-lo no disco. - Só que o mais interessante nisso é que um simples comando de salvar cria um arquivo com a extensão .COM, ou seja, executável - sem precisarmos efetuar os processos de montagem e ligação, como veremos posteriormente com o TASM. - Eis os passos para salvar um programa que já esteja na Memória: - Obter o tamanho do programa subtraindo o endereço final do endereço inicial, naturalmente que no sistema hexadecimal. - Dar um nome ao programa. - Colocar o tamanho do programa no registrador CX. - Mandar o debug gravar o programa em disco. * Exemplo 2 - Usando como exemplo o seguinte programa, vamos clarear a idéia de como realizar os passos acima descritos: 0C1B:0100 mov ax,0002 0C1B:0103 mov bx,0004 0C1B:0106 add ax,bx 0C1B:0108 int 20 0C1B:010A - Para obter o tamanho de um programa, o comando "h" é usado, já que ele nos mostra a adição e subtração de dois números em hexadecimal. - Para obter o tamanho do programa em questão, damos como parâmetro o valor do endereço final do nosso programa (10A), e o endereço inicial (100). - O primeiro resultado mostra-nos a soma dos endereços, o segundo, a subtração. -h 10a 100 020a 000a - O comando "n" permite-nos nomear o programa. -n test.com - O comando "rcx" permite-nos mudar o conteúdo do registrador CX para o valor obtido como tamanho do arquivo com o comando "h", neste caso 000a. -rcx CX 0000 :000a - Finalmente, o comando "w" grava nosso programa no disco, indicando quantos bytes gravou. -w Writing 000A bytes - Para já salvar um arquivo quando carregá-lo, 2 passos são necessários: - Dar o nome do arquivo a ser carregado. - Carregá-lo usando o comando "l" (load). - Para obter o resultado correto destes passos, é necessário que o programa acima já esteja criado. - Dentro do Debug, escrevemos o seguinte: -n test.com -l -u 100 109 0C3D:0100 B80200 MOV AX,0002 0C3D:0103 BB0400 MOV BX,0004 0C3D:0106 01D8 ADD AX,BX 0C3D:0108 CD20 INT 20 - O último comando "u" é usado para verificar que o programa foi carregado na Memória. - O que ele faz é desmontar o código e mostrá-lo em assembly. - Os parâmetros indicam ao Debug os endereços inicial e final a serem desmontados. - O Debug sempre carrega os programas na Memória no endereço 100h, conforme já comentamos. * Exemplo 3 ;exemplo3 .model small .stack .code mov ah,2h ;move o valor 2h para o registrador ah mov dl,2ah ;move o valor 2ah para o registrador dl ;(‚ o valor ASCII do caractere *) int 21h ;interrupção 21h mov ah,4ch ;função 4ch, sai para o sistema operacional int 21h ;interrupção 21h end ;finaliza o programa * Exemplo 4 -a0100 297D:0100 MOV AX,0006 ;Põe o valor 0006 no registrador AX 297D:0103 MOV BX,0004 ;Põe o valor 0004 no registrador BX 297D:0106 ADD AX,BX ;Adiciona BX ao conteúdo de AX 297D:0108 INT 20 ;Finaliza o Programa - A única coisa que este programa faz é salvar dois valores em dois registradores e adicionar o valor de um ao outro. * Exemplo 5 - a100 0C1B:0100 jmp 125 ;Salta para o endereço 125h 0C1B:0102 [Enter] - e 102 'Hello, How are you ?' 0d 0a '$' - a125 0C1B:0125 MOV DX,0102 ;Copia a string para registrador DX 0C1B:0128 MOV CX,000F ;Quantas vezes a string ser mostrada 0C1B:012B MOV AH,09 ;Copia o valor 09 para registrador AH 0C1B:012D INT 21 ;Mostra a string 0C1B:012F DEC CX ;Subtrai 1 de CX 0C1B:0130 JCXZ 0134 ;Se CX é igual a 0 salta para o endereço 0134 0C1B:0132 JMP 012D ;Salta ao endereço 012D 0C1B:0134 INT 20 ;Finaliza o programa - Este programa mostra 15 vezes na tela a string de caracteres. * Exemplo 6 -a100 297D:0100 MOV AH,01 ;Função para mudar o cursor 297D:0102 MOV CX,0007 ;Formata o cursor 297D:0105 INT 10 ;Chama interrupção do BIOS 297D:0107 INT 20 ;Finaliza o programa - Este programa muda o formato do cursor. * Exemplo 7 -a100 297D:0100 MOV AH,01 ;Função 1 (lê caractere do teclado) 297D:0102 INT 21 ;Chama interrupção do DOS 297D:0104 CMP AL,0D ;Compara se o caractere lido é um ENTER 297D:0106 JNZ 0100 ;Se não é, lê um outro caractere 297D:0108 MOV AH,02 ;Função 2 (escreve um caractere na tela) 297D:010A MOV DL,AL ;Character to write on AL 297D:010C INT 21 ;Chama interrupção do DOS 297D:010E INT 20 ;Finaliza o programa - Este programa usa a interrupção 21h do DOS. - Usa duas funções da mesma: a primeira lê um caractere do teclado (função 1) e a segundo escreve um caractere na tela. - O programa lê caracteres do teclado até encontrar um ENTER. * Exemplo 8 -a100 297D:0100 MOV AH,02 ;Função 2 (escreve um caractere na tela) 297D:0102 MOV CX,0008 ;Põe o valor 0008 no registrador CX 297D:0105 MOV DL,00 ;Põe o valor 00 no registrador DL 297D:0107 RCL BL,1 ;Rotaciona o byte em BL um bit para a esquerda 297D:0109 ADC DL,30 ;Converte o registrador de flag para 1 297D:010C INT 21 ;Chama interrupção do DOS 297D:010E LOOP 0105 ;Salta se CX > 0 para o endereço 0105 297D:0110 INT 20 ;Finaliza o programa - Este programa mostra na tela um número binário através de um ciclo condicional (LOOP) usando a rotação do byte. * Exemplo 9 -a100 297D:0100 MOV AH,02 ;Função 2 (escreve um caractere na tela) 297D:0102 MOV DL,BL ;Põe o valor de BL em DL 297D:0104 ADD DL,30 ;Adiciona o valor 30 a DL 297D:0107 CMP DL,3A ;Compara o valor 3A com o conteúdo de DL sem afet -lo ;seu valor apenas modifica o estado do flag de carry 297D:010A JL 010F ;salta ao endereço 010f, se for menor 297D:010C ADD DL,07 ;Adiciona o valor 07 a DL 297D:010F INT 21 ;Chama interrupção do DOS 297D:0111 INT 20 ;Finaliza o programa - Este programa imprime um valor zero em dígitos hexadecimais. * Exemplo 10 -a100 297D:0100 MOV AH,02 ;Função 2 (escreve um caractere na tela) 297D:0102 MOV DL,BL ;Põe o valor de BL em DL 297D:0104 AND DL,0F ;Transporta fazendo AND dos números bit a bit 297D:0107 ADD DL,30 ;Adiciona 30 a Dl 297D:010A CMP DL,3A ;Compara Dl com 3A 297D:010D JL 0112 ;Salta ao endereço 0112, se menor 297D:010F ADD DL,07 ;Adiciona 07 a DL 297D:0112 INT 21 ;Chama interrupção do DOS 297D:0114 INT 20 ;Finaliza o programa - Este programa é usado para imprimir dois dígitos hexadecimais. * Exemplo 11 -a100 297D:0100 MOV AH,02 ;Função 2 (escreve um caractere na tela) 297D:0102 MOV DL,BL ;Põe o valor de BL em DL 297D:0104 MOV CL,04 ;Põe o valor 04 em CL 297D:0106 SHR DL,CL ;Desloca os 4 bits mais altos do número ao nibble mais à direita 297D:0108 ADD DL,30 ;Adiciona 30 a DL 297D:010B CMP DL,3A ;Compara Dl com 3A 297D:010E JL 0113 ;Salta ao endereço 0113, se menor 297D:0110 ADD DL,07 ;Adiciona 07 a DL 297D:0113 INT 21 ;Chama interrupção do DOS 297D:0115 INT 20 ;Finaliza o programa - Este programa imprime o primeiro de dois dígitos hexadecimais. * Exemplo 12 -a100 297D:0100 MOV AH,02 ;Função 2 (escreve um caractere na tela) 297D:0102 MOV DL,BL ;Põe o valor de BL em DL 297D:0104 MOV CL,04 ;Põe o valor 04 em CL 297D:0106 SHR DL,CL ;Desloca os 4 bits mais altos do número ao nibble mais à direita 297D:0108 ADD DL,30 ;Adiciona 30 a DL 297D:010B CMP DL,3A ;Compara Dl com 3A 297D:010E JL 0113 ;Salta ao endereço 0113, se menor 297D:0110 ADD DL,07 ;Adiciona 07 a DL 297D:0113 INT 21 ;Chama interrupção do DOS 297D:0115 MOV DL,BL ;Põe o valor de BL em DL 297D:0117 AND DL,0F ;Transporta fazendo AND dos números bit a bit 297D:011A ADD DL,30 ;Adiciona 30 a DL 297D:011D CMP DL,3A ;Compara Dl com 3A 297D:0120 JL 0125 ;Salta ao endereço 0125, se menor 297D:0122 ADD DL,07 ;Adiciona 07 a DL 297D:0125 INT 21 ;Chama interrupção do DOS 297D:0127 INT 20 ;Finaliza o programa - Este programa imprime o segundo de dois dígitos hexadecimais. * Exemplo 13 -a100 297D:0100 MOV AH,01 ;Função 1 (lˆ caractere do teclado) 297D:0102 INT 21 ;Chama interrupção do DOS 297D:0104 MOV DL,AL ;Põe o valor de AL em DL 297D:0106 SUB DL,30 ;Subtrai 30 de DL 297D:0109 CMP DL,09 ;Compara DL com 09 297D:010C JLE 0111 ;Salta ao endereço 0111, se menor ou igual 297D:010E SUB DL,07 ;Subtrai 07 de DL 297D:0111 MOV CL,04 ;Põe o valor 04 em CL 297D:0113 SHL DL,CL ;Insere zeros à direita 297D:0115 INT 21 ;Chama interrupção do DOS 297D:0117 SUB AL,30 ;Subtrai 30 de AL 297D:0119 CMP AL,09 ;Compara AL com 09 297D:011B JLE 011F ;Salta ao endereço 011f, se menor ou igual 297D:011D SUB AL,07 ;Subtrai 07 de AL 297D:011F ADD DL,AL ;Adiciona AL a DL 297D:0121 INT 20 ;Finaliza o programa - Este programa pode ler dois dígitos hexadecimais. * Exemplo 14 -a100 297D:0100 CALL 0200 ;Chama um procedimento 297D:0103 INT 20 ;Finaliza o programa -a200 297D:0200 PUSH DX ;Põe o valor de DX na pilha 297D:0201 MOV AH,08 ;Função 8 297D:0203 INT 21 ;Chama interrupção do DOS 297D:0205 CMP AL,30 ;Compara AL com 30 297D:0207 JB 0203 ;Salta se CF é ativado ao endereço 0203 297D:0209 CMP AL,46 ;Compara AL com 46 297D:020B JA 0203 ;Salta ao endereço 0203, se diferente 297D:020D CMP AL,39 ;Compara AL com 39 297D:020F JA 021B ;Salta ao endereço 021B, se diferente 297D:0211 MOV AH,02 ;Função 2 (escreve um caractere na tela) 297D:0213 MOV DL,AL ;Põe o valor de AL em DL 297D:0215 INT 21 ;Chama interrupção do DOS 297D:0217 SUB AL,30 ;Subtrai 30 de AL 297D:0219 POP DX ;Extrai o valor de DX da pilha 297D:021A RET ;Retorna o controle ao programa principal 297D:021B CMP AL,41 ;Compara AL com 41 297D:021D JB 0203 ;Salta se CF é ativado ao endereço 0203 297D:021F MOV AH,02 ;Função 2 (escreve um caractere na tela) 297D:022 MOV DL,AL ;Põe o valor AL em DL 297D:0223 INT 21 ;Chama interrupção do DOS 297D:0225 SUB AL,37 ;Subtrai 37 de AL 297D:0227 POP DX ;Extrai o valor de DX da pilha 297D:0228 RET ;Retorna o controle ao programa principal - Este programa se mantém lendo caracteres até receber um que possa ser convertido para um número hexadecimal. *********************************************************** 5.2 - Exemplos de Programas com TASM * Procedimento - Nesta seção forneceremos a você vários exemplos de programas a serem montados fazendo uso do TASM da Borland. - Passo 1 - Use qualquer editor para criar o programa fonte. - Entre com as seguintes linhas, contidas nos exemplos abaixo. - Passo 2 - Montar o programa C:\>tasm one.asm Turbo Assembler Version 2.0 Copyright (c) 1988, 1990 Borland International Assembling file: one.asm Error messages: None Warning messages: None Passes: 1 Remaining memory: 471k C:\> - Isto criar um programa objeto com o mesmo nome do fonte, neste caso: one.obj - Passo 3 - Criar o programa executável C:\>tlink one.obj Turbo Link Version 3.0 Copyright (c) 1987, 1990 Borland International C:\> - Isto cria o programa executável com o mesmo nome do objeto e com extensão diferente, one.exe - Passo 4 - Rodar o programa executável. - Basta digitar o nome do programa criado. * Exemplo 1 ; use ; para fazer comentários em programas assembly .MODEL SMALL ;modelo de Memória .STACK ;espaço de Memória para instruções do programa na pilha .CODE ;as linhas seguintes são instruções do programa mov ah,01h ;move o valor 01h para o registrador ah mov cx,07h ;move o valor 07h para o registrador cx int 10h ;interrupção 10h mov ah,4ch ;move o valor 4ch para o registrador ah int 21h ;interrupção 21h END ;finaliza o código do programa - Este programa assembly muda o tamanho do cursor. - Salvar o arquivo com o seguinte nome: exam1.asm (não esquecer de salvá-lo no formato ASCII). - Usar o programa TASM para construir o programa objeto. C:\>tasm exam1.asm Turbo Assembler Version 2.0 Copyright (c) 1988, 1990 Borland International Assembling file: exam1.asm Error messages: None Warning messages: None Passes: 1 Remaining memory: 471k - O TASM só pode criar programas no formato .OBJ, que ainda não pode ser executado... - Usar o programa TLINK para criar o programa executável. C:\>tlink exam1.obj Turbo Link Version 3.0 Copyright (c) 1987, 1990 Borland International C:\> - Onde exam1.obj é o nome do programa intermediário, .OBJ. - O comando acima gera diretamente o arquivo com o nome do programa intermediário e a extensão .EXE. - É opcional a colocação da extensão .obj no comando. - Executar o programa executável criado. C:\>exam1[enter] - Lembre-se, este programa assembly muda o tamanho do cursor no DOS. * Exemplo 2 ;nome do programa: one.asm ; .model small .stack .code mov AH,1h ;Função 1 do DOS Int 21h ;lê o caracter e returna o código ASCII ao registrador AL mov DL,AL ;move o código ASCII para o registrador DL sub DL,30h ;subtrai de 30h para converter a um dígito de 0 a 9 cmp DL,9h ;compara se o dígito está entre 0 e 9 jle digit1 ;se verdadeiro obtém o primeiro número (4 bits) sub DL,7h ;se falso, subtrai de 7h para converter a uma letra A-F digit1: mov CL,4h ;prepara para multiplicar por 16 shl DL,CL ;multiplica para converter dentro dos 4 bits mais altos int 21h ;obtém o próximo caracter sub AL,30h ;repete a operação de conversão cmp AL,9h ;compara o valor 9h com o conteúdo do registrador AL jle digit2 ;se verdadeiro, obtém o segundo dígito sub AL,7h ;se falso, subtrai de 7h digit2: add DL,AL ;adiciona o segundo dígito mov AH,4Ch ;função 4Ch do DOS (exit) Int 21h ;interrupção 21h End ;finaliza o programa - Este programa lê dois caracteres e os imprime na tela * Exemplo 3 ;nome do programa: two.asm .model small .stack .code PRINT_A_J PROC MOV DL,'A' ;move o character A para o registrador DL MOV CX,10 ;move o valor decimal 10 para o registrador CX ;este valor é usado para fazer laços com 10 interações PRINT_LOOP: CALL WRITE_CHAR ;Imprime o caracter em DL INC DL ;Incrementa o valor do registrador DL LOOP PRINT_LOOP ;laços para imprimir 10 caracteres MOV AH,4Ch ;Função 4Ch, para sair ao DOS INT 21h ;Interrupção 21h PRINT_A_J ENDP ;Finaliza o procedimento WRITE_CHAR PROC MOV AH,2h ;Função 2h, imprime caracter INT 21h ;Imprime o caracter que está em DL RET ;Retorna o controle ao procedimento que chamou WRITE_CHAR ENDP ;Finaliza o procedimento END PRINT_A_J ;Finaliza o programa - Este programa mostra os caracteres ABCDEFGHIJ na tela. * Exemplo 4 ;nome do programa: three.asm .model small .STACK .code TEST_WRITE_HEX PROC MOV DL,3Fh ;Move o valor 3Fh para o registrador DL CALL WRITE_HEX ;Chama a sub-rotina MOV AH,4CH ;Função 4Ch INT 21h ;Retorna o controle ao DOS TEST_WRITE_HEX ENDP ;Finaliza o procedimento PUBLIC WRITE_HEX ;........................................................; ;Este procedimento converte para hexadecimal o byte ; ;armazenado no registrador DL e mostra o dígito ; ;Use:WRITE_HEX_DIGIT ; ;........................................................; WRITE_HEX PROC PUSH CX ;coloca na pilha o valor do registrador CX PUSH DX ;coloca na pilha o valor do registrador DX MOV DH,DL ;move o valor do registrador DL para o registrador DH MOV CX,4 ;move o valor 4 para o registrador CX SHR DL,CL CALL WRITE_HEX_DIGIT ;mostra na tela o primeiro número hexadecimal MOV DL,DH ;move o valor do registrador DH para o registrador DL AND DL,0Fh CALL WRITE_HEX_DIGIT ;mostra na tela o segundo número hexadecimal POP DX ;retira da pilha o valor do registrador DX POP CX ;retira da pilha o valor do registrador CX RET ;Retorna o controle ao procedimento que chamou WRITE_HEX ENDP PUBLIC WRITE_HEX_DIGIT ;......................................................................; ;Este procediento converte os 4 bits mais baixos do registrador DL ; ;para um número hexadecimal e o mostrana tela do computador ; ;Use: WRITE_CHAR ; ;......................................................................; WRITE_HEX_DIGIT PROC PUSH DX ;coloca na pilha o valor de DX CMP DL,10 ;compara se o número de bits é menor do que 10 JAE HEX_LETTER ;se não, salta para HEX_LETER ADD DL,"0" ;se sim, converte para número JMP Short WRITE_DIGIT ;escreve o caracter HEX_LETTER: ADD DL,"A"-10 ;converte um caracter para hexadecimal WRITE_DIGIT: CALL WRITE_CHAR ;imprime o caracter na tela POP DX ;Retorna o valor inicial do registrador DX ;para o registrador DL RET ;Retorna o controle ao procedimento que chamou WRITE_HEX_DIGIT ENDP PUBLIC WRITE_CHAR ;......................................................................; ;Este procedimento imprime um caracter na tela usando o D.O.S. ; ;......................................................................; WRITE_CHAR PROC PUSH AX ;Coloca na pilha o valor do registarador AX MOV AH,2 ;Função 2h INT 21h ;Interrupção 21h POP AX ;Extrai da pilha o valor de AX RET ;Retorna o controle ao procedimento que chamou WRITE_CHAR ENDP END TEST_WRITE_HEX ;Finaliza o programa * Exemplo 5 ;nome do programa: four.asm .model small .stack .code TEST_WRITE_DECIMAL PROC MOV DX,12345 ;Move o valor decimal 12345 para o registrador DX CALL WRITE_DECIMAL ;Chama o procedimento MOV AH,4CH ;Função 4Ch INT 21h ;Interrupção 21h TEST_WRITE_DECIMAL ENDP ;Finaliza o procedimento PUBLIC WRITE_DECIMAL ;.................................................................; ;Este procedimento escreve um número de 16 bit como um número ; ;sem sinal em notação decimal ; ;Use: WRITE_HEX_DIGIT ; ;.................................................................; WRITE_DECIMAL PROC PUSH AX ;Põe na pilha o valor do registrador AX PUSH CX ;Põe na pilha o valor do registrador CX PUSH DX ;Põe na pilha o valor do registrador DX PUSH SI ;Põe na pilha o valor do registrador SI MOV AX,DX ;move o valor do registrador DX para AX MOV SI,10 ;move o valor 10 para o registrador SI XOR CX,CX ;zera o registrador CX NON_ZERO: XOR DX,DX ;zera o registrador CX DIV SI ;divizão entre SI PUSH DX ;Põe na pilha o valor do registrador DX INC CX ;incrementa CX OR AX,AX ;não zero JNE NON_ZERO ;salta para NON_ZERO WRITE_DIGIT_LOOP: POP DX ;Retorna o valor em modo reverso CALL WRITE_HEX_DIGIT ;Chama o procedimento LOOP WRITE_DIGIT_LOOP ;loop END_DECIMAL: POP SI ;retira da pilha o valor do registrador SI POP DX ;retira da pilha o valor do registrador DX POP CX ;retira da pilha o valor do registrador CX POP AX ;retira da pilha o valor do registrador AX RET ;Retorna o controle ao procedimento que chamou WRITE_DECIMAL ENDP ;Finaliza o procedimento PUBLIC WRITE_HEX_DIGIT ;......................................................................; ; ; ;Este procedimento converte os 4 bits mais baixos do registrador DL ; ;num número hexadecimal e os imprime ; ;Use: WRITE_CHAR ; ;......................................................................; WRITE_HEX_DIGIT PROC PUSH DX ;Põe na pilha o valor do registrador DX CMP DL,10 ;Compara o valor 10 com o valor do registrador DL JAE HEX_LETTER ;se não, salta para HEX_LETER ADD DL,"0" ;se ‚, converte em dígito numérico JMP Short WRITE_DIGIT ;escreve o caracter HEX_LETTER: ADD DL,"A"-10 ;converte um caracter para um número hexadecimal WRITE_DIGIT: CALL WRITE_CHAR ;mostra o caracter na tela POP DX ;Retorna o valor inicial para o registrador DL RET ;Retorna o controle ao procedimento que chamou WRITE_HEX_DIGIT ENDP PUBLIC WRITE_CHAR ;......................................................................; ;Este procedimento imprime um caracter na tela usando uma função D.O.S.; ;......................................................................; WRITE_CHAR PROC PUSH AX ;Põe na pilha o valor do registrador AX MOV AH,2h ;Função 2h INT 21h ;Interrupção 21h POP AX ;Retira da pilha o valor inicial do registrador AX RET ;Retorna o controle ao procedimento que chamou WRITE_CHAR ENDP END TEST_WRITE_DECIMAL ;finaliza o programa - Este programa mostra na tela os números 12345 * Exemplo 6 ;nome do programa: five.asm .model small .stack .code PRINT_ASCII PROC MOV DL,00h ;move o valor 00h para o registrador DL MOV CX,255 ;move o valor decimal 255 para o registrador CX ;usado para fazer um laços com 255 interações PRINT_LOOP: CALL WRITE_CHAR ;Chama o procedimento que imprime INC DL ;Incrementa o valor do registrador DL LOOP PRINT_LOOP ;Loop para imprimir 10 caracteres MOV AH,4Ch ;Função 4Ch INT 21h ;Interrupção 21h PRINT_ASCII ENDP ;Finaliza o procedimento WRITE_CHAR PROC MOV AH,2h ;Função 2h para imprimir um caracter INT 21h ;Imprime o caracter que está em DL RET ;Retorna o controle ao procediemento que chamou WRITE_CHAR ENDP ;Finaliza o procedimento END PRINT_ASCII ;Finaliza o programa - Este programa mostra na tela o valor dos 256 caracteres do código ASCII. *********************************************************** *********************************************************** 6 - Descrição de um Sistema Computacional - O processador tem uma série de células de Memória usadas com freqüência e, dessa forma, são partes da CPU. - Estas células são conhecidas com o nome de registradores. - Um processador de um PC possui cerca de 14 registradores. - Como os PCs tem sofrido evolução veremos que podemos manipular registradores de 16 ou 32 bits. - A unidade de lógica e aritmética da CPU realiza as operações relacionadas ao cálculo simbólico e numérico. - Tipicamente estas unidades apenas são capazes de realizar operações elementares, tais como: adição e subtração de dois números inteiros, multiplicação e divisão de número inteiro, manuseio de bits de registradores e comparação do conteúdo de dois registradores. - Os registradores são grupos de 8 ou 16 flip-flops. - Computadores pessoais podem ser classificados pelo que é conhecido como tamanho da palavra, isto é, a quantidade de bits que o processador é capaz de manusear de uma só vez. - Um grupo de 16 bits é conhecido como palavra; uma palavra pode ser dividida em grupos de 8 bits chamados bytes, e grupos de 4 bits chamados nibbles. - Registradores da CPU. - Para o propósito didático, vamos focar registradores de 16 bits. - A CPU possui 4 registradores internos, cada um de 16 bits. - São eles AX, BX, CX e DX. - São registradores de uso geral e também podem ser usados como registradores de 8 bits. - Para tanto devemos referenciá-los como, por exemplo, AH e AL, que são, respectivamente, o byte high e o low do registrador AX. - Esta nomenclatura também se aplica para os registradores BX, CX e DX. - Os registradores, segundo seus respectivos nomes: AX Registrador Acumulador BX Registrador Base CX Registrador Contador DX Registrador de Dados DS Registrador de Segmento de Dados ES Registrador de Segmento Extra SS Registrador de Segmento de Pilha CS Registrador de Segmento de código BP Registrador Apontador da Base SI Registrador de Índice Fonte DI Registrador de Índice Destino SP Registrador Apontador de Pilha IP Registrador Apontador da Próxima Instrução F Registrador de Flag *********************************************************** *********************************************************** 7 - Bibliografias - Assembly Language - Autores Diversos - Coleção Master Class - Editora Wrox - Páginas: 16,17,24,25 - http://www.tol.pro.br/01234151617890/tutorial/52.ZIP - Tutorial no qual foi baseado este trabalho (Português) - http://tol.nahp.brturbo.com/01234151617890/tutorial/52.ZIP - Mirror para o mesmo Tutorial (Português) - http://devlib.virtualave.net/dir/files/assemb.zip - Mirror para o mesmo Tutorial (Inglês) - http://directory.google.com/Top/Computers/Programming/Languages/Assembly/x86/FAQs,_Help,_and_Tutorials/ - Links - http://devlib.virtualave.net/asm1.html - Tutoriais para Assembly e muitas outras linguagens *********************************************************** ----------//----------