Arquitectura de Computadores – Curso Informática Componente Linguagem Assembly Guia Prático Índice 1. Introdução .................................................. 3 1.1. Linguagem ................................................................................................................. 3 1.2 Representação de dados .................................................................................... 3 1.3 Estrutura de um programa ............................................................................... 4 2. Organização do CPU .......................................... 6 2.1. Registos ................................................................................................................... 6 A) Registos de uso geral ............................................................................ 6 B) Registos de endereço .............................................................................. 6 C) Registos de Segmento .............................................................................. 6 D) Registos de controlo e Flags ........................................................... 7 E) Registos de 32 bits ................................................................................. 7 F) Esquema dos registos ............................................................................... 7 3. Instruções e operações básicas com registos ................. 9 3.1 Operações básicas ................................................................................................ 9 3.2 Operações com registos .................................................................................. 13 a. Registo AX ....................................................................................................... 13 b. Registo BX ....................................................................................................... 13 c. Registo CX ....................................................................................................... 14 d. Registo DX ....................................................................................................... 14 e. Registo IP ....................................................................................................... 14 f. Registo SI (Source Index) ................................................................... 15 g. Registo DI (Destination Index) ....................................................... 15 h. Registos BP, SP e a Pilha (Stack) ................................................ 15 4. Segmentação e o Segmento DS ................................ 17 4.1 Segmentos ................................................................................................................. 17 4.2 CS (Code Segment) .............................................................................................. 18 4.3 ES (Extra Data Segment) ................................................................................ 18 4.4 SS (Stack Segment) ............................................................................................ 18 5. Modos de endereçamento ..................................... 19 5.1 Imediato .................................................................................................................... 19 5.2 Registo ...................................................................................................................... 19 5.3 Directo ...................................................................................................................... 19 5.4 Indirecto ................................................................................................................. 19 5.5 Relativo .................................................................................................................... 20 5.6 Indexado .................................................................................................................... 20 6. Chamadas ao sistema (System calls) ......................... 21 7. Directivas ................................................. 23 7.1 Directivas mais usadas .................................................................................. 23 7.2 Directivas de alocação .................................................................................. 24 7.3 Outras Directivas .............................................................................................. 25 7.4 Operandos ................................................................................................................. 26 2 1. Introdução 1.1. Linguagem As razões que levam a usar a programação em assembly prendem-se por permitir uma maior aproximação à máquina Os programas em assembly ocupam menos espaço em memória (10 x menos), são mais rápidos (2 a 3 x mais rápidos) e os programas em alto nível podem usar rotinas feitas em assembly. O esquema usado é apresentado na figura seguinte. 1.2 Representação de dados Consideramos aconselhável introduzir, desde assembly se representam números nos diferentes A transformação de números entre sistemas de introdutória a este manual. Vamos então ilustrar a representação de 100 em numeração. Note-se a presença ou ausência de um já, a forma como em sistemas de numeração. numeração é do âmbito diferentes sistemas de sufixo. Em decimal o número escreve-se sem qualquer alteração; exemplo: Mov bx, 100 Em binário acrescenta-se um b ao fim do número; exemplo: Mov bx, 01100100b Em Octal acrescenta-se um º no fim do número; exemplo: Mov bx, 144º Em hexadecimal acrescenta-se um h no fim do número. Se o número começar por letra acrescenta-se um 0 no princípio para não confundir com um label; exemplo: Mov bx, 64h Mov bx, 0E5Bah Os caracteres são carregados introduzido o valor ASCII, exemplo: entre plicas, aspas ou é Mov dl, 65; ASCII A 3 Mov dl, 41h Mov dl, ‘A’ Mov dl, “A” Os números em vírgula flutuante são carregados Directivas DD, DQ e DT que abordaremos no capítulo 7. através de 1.3 Estrutura de um programa Um programa em Assembly comporta: Comentários Etiquetas (Labels) Directivas Operadores Conjunto de instruções Modos de endereçamento Chamadas ao sistema (System Calls) Atendemos à estrutura básica de um programa .MODEL small ; Modelo .STACK 100h ; Tamanho da stack .DATA ; Início secção de dados (DS) .CODE ; Início código (CS) inicio: ; Label Mov ah, 4ch Int 21h END inicio do código ; Terminar programa ; Interrupção do DOS ; Fim e indicação do inicio da execução Este programa não faz nada de útil, regressando ao DOS. As linhas de código, instruções ou comandos, têm o seguinte formato: <label:> <instrução/Directiva> <operando, operando> <;comentário> Por exemplo: l1: Mov ax, cx ; axcx Por serem muito simples iremos abordar os comentários e as etiquetas nesta introdução. Os comentários servem para reflectir o que o programador quer fazer com a instrução. Antes de cada bloco de código deve ser explicada a sua função. Os comentários são colocados após o sinal de ponto e vírgula (;). As etiquetas ou labels, em inglês, são nomes simbólicos dados a endereços, úteis, principalmente para referências de linhas de código, bem como saltos. As variáveis ou constantes permitem ir buscar instruções à memória. Seguem-se alguns exemplos: val1 msg max decimal .DATA dw ? ; Espaço para dois bytes (1 word) db ‘Olá, Bom dia’ ; Cada carácter ocupa 1 byte equ 100 ; Definição de constante max = 100 4 inicio: … jmp … inicio ;Salta para inicio Nestes dois extractos de código as palavras val1 e msg são variávies, max é uma constante e inicio é uma etiqueta ou label. 5 2. Organização do CPU 2.1. Registos Os registos são células de memória no interior do processador com um acesso muito rápido. Os registos comuns da família de processadores conhecida por iAPx86 (INTEL): 8086, 8088, 80186, 80286, 80386,80486... Em comum: 16/8 bits A) Registos de uso geral Acumulador: registo “especial”, apesar de ser “general purpose” principalmente destinado a operações aritméticas, lógicas e deslocamento. É uma espécie de memória auxiliar muito útil durante o processo de computação, de tecnologia avançada e extremamente rápida, localizada dentro da CPU. AX AH + AL Acumulador: AX AH AL 16 bits 8 bits (High byte) 8 bits (Low byte) Tal como AX, existem outros registos de aplicação geral, mas incluindo finalidades específicas: Endereço Base: BX BH + BL Contadores: CX CH + CL Dados gerais e endereços de I/O: DX DH + DL B) Registos de endereço Existem registos com funções específicas. especializados a guardar endereços: Base Pointer: Stack Pointer (Topo): Source Index: Destination Index: Estes registos BP SP Registos de gestão da pilha SI DI Registos de índice (acesso a vectores) são C) Registos de Segmento Temos registos de Segmento de memória. O 8086 pode endereçar até 1 Mbyte de memória. De uma só vez apenas pode endereçar 254 Kbytes em blocos de 64 Kbytes (segmentos). Estes são, assim, áreas distintas de um programa. - Code Segment: Data Segment: Stack Segment: Extra Segment: CS DS SS ES 6 D) Registos de controlo e Flags O ponteiro de instruções, Instruction Pointer (IP), é um registo que aponta o endereço da próxima instrução a ser executada. Todo o processador contém um registo especial chamado SR (Status Register), constituído por bits indicadores de estados de operações, popularmente conhecidos por Flags. (Operação anterior resultou em zero ou carry? Há uma interrupção?), etc.. As flags principais, em qualquer processador são: Flag O Z S P D I C A T Descrição Overflow O bit “O” é ‘1’ quando a operação anteriormente executada resultou em overflow. É ‘0’ se não existiu overflow; Zero Z é ‘1’ quando a operação anterior resultou em 0; Sign S é ‘1’ quando a operação anterior resultou num resultado negativo (MSB=1); Parity P é ‘1’ quando o resultado de uma operação contém um número para de bits igual a ‘1’; Direction Direcção do movimento no acesso a strings. D é ‘0’ se os offsets SI e DI são incrementados. Se D é ‘1’ se são decrementados; Interrupção Carry Transporte final numa operação; Auxiliary carry Operações entre bits; Trap Flag E) Registos de 32 bits A arquitectura x86 evoluiu, e há registos que não são comuns aos 80386 e 80486. São registos de 32 bits: eax, ebx, ecx, edx, ebp, esi, edi, esp, eip, em que o ‘e’ significa “extended”. F) Esquema dos registos Organização dos registos da família de processadores Intel x86: 31 23 15 7 AH DH CH BH 0 AL DL CL BL Stack Base Pointer Source Index Destination Index Stack Pointer 16 bits AX DX CX BX 32 bits EAX EDX ECX EBX BP EBP SI DI SP ESI EDI ESP CS Code Segment SS Stack Segment DS Data Segment 7 31 23 15 7 0 16 bits 32 bits ES Extra Segment FS Extra Segment GS Extra Segment EFLAGS EIP Extended Instruction Pointer Flags AF – Auxiliary Carry OF – Overflow SF – Sign CF – Carry PF – Parity ZF – Zero 8 3. Instruções e operações básicas com registos 3.1 Operações básicas Vamos abordar as instruções mais simples com registos já estudados. As instruções podem ser agrupadas em 6 grandes conjuntos: Movimentação de dados; Aritméticas; Lógicas e de deslocamento; Controlo; Derivação; Manipulação de blocos e strings; a) MOV Mnemónica MOV Descrição Movimento. Usada na transferência de informação (Move byte or Word) Exemplo mov ax, 5h (ax é carregado com o valor de 5 hexadecimal) mov bx, ax (bx é carregado com o conteúdo de ax) b) Aritméticas Mnemónica Descrição ADD Adição (Arithmetic addition) ADC Adição com carry SUB Subtracção (Subtract) SBB Subtracção com borrow Multiplicação (AX * Reg) Se 32 bits usa o DX para auxiliar. Divisão Se 32 bits axquociente Dx resto MUL DIV Exemplo mov ax, 5H (Ao conteúdo de ax é adicionado com o valor de 5 hexadecimal) mov ax, cx (ax é carregado com a soma de ax com cx) Adiciona o carry da operação anterior mov bx, 5H (Ao conteúdo de bx é subtraido o valor de 5 hexadecimal) mov ax, cx (ax é carregado com a subtracção de ax com cx) Usa o borrow da operação anterior mov al, 2 mov bx, 3 mul bx ;ax fica com 6 mov ax, 30 mov bl, 10 div bx ;AHquociente, ALresto 9 c) INC Mnemónica INC Descrição Incremento de 1 (Increment) DEC Decremento (Decrement) NEG Troca de sinal LOOP Decrementa CX e repete o ciclo até CX = 0 LOOPZ Ciclo que também teste a ZF = 1 Exemplo inc dx (Ao conteúdo de dx é incrementado o valor de 1) dec dx (Ao conteúdo de dx é decrementado o valor de 1) mov bx, 2h neg bx Loop Mov cx, 30h L1: Loop L1 d) Salto Mnemónica Jmp Descrição Salto incondicional (Unconditional Jump) Salto condicional; É uma instrução que analisa a flag Z (Jump not zero) Jnz JA JAE JB JBE JC JCXZ JE JG JGE JL JLE JMP JNA JNAE JNB JNBE JNC JNE JNG JNGE JNL JNLE JNO JNP JNS JNZ JO JP JPE JPO JS JZ Exemplo Jmp l1 (Salto para a linha de código contendo a label l1) sub cx,1; Qd cx=0 ZF = 1 jnz l2 (Salto para a label l2 se o resultado da operação anterior foi diferente de zero) Jump if Above Jump if Above or Equal Jump if Below Jump if Below or Equal Jump if Carry Jump if CX Zero Jump if Equal Jump if Greater(signed) Jump if Greater or Equal(signed) Jump if Less(signed) Jump if Less or Equal(signed) Unconditional Jump Jump if Not Above Jump if Not Above or Equal Jump if Not Below Jump if Not Below or Equal Jump if Not Carry Jump if Not Equal Jump if Not Greater(signed) Jump if Not Greater or Equal(signed) Jump if Not Less(signed) Jump if Not Less or Equal(signed) Jump if Not Overflow(signed) Jump if No Parity Jump if Not Signed(signed) Jump if Not Zero Jump if Overflow(signed) Jump if Parity Jump if Parity Even Jump if Parity Odd Jump if Signed(signed) Jump if Zero CF=0 and ZF=0 CF=0 CF=1 CF=1 or ZF=1 CF=1 CX=0 ZF=1 ZF=0 and SF=OF SF=OF SF!= OF ZF=1 or SF!= OF unconditional CF=1 or ZF=1 CF=1 CF=0 CF=0 and ZF=0 CF=0 ZF=0 ZF=1 or SF!= OF SF!= OF SF=OF ZF=0 and SF=OF OF=0 PF=0 SF=0 ZF=0 OF=1 PF=1 PF=1 PF=0 SF=1 ZF=1 10 e) Deslocação e rotação Mnemónica Descrição Exemplo shl al,1 ; o bit à direita recebe um zero mov cl, 4 shl al, cl ; 4 deslocações SHL/SAL Shift left (o bit mais à esquerda passa para a CF) SHR/SAR Shift rigth (o bit da direita vai para o carry) ROR Rotate right (Sem carry) ROL Rotate left (Sem carry) RCR RCL Rotate right (Com carry) Rotate left (Com carry) Mnemónica Descrição Cbw Converte byte numa word Cwd Converte Word numa doubleword. ror dx, 1; o LSB vai para MSB rol dx,1 ;o MSB vai para LSB rcr al, 1 rcl dx, 1 Exemplo mov al, -1 ;positivo ou negativo cbw mov axl, 600H ;usa registo dx auxiliar cbw f) Lógicas Mnemónica AND OR Descrição Exemplo and bx, cx AND lógico bit a bit and al, 2 Ou lógico bit a bit or cx, dx XOR Ou exclusivo NOT Complementa os bits xor al, 11101001b mov dl, 10000001b NOT dl g) XCHG Mnemónica Xchg IN OUT Descrição Troca de informação entre registos Leitura dos portos Escrita nos portos Exemplo xchg ax,cx in al, mov dx, mov al, porto out dx, 4h ; leitura porto 41h 20h ; escrita do valor 5 no 5 ; porto 20h dx recebe o nº al h) Uso de subrotinas e pilha Mnemónica CALL RET PUSH POP Descrição Chamada a uma subrotina Retorno de um call Guarda a informação de registos na pilha Devolve a informação da pilha PROC Inicia um bloco de código ENDP Termina um bloco de código Exemplo call Sub1 ; Faz push automático Sub1: … ret ;Faz pop automático push bx pop bx PROC NEAR;Pequenos retornos PROC FAR;Grandes Retornos > 64 K ENDP 11 i) Operações com strings Operador $ O símbolo $ é sempre igual ao OFFSET no segmento onde o programa está a executar. Isto é útil para obter tamanhos de strings, exemplo: str1 tam DB ‘Olá, como estão?’, 13, 10 equ ($-str1) A variável tam fica com o tamanho da string. Mnemónica Descrição (Load string/byte/Word) Substitui: … LODS/LODSB/LODSW mov si, OFFSET str1 mov al, [si] inc si ... CLD Clear D Flag STD Set D Flag STOS/STOSB/STOSW MOVS/MOVSB/MOVSW Move String/byte/Word SCAS/SCASB/SCASW Scan String/Byte/word CMPS/CMPSW Exemplo Estas instruções usam o DI como índice fonte do DS. Carrega em AL o byte endereçado por DS:SI e incrementa ou decrementa SI, dependendo do estado da flag D. Se D=0, SI é incrementado; Se D=1, SI é decrementado. cld std Oposto de LODS. Carrega string em memória a partir do AC Transferência directa de Memória (DS) para Memória (ES), DS:SI passa para ES:DI, SI e Di são incrementados ou decrementados no processo Compara Al com o byte apontado por ES:DI, actualizando as flags. DI é incrementado ou decrementado Compara string/Word Vamos ver um exemplo de utilização de alguns comandos de strings. Vamos procurar se a letra ‘t’ se encontra na string testestring. … .DATA testestring DB ‘Texto de teste’,0 tamanho EQU ($-testestring) … .CODE ;Início do código (CS) … Mov ax,@data ; início segmento de dados Mov es, ax Mov di, OFFSET testestring ;ES:DI Apontar DI para a string Mov al, ‘t’ ;Carregar AL com ‘t’ Mov cx, tamanho ; comprimento da string a ser verificada Cld ; verificação incrementando o DI pesquisa: Scasb ;faz ES:DI igual a Al? Je encontrou_t ; Salta se encontrou um t Loop pesquisa ; Salta enquanto cx não for zero … ;Não encontrou nenhum t 12 encontrou_t: Dec … di ; Aponta para o offset de “t” Iremos analisar algumas das instruções principais com maior detalhe. 3.2 Operações com registos a. Registo AX Vamos exemplificar com as instruções mov e add. Note que o ponto e vírgula (;) é o sinal de comentário. Mov ah,3 ; AH 3 ; O registo AH (o High-byte do acumulador) é carregado com o valor 3 AX AH 3 AL ???? Mov al,2 ;AL 2 AX AH 3 AL 2 Mov CX,1 ; CX 3 Add ax,cx ; ax ax + cx 20H 3H 23H AX CX AX Note-se que a notação ax ax + cx no campo de comentário é simplista. Tem como objectivo representar o seguinte (ax) ((ax) + (cx)). Isto significa que AX é carregado com o resultado da soma do valor anterior de AX com o valor (conteúdo) de CX. b. Registo BX Este é um registo de aplicação geral usado com maior frequência para apontar localizações de memória. Mov bx,4 ; bx 4 Mov al,[bx] ; Ver esquema abaixo O Registo bx é um offset em relação ao segmento de dados (DS). O conteúdo (dados) apontado por bx é carregado em AL. Esta instrução tem o nome de endereçamento indirecto (a ser analisada detalhadamente em breve). DS (Data Segment) contém endereços base, como apresentado no 20H 0 esquema. O Registo bx é aqui usado como um offset que tem os 30H 1 valores indicados à direita. Temos então que as instruções 23H 2 acima representadas resultam em carregar o registo AL com o 1AH 3 valor de 4BH. 4BH 4 … … AX Mov al,[bx] AH AL ? 4BH 13 c. Registo CX O registo CX é usado principalmente como um contador. Vamos ver dois exemplos: i) Tendo o seguinte código: Mov cx, 20H repetir: … Sub cx, 1 Jnz repetir … A secção entre a Label repetir e a instrução de salto (jnz) é repetida até que CX seja zero. Neste caso a flag Z toma o valor um devido ao resultado de sub cx,1. ii) Iremos agora ver o caso da instrução loop em conjunto com o registo CX. A instrução loop executa um ciclo que decrementa automaticamente CX e pára quando CX=0. Podemos então reescrever o código acima de uma forma mais simples usando esta instrução: Mov cx, 20H repetir: … Loop repetir … A secção código compreendida entre a label repetir e a instrução loop será repetida CX vezes. d. Registo DX Este registo tem como principal utilização o endereçamento de I/O. É o único registo que pode ser usado para este efeito. Neste caso, trabalha juntamente com AL e OUT em que no registo DX se armazena o endereço, no AL os dados e OUT representa o porto de saída. Vejamos a escrita de 30H no porto 200. Mov Mov Out al, 30h dx, 200 dx, al ; ; ; Vejamos agora as instruções de entrada: Mov In dx,100 al, dx ; ; Carrega AL com a informação contida no Porto 100. e. Registo IP Este Registo não é acedido pelo utilizador. Aponta para a instrução (código) seguinte a ser executada. Este endereço é um offset, ou seja a base deste endereço é o code segment (CS). 14 f. Registo SI (Source Index) É um registo que, tal como BX, aponta para posições de memória. Vamos carregar AL com o conteúdo endereçado por SI. Mov Mov si, 30h al, [si] DS … 4AH … SI … 30h … Após esta instrução o acumulador fica como se mostra: AH ? AX AL 4A H g. Registo DI (Destination Index) É um registo que pode ser usado tal como SI. Mov Mov di, 30h bl, [di] DS … 3BH … DI … 30h … Após esta instrução o BX fica como se mostra: BH ? BX BL 3B H Oportunamente veremos que os registos SI e DI têm aplicações específicas na manipulação de strings. Aqui estes registos servem para endereçar a fonte e o destino, respectivamente SI e DI. h. Registos BP, SP e a Pilha (Stack) Os registos BP e SP apontam para posições relativas da Pilha (stack). O processador acede à Pilha por meio do registo SP. BP aponta para a base da pilha e SP aponta para o topo da pilha. O registo BP, que indexa o segmento da pilha, não tem qualquer função directa na manipulação da pilha. Utiliza-se para aceder aos elementos da pilha pela posição que nela ocupam. Não confundir estes dois registos com BX, SI e DI. A memória apontada por estes três registos é em relação ao DS (Data Segment), ou, no caso de DI, também ao ES. A pilha (stack) armazena dados especiais, como por exemplo, cálculos recursivos ou temporários, o endereçamento e retorno de uma subrotina, etc. … SP BP 15 As instruções usadas para colocar e retirar dados da pilha são o push e o pop. O push coloca um valor (dado) no topo da pilha. O pop retira o valor da stack. Sempre que se efectua estas operações o SP é actualizado automaticamente. Note-se que a pilha funciona como uma LIFO (Last In, First out), ou seja o último valor a ser carregado é o primeiro a sair. Vejamos um exemplo: … 45 2B 1A End. da Pilha 306 305 304 303 302 301 300 SP BP O seguinte código produz alterações na pilha: Mov Mov Push Add Push Pop Pop dx, 5 ; cx, dx; dx ; ; cx, 1 ; cx ; ; cx ; ; dx ; ; dx 5 cx 5 stack dx SP = 303 cx 6 stack dx SP = 304 o valor de cx é retirado da stack o valor de dx é retirado da stack … 6 5 45 2B 1A End. da Pilha 306 305 304 303 302 301 300 SP BP Destaque-se a sequência das instruções Push e Pop: Push Push … Pop Pop dx cx cx dx Assim é a única forma correcta de retirar os valores de CX e DX da pilha. Isto deve-se à característica LIFO da pilha. As instruções PUSHF e POPF são idênticas às PUSH e POP mas servem para os registos FLAGS. 16 4. Segmentação e o Segmento DS 4.1 Segmentos Segmentos são blocos de memória de 64 K (nos processadores mais modernos 386/486/Pentium podem ir até 4 Gigabyte) onde residem, separadamente, o código e os dados. O stack é também um segmento, mas de tamanho menor (512 a 1024 bytes apenas). Num programa os segmentos representam áreas distintas. A informação é acedida à base de segmento : offset. O registo de segmento é deslocado à esquerda de 4 vezes, ou seja, uma multiplicação por 16 e adicionado o offset. Isto acontece porque os registos são de 16 bits (8086 ao 80286) e as linhas de endereço serem de 20 bits. Portanto há um conflito, pois 216 = 64 K (Registos) e 220 = 1 Megabyte (dos endereços). Esquematicamente: AX BX CX … A0 … … A19 Temos então 20linhas de endereço para registos de 16 bits. Notemos que a partir do processador 80386 começaram a aparecer registos de 32 bits. Vamos ver um exemplo para determinar um determinado endereço físico: DS = 2000 H ; o endereço base do segmento de dados é 2000 H SI = 300 H ; O SI é o offset, neste caso com o valor de 300 H Temos então que 2000 H : 300 H (Ambos de 16 Bits) deslocar 2000 H à esquerda de 4 bits (0010 0000 0000 0000 0000) fica 20000H donde o endereço efectivo colocado no address bus é de 20000H + 300 H ou seja 20300 H Normalmente não se carrega estes segmentos directamente com números (endereços), mas sim através dos seus próprios nomes simbólicos. No caso do turbo assembler: .DATA, .CODE, .STACK, etc. O processo de compilação e linkagem encarrega-se de carregá-los com valores específicos. No caso do sistema operativo DOS o nome do segmento de dados é: .DATA Pelo que podemos acedê-lo através do comando @data e carregá-lo (o se endereço base) no registo do segmento de dados (DS) com o auxílio de um registo de aplicação geral; nunca directamente. Vamos exemplificar: Mov ax, @data ;DS contém o endereço base da secção de dados Mov ds,ax ; Assim num programa há uma secção de dados chamada .DATA .DATA ;início da área de dados (DS ou ES) Val1 dw 5 ; Val2 db 4 ; … 17 .CODE Mov Mov Val1; ax, @data ds, ax ; início da secção de código (CS) ; ; ;DS aponta, neste momento, para a variável ;Início do bloco de dados 4.2 CS (Code Segment) O segmento de código é o registo que aponta para o endereço base do Code Segment (CS), normalmente um bloco de 64 K. Conforme analisado o registo IP contém o endereço da próxima instrução a ser executada, pode ser um comando ou linha de código. Donde se pode concluir que o CS está directamente relacionado com o registo IP. 4.3 ES (Extra Data Segment) Na continuação da análise sobre segmentação, o registo ES (64 K) pode servir de área adicional de armazenagem de dados. Esta área, quando usada na maniplação de strings, serve de local de destino. ES : DI 4.4 SS (Stack Segment) Já analisado. 18 5. Modos de endereçamento Vamos considerar seis formas de endereçamento: directo, indirecto, relativo e indexado. imediato, registo, 5.1 Imediato A instrução contém o valor do operando. Não há o recurso a qualquer posição de memória. Aqui os dados especificados como fazendo parte da instrução. Alguns exemplos: Mov Add Mov Mov al, 00 al,04 ax,0ffffh ebx,0BCD1A123h ; al 00H ; al al + 4 ; ax FFFFFH (16 bits) ;32 bits 5.2 Registo Neste método existe a transferência operandos estão contidos em registos: Mov Mov Mov bl, al ds,cx edx, ebx de dados entre registos. Os ; ; ; Só para processadores 32 bits 5.3 Directo A instrução contém o endereço de memória onde está armazenado o valor que se pretende usar. Mov ax, data1 ; ax é carregado com o conteúdo da localização de memória apontado pelo endereço de memória associado à variável data1 DS … 3BH 01 … AX Endereço … 30h 31h … 0 0000 1 0001 Low Byte High byte 3 0011 B 1010 5.4 Indirecto O endereçamento é efectuado através de um dos seguintes registos. SI, DI, BX ou BP. Estes registos devem estar contidos entre parêntesis rectos [ ], por exemplo, [bx]. É um modo de endereçamento muito eficaz para aceder a tabelas. Para serem usados estes registos necessitam de ser carregados, vejamos dois exemplos: a) Atente ao seguinte código: Lea Mov bx, data1 ax, [bx] ; load effective address ; address data1 19 Temos que bx é carregado com o offset, ou endereço de data1 no DS. Na instrução seguinte ax é carregado com o valor apontado por bx. No caso ax é carregado com o valor 01AB. End … Mem … DS 0005 0006 AB 01 L Byte H Byte b) Atente ao seguinte código: Mov bx, OFFSET data1 Carrega bx com o endereço offset de data1. Chama-se directiva a label OFFSET. 5.5 Relativo Neste modo exemplo: … data2 … Lea Mov Mov ... de endereçamento existe uma base relativa e um offset, por db ‘BOA TARDE!’ bx, data2 al, [bx]+0 al, [bx]+7 ; Carrega B ; Carrega D A instrução mov al, [bx]+0 poderia ser substituída por mov al, [bx]. São possíveis algumas variações à forma como adicionar o endereço que se quer carregar, por exemplo [bx] + 7 ou [bx + 7] ou 7 [bx]. offset … 20 21 22 23 24 25 26 27 28 29 2A Mem … B O A data2 T A R D E ! … 5.6 Indexado Nesta forma … Data4 … Mov Mov … de endereçamento é permitida a utilização de um índice. db ‘Boa tarde!’ si, 0 al, data4[si] Desta forma podemos incrementar o índice SI de forma a aceder normalmente aos elementos de um dado array. 20 6. Chamadas ao sistema (System calls) O sistema operativo (SO) (MS-DOS) ocupa parte da RAM tal como os segmentos. O SO fornece um conjunto de funções, devidamente numeradas, as quais podem ser invocadas directamente pelo programa assembly, o qual deve carregar o registo AH com o número da função e invocar o interrupt 21 H conforme brevemente ilustrado. Destaque-se que o objectivo desta secção é demonstrar como aplicar estas funções, através de exemplos com números de funções possíveis de serem executadas no laboratório. Para se poder fazer uma chamada de uma função do DOS carrega-se o Registo AH com o número dessa função. Os outros registos podem, ou não, ser usados pela função. Depois de se carregar o registo AH com o número da função chama-se o interrupt 21h. Na tabela em Exemplo: Função 01H Read Keyboard and Echo. O carácter digitado é carregado no registo AL. … Mov ah, 1 Int 21h … 21 Ler o carácter que está agora no AL (é necessário digitá-lo) Exemplo: Função 02H Display Character. Esta função mostra o caracter em DL. … Mov ah,2 Mov dl, ‘B’ Int 21h … Assim combinando estas duas funções podemos ler e visualizar, para além do próprio eco, o carácter digitado do seguinte modo: … Mov ah, 1 ; leitura de carácter Int 21h ; al carácter Mov ah,2 ; Mov dl, al ; al fica à espera que se escreva no ecrã Int 21h … Exemplo: Função 4CH Terminate a Process. Esta função termina um processo em execução. Vejamos o exemplo ilustrado. Aqui o programa mostra o carácter digitado duas vezes, uma vez devido á digitação, outra devido à acção do eco. O programa termina quando a tecla <ENTER> é pressionada. Destaque-se ainda que este programa contém alguns princípios, directivas, etc., a serem introduzidos mais à frente neste manual. Queremos agora exemplificar o método de aplicação das funções. .MODEL cada small ;modelo para segmentos separados de 64K .STACK 100h ;Tamanho da Pilha .CODE ;Início do código (CS) echoloop: ; Label (serve para indicar um ponto de salto) Mov Int Cmp Jz leitura Mov Mov Int Jmp fim: Mov Int END ah,1 21h al, 13 fim dl, al ah, 2 21h echoloop ah, 4ch 21h ; ler a tecla digitada ;Comparar se a tecla foi <ENTER> ;Sim foi <ENTER>, chegamos ao fim da ;A comparação é uma subtracção. ;Se o resultado é uma igualdade ; produz um zero daí a z flag =1 ; visualizar outra vez o digitado ;repetir até que o <ENTER> seja lida ;fim do programa ;Executar a função 4CH ;Directiva END Exemplo: Outra função importante é Display String. A string deve terminar com o carácter ‘$’ e DX é o offset inicialmente carregado com o primeiro elemento da string. Um programa sobre esta função é introduzido mais tarde, já que precisamos de mais princípios a serem abordados. No entanto para referência indicamos que em anexo apresentamos exemplos de várias utilizações de funções do DOS 22 7. Directivas Neste capítulo vamos abordar as directivas. Ao longo deste texto já temos usado várias directivas e temos incluído um comentário explicativo da sua função. Devemos começar por dizer que as directivas não são instruções do processador. Antes são ordens para o assembler “organizar” a memória e os programas em assembler. 7.1 Directivas mais usadas END Indica o fim do código. Se escrevermos END xxx, este operando representa uma label que indica onde o código deve começar a ser executado. .STACK Define o tamanho da pilha para programas que façam uso dela. Define o Stack Segment (SS). A instrução .STACK 200h define uma pilha com 512 bytes. .CODE Define o início Instruções. segmento de código (Code Segment) – .DATA Define o início do segmento de dados ou do segmento extra de dados. Para se aceder a posições de memória nestes segmentos de dados deve-se carregar o registo DS com o símbolo @data Mov ax, @data ;para o segmento de dados Mov ds, ax Mov dx, @data ;para o segmento extra de dados Mov es, dx Um dos métodos para se inicializar o offset de DS, para se poder trabalhar conjuntamente com DS ou ES é o seguinte: mov dx, OFFSET dados Ou seja no contexto vamos apresentar um programa que mostra no ecrã uma mensagem, utilizando a função do DOS #9 (Print String) .MODEL small .STACK 200h .DATA dados DB ‘Viva as aulas de AC’ .CODE inicioprograma: Mov bx, @data ; bx é carregado com o início de DS ; não tem que ser sempre o ax Mov ds, bx ; ds inicio do segmento de dados Mov dx, OFFSET dados ; dx é carregado com o endereço da ; label dados (ex: offset 600H) Mov ah, 9 ; função DOS Int 21h ;invoca função do DOS de impressão Mov ah, 4Ch ; função DOS de terminar o pgm Int 21h END inicioprograma 23 Este programa mostra no ecrã a mensagem “Viva as aulas de AC” dados V i v … 600H 601H 602H DOSSEG Ordena os segmentos segundo uma ordem convencionada pela Microsoft. Não é necessário invocá-la. MODEL Modelo de memória utilizado. Modelos mais utilizados Tiny – O código e os dados cabem num mesmo segmento de 64 K. Small – O código e os dados cabem em segmentos separados de 64 K Medium – Código pode exceder 64 K e dados cabem num segmento de 64 K. Compact – Código em 64 K e dados excede 64 K. Large – Código e dados maiores que 64 K; Nenhum array excede 64K. Huge – tudo pode exceder 64 K. CONST Área de dados contendo as constantes. RADIX Directiva que permite indicar opcionalmente o sistema de numeração a seguir (valor por defeito; é pouco usada) 7.2 Directivas de alocação Estas directivas servem para definir bytes, podendo-se assim carregar valores: DB (Define Byte - 1 byte) DW (Define Word - 2 bytes) DD (Define Double Word - 4 bytes) DF, DP (6 bytes) DQ (Define Quadword - 8 bytes) DT (Define Ten Bytes) EQU(Equate) - atribui um valor constantes. a uma variável. Atribuição de Alguns exemplos. Alocação de um carácter: … .DATA letra1 DB ‘A’ … Mov ah,2 ; Função Display Mov dl, [letra1] Int 21h … Alocação de tabelas (arrays), caso 1: … .DATA array1 DB 20, 21, 22, 23, 24, 25 array2 DW 19, 11, 12, 13, 14, 15 … 24 Alocação de tabelas (arrays), caso 2: … .DATA array3 DB 100h DUP (0) … Aqui mostra-se o exemplo de como reservar espaço para um determinado array e inicializá-lo a zero. A tabela array3 tem 256 bytes, 100h, totalmente inicializados a zero, DUP (0). Alocação de tabelas (arrays), caso 3: … .DATA array3 DB 50 DUP (‘A’) … Alocação de tabelas (arrays), caso 4: … .DATA str1 DB ‘A’, ‘B’, ‘C’, ‘D’ str2 DB ‘ABCD’ … Aqui mostra-se que ambos os métodos são equivalentes pois a directiva DB guarda cada carácter num byte. Lembra-se que em strings deve-se avançar o cursor para linha seguinte inserindo o CR(carriage return), LF(Line Feed). Alocação de tabelas (arrays), caso 5: … .DATA val1 DW ((2000/2)+1) val2 DW 10 DUP (0) v DW val2 … Note-se que v guarda o valor do endereço de val2 e não o valor apontado pelo endereço. Exemplo de um programa que lê do teclado e armazena os caracteres num array: … .DATA caract DB 10 DUP(0) … .CODE Mov ax, @data Mov ds, ax Mov bx, OFFSET caract Mov cx, 10 repete: Mov ah, 1 ; DOS leitura de caracteres Int 21h Mov [bx], al ;Escrever no array o carácter digitado Inc bx Loop repete 7.3 Outras Directivas LABEL Esta directiva permite exemplo: caract DB 10 pode ser substituído caract LABEL DB 10 especificar o nome e o tipo de uma label, DUP(0) por: BYTE DUP (0) 25 Os tipo de label podem ser: WORD (2 Bytes), DWORD (4 Bytes), FWORD (6 Bytes), PWORD (8 Bytes), QWORD (10 Bytes). SEGMENT, ENDS e ASSUME Até agora analisámos as directivas de segmento simplificadas. Estas novas directivas, do tipo standard, são bastante úteis em programas mais complexos, permitindo-nos nomear as suas partes constituintes. Por exemplo, a secção de código seguinte começa em código, e os blocos de dados são associados data1 a DS e data2 a ES, através da directiva ASSUME: … data1 var1 data1 SEGMENT WORD ‘DATA’ DW 0 ENDS data2 var2 data2 SEGMENT WORD ‘DATA’ DW 0 ENDS codigo SEGMENT WORD ‘CODE’ Assume cs:codigo Inicio: codigo Mov Mov ASSUME Mov Mov ASSUME … ENDS END ax, data1 ds, ax ds:data1 ax, data2 es, ax ds:data2 ; coloca Data1 em DS ; coloca Data2 em ES Inicio PUBLIC, EXTERN e GLOBAL Estas directivas são necessárias para declarações das componentes globais, externas (programa chamante) e públicas (programa chamado), pertencentes a programas contidos em diferentes ficheiros. 7.4 Operandos Como temos visto os operandos de uma operação podem ser registos, ax, bx, al, entre outros, e constantes, 5, ‘A’. Vamos agora analisar os casos em que os operandos podem ser expressões mais complexas. … .DATA valor1 DB 0 valor2 DB 0 valor3 DB 0 .CODE Mov ax, SEG valor1 Mov ds, ax Mov bx, OFFSET valor2 Mov BYTE PTR [bx], 5H Mov al, SIZE valor3 Vamos atender à instrução mov ax, SEG valor1. A instrução referida carrega ax com o segmento de dados onde está valor1. Ou seja a expressão SEG faz o mesmo que mov ax, @data. 26 Num segundo caso vamos ver a expressão mov bx, OFFSET valor2. Aqui o registo bx é carregado com o valor do endereço da label (variável valor2). Assim [bx] acede ao valor, conteúdo, apontado por bx. A terceira expressão é mov BYTE PTR[bx], 5H. A expressão indica que é do tipo byte e carrega o valor 5H (1 byte) na variável valor2. Vejamos e exemplo de um programa que efectua a soma de duas palavras longas (4 bytes cada). O resultado é armazenado em soma (4 bytes). … .DATA valor1 DD 100h valor2 DD 150h soma DD ? .CODE Mov ax, WORD PTR [valor1] ; ax L-word de valor1 Mov dx, WORD PTR [valor1+2] ;dx H-word de valor 1 Add ax, WORD PTR [valor2] ;axL-word de valor2 +ax Add dx, WORD PTR [valor2+2] ;dxH-word de valor2 +dx Mov WORD PTR [soma], ax ; L-word de soma ax Mov WORD PTR [soma+2], dx ; H-word de soma dx A última expressão é mov al, SIZE valor3. Aqui SIZE indica o tamanho da variável. Ou seja 2 é carregado em al pois é a definição de valor 2, dois bytes. 27 Anexo A – Exemplos de uso de funções do DOS Exemplo da utilização da Função de mostrar uma string no ecrã. Exemplo de utilização da função de obtenção da data (Get Date) 28 Exemplo da função de (Set date) Exemplo de uma função de Get Time 29 Exemplo de uma função de Set Time 30 Exemplo de uma função de Open File 31 32