You are on page 1of 44

Assembly

Linguagem Assembly uma linguagem de programao de baixo nvel. Necessitamos de obter algum conhecimento sobre a estrutura do computador. O funcionamento simples do computador como o esquema seguinte:

O sistema de BUS (mostrado em amarelo) conecta / liga os diferentes componentes de um computador. O CPU o corao do computador, a maioria dos clculos ocorrem no interior da CPU. A memria RAM o local onde os programas so carregados, a fim de ser executados.

O 8080 um processador de 8 bits, isto , a sua UAL opera sobre nmeros de 8 bits. O seu bus de sistema tem, tambm, 8 linhas de dados. O 8086 um processador de 16 bits, com uma UAL operando sobre nmeros de 16 bits, pelo que o seu bus interno ao CPU e os seus registadores do CPU so de 16 bits. De modo a manter alguma compatibilidade, contudo, os registadores de dados do 8086 podem ser manipulados em 'duas metades' de 8 bits cada, de modo a, assim, se poder fazer a correspondncia com os registadores de 8 bits, do 8080. A compatibilidade entre estes dois processadores no vai muito mais longe, j que no 8086 se pretendeu alcanar um espao de endereos reais de 1MegaByte, muito superior aos 64KBytes do 8085, e a prpria forma de enderear a memria no 8086, muito mais sofisticada, pois recorre tcnica de segmentao, que o 8085 no tinha.

Unidade Central de Processamento

O CPU 8086 tinha 8 registos genricos, cada registo tinha o seu prprio nome: AX o acumulador de registos (dividido em AH / AL). BX - o registo do endereo base (dividido BH / BL). CX o contador de registos (dividido em CH / CL). DX o registo de dados (dividido em DH / DL). SI registo de procura de index. DI - registo de destino de index. BP ponteiro para a base. SP ponteiro para a pilha.

A utilizao de cada registo determinada pelo utilizador. O principal objectivo de um registo guardar um nmero (varivel). O tamanho dos registos de 16 bits, ou seja: 0011000000111001b (na forma binria), ou 12345 em decimal (escrita utilizada pelo homem). O microprocessador 8086 tem 4 registos genricos (AX, BX, CX, DX) podendo considerar-se dois registos de 8 bits, por exemplo, se AX = 0011000000111001b o AH=00110000b e AL= 00111001b. No entanto quando se modifica qualquer um dos registos de 8 bits o registo de 16 bits actualizado, e vice-versa. O mesmo acontece para os outros 3 registos, "H" significa "Alto", o registo mais significativo e "L" significa "Baixo" ou a parte do registo menos significativa.

Como os registos esto localizados no interior da UCP so muito mais rpidos do que a memria. Aceder a uma memria local requer a utilizao de um sistema de barramento (bus), por isso, leva muito mais tempo. O acesso aos dados num registo normalmente no tem tempo. Portanto, o utilizador deve tentar manter as variveis nos registos. O conjunto de registos muito pequeno e a maior parte deles tm funes especiais que limitam o seu uso como variveis, mas continuam a ser um bom lugar para armazenar temporariamente os dados que resultam dos clculos.

CS aponta para o segmento que contem o programa actual. DS geralmente aponta no segmento onde as variveis esto definidas. ES - registo de segmento extra, o cdigo actualizado sempre que um registo de segmento utilizado. SS aponta para o segmento que contem a pilha. Embora seja possvel armazenar alguns dados nos registos do segmento, esta hiptese no a melhor. Os registos do segmento tm uma funo muito especial, ou seja, tm a funo de apontar para os blocos de memria acessveis. Os registos do segmento trabalham juntamente com os registos genricos, para aceder a qualquer valor da memria. Por exemplo se o utilizador precisar de aceder memria no endereo fsico 12345h (hexadecimal), dever definir o DS = 1230h e o SI = 0045h. Desta forma tem-se acesso a muito mais memria do que com um nico registo que est limitado a 16 bits. O processador (CPU) faz um clculo do endereo fsico, multiplicando o registo de segmento por 10h e adicionando o registo genrico a este (1230h * 10h + 45h = 12345h):

O endereo formado com 2 registos, tem o nome de endereo efectivo. Por defeito, os registos BX, SI e DI trabalham com registo de segmento DS; O BP e o SP trabalham com o registo de segmento SS. Outros registos com funes gerais no podem formar um endereo efectivo! Embora BX possa formar um endereo eficaz, BH e BL no o podem fazer.

IP - o ponteiro de instruo. Flags Register - determina o estado actual do microprocessador. O registo IP trabalha sempre com o CS que um registo de segmento que aponta para a instruo que no momento est a ser executada. O registo das Flags modificado automaticamente pelo CPU depois de qualquer operao matemtica, isto permite determinar o tipo de resultado, e determinar as condies de transferncia de controlo para outras partes do programa. Normalmente no podemos ter acesso a esses registos directamente, a forma como ns podemos aceder a estes registos atravs do Ax e outros registos genricos, mas possvel alterar valores nos registos de sistema usando alguns truques.

Para ter acesso memria pode-se usar estes quatro registos: BX, SI, DI, BP. Combinando estes registos dentro de parntesis rectos, pode-se obter diferentes locais na memria. Estas combinaes suportam:

D8 Mantm-se em 8 bits designado por deslocamento imediato. D16 - Mantm-se em 16 bit designado por deslocamento imediato.

O deslocamento pode ser um valor imediato ou uma varivel, ou mesmo ambas. Se forem vrios valores, o assembly avalia todos os valores e calcula um valor imediato simples. O deslocamento pode estar dentro ou fora de parntesis recto, e o assembly gera o mesmo cdigo mquina para ambos. O deslocamento um valor assumido, por isso pode ser positivo ou negativo. Geralmente o compilador tem ateno diferena entre o d8 e d16 e gera o cdigo mquina necessrio.

Por exemplo, vamos assumir que DS = 100, BX = 30, SI = 70 O seguinte endereo: [BX + SI] + 25 calculado pelo processador para este endereo fsico : 100 * 16 + 30 + 70 + 25 = 1725. Por defeito os registos de segmentos DS so usados para todos os modelos, excepto aqueles com registos BP, para estes registos de segmentos usado o SS. Existe uma maneira fcil de recordar todas estas possveis combinaes usando este quadro:

Pode-se formar todas as combinaes vlidas ao retirar apenas um item de cada coluna, ou no retirando nenhum item da coluna. Como se pode verificar BX e BP nunca se encontram juntos. Para SI e DI isto tambm vlido. Aqui est um exemplo de um modo de endereo vlido:[BX+5],[BX+SI],[DI+BX-4]. O valor no registo de segmento (CS, DS, SS, ES) chamado de segmento, e o propsito do valor do registo (BX, SI, DI, BP) chamado de offset.. Quando DS contem o valor de 1234h e SI contem o valor 7890h ele tambm pode ser guardado como 1234:7890. O endereo fsico pode ser 1234h * 10h + 7890h = 19BD0h. Se zero for adicionado a um nmero decimal multiplicado por 10, contudo 10h = 16, ento se zero for adicionado a um valor hexadecimal, ele multiplicado por 16, por exemplo: 7h=7 70h=112

Para falar acerca do tipo de dados do compilador, estes so os prefixos que devem ser utilizados: byte ptr - para bytes. word ptr para palavras (dois bytes). Por exemplo: byte ptr [BX] ; byte access. or word ptr [BX] ; word access. O assembler tambm suporta pequenos prefixos tais como: b. - para byte ptr w. - para word ptr Em certos casos o assembler pode calcular o tipo de dados automaticamente.

Copia o segundo operando (fonte) para o primeiro operando (destino). O operando fonte pode ser um valor imediato, um registo genrico ou a localizao na memria. O registo de destino pode ser um registo genrico ou uma localizao na memria. Ambos os operandos tm de ter o mesmo tamanho, que pode ser um byte ou uma palavra. So suportadas estes tipos de operaes: MOV REG, memory MOV memory, REG MOV REG, REG MOV memory, immediate MOV REG, immediate REG: AX, BX, CX, DX, AH, AL, BL, BH, CH, CL, DH, DL, DI, SI, BP, SP. memory: [BX], [BX+SI+7], variable, etc... immediate: 5, -24, 3Fh, 10001101b, etc...

Para registos de segmentos apenas estes tipos de MOV so suportados: MOV SREG, memory MOV memory, SREG MOV REG, SREG MOV SREG, REG SREG: DS, ES, SS, and only as second operand: CS. REG: AX, BX, CX, DX, AH, AL, BL, BH, CH, CL, DH, DL, DI, SI, BP, SP. memory: [BX], [BX+SI+7], variable, etc... A instruo MOV no pode ser usada para colocar o valor nos registos CS e IP.

Pequeno programa que demonstra o uso da instruo MOV: ORG 100h ; this directive required for a simple 1 segment .com program. MOV AX, 0B800h ; set AX to hexadecimal value of B800h. MOV DS, AX ; copy value of AX to DS. MOV CL, 'A' ; set CL to ASCII code of 'A', it is 41h. MOV CH, 1101_1111b ; set CH to binary value. MOV BX, 15Eh ; set BX to 15Eh. MOV [BX], CX ; copy contents of CX to memory at B800:015E RET ; returns to operating system.

Utilizando um emulador , copiando e colando seguido de F5 - > single step ; - > comentrios

O programa anterior escreve directamente para a memria de vdeo, portanto pode-se ver que MOV uma importante instruo.

A varivel est num local da memria. Para o programador muito mais fcil ter um valor guardado numa varivel chamada var1 do que no endereo chamado 5A73:235B, especialmente quando se tem 10 ou mais variveis. Este compilador (8086) suporta dois tipos de variveis: BYTE e WORD. Sintaxe para a declarao de varivel: name DB value name DW value DB Mantm-se em Define Byte. DW Mantm-se em Define Word.

name Pode ser qualquer combinao de letras ou dgitos, deve comear com uma letra. possvel declarar variveis sem nome no especificando o nome (Esta varivel ter um endereo mas no um nome). value Pode ser qualquer valor numrico de qualquer sistema de numerao (hexadecimal, binrio, ou decimal), ou "?" smbolo para as variveis que no so inicializadas.

A instruo MOV tambm utilizada para copiar valores de origem para o destino. Exemplo com a instruo MOV: ORG 100h MOV AL, var1 MOV BX, var2 RET ; stops the program. VAR1 DB 7 var2 DW 1234h

Ao copiar este cdigo para um emulador do processador 8086, dever obter-se o seguinte :

Como se pode ver parece-se com este exemplo, excepto as variveis que so repostas com os locais da memria actualizados. Quando o compilador fizer o cdigo mquina, automaticamente repe todas as variveis com os respectivos nomes e offsets. Por defeito o segmento carregado no registo DS (Quando os ficheiros COM so carregados o valor do registo DS est definido para o mesmo registo CS). Na lista da memria a primeira linha um offset, a segunda linha um valor hexadecimal, a terceira linha um valor decimal, e a ltima linha um carcter da tabela ASCII

O compilador no distingue letras maisculas das minsculas, por isso "VAR1" e "var1" referem-se mesma varivel. O offset de VAR1 0108h, e o endereo completo 0B56:0108.

O offset de var2 0109h, e o endereo completo 0B56:0109, esta varivel uma WORD por isso ocupa 2 bytes. Assume-se que o byte menos significativo armazenado no endereo menos significativo, por isso 34h est localizado antes de 12h. Como se pode ver, existem algumas outras instrues depois da instruo RET, isto acontece por causa do descompilador no saber onde comeam os dados, e s processar os valores na memria e perceb-los como uma instruo vlida do 8086. Pode-se escrever o mesmo programa utilizando s a mesma directiva DB: ORG 100h ; s uma directiva para fazer um ficheiro simples DB 0A0h DB 08h DB 01h DB 8Bh DB 1Eh DB 09h DB 01h DB 0C3h DB 7 DB 34h DB 12h

Como se deve imaginar, o compilador s converte o programa fonte para o conjunto de bytes, este conjunto tem o nome de cdigo mquina, e o processador percebe e cdigo mquina e executa-o. ORG 100h um compilador directivo (significa que o compilador diz como trabalhar com o cdigo fonte). Este directivo muito importante quando se trabalha com variveis. O ficheiro executvel indica ao compilador como vai carregado no offset 100h (256 bytes), por isso o compilador calcula o endereo correcto para todas as variveis quando repe os nomes das variveis com os offsets. Os directivos nunca so convertidos para o cdigo mquina real. Por que que os ficheiros executveis so carregados no offset com 100h? O sistema operativo mantm alguns dados do programa nos primeiros 256 bytes do CS (Cdigo segmento), tais como linha de comandos, parmetros etc. Embora isto seja verdade s para os ficheiros COM, os ficheiros EXE so carregados no offset em 0000, geralmente so usados segmentos para variveis.

Arrays Arrays podem ser vistos como cadeias de variveis. Uma string de texto pode ser vista como um exemplo de byte array, cada carcter apresentado como um cdigo ASCII (0..255). Aqui ficam alguns exemplos de definies de array: a DB 48h, 65h, 6Ch, 6Ch, 6Fh, 00h b DB 'Hello', 0 b uma cpia exacta do a array, quando compilado v-se uma string dentro de aspas automaticamente converte-a num conjunto de bytes. A figura abaixo mostra uma parte da memria onde estes arrays so declarados:

Pode-se ter acesso ao valor de qualquer elemento do array usando parentesis rectos, por exemplo: MOV AL, a[3] Podemos tambm usar uma qualquer utilizao dos registos da memria ndice BX, SI, DI, BP , por exemplo: MOV SI, 3 MOV AL, a[SI]

Se precisarmos de declarar um array maior , podemos usar o operador DUP. A sintaxe para o DUP : number DUP ( value(s) ) number - nmero de duplicar a fazer (qualquer valor constante). value - DUP expresso que ser duplicado. Para exemplo: c DB 5 DUP(9) uma alternativa a forma de declarar: c DB 9, 9, 9, 9, 9

Podemos usar DW em vez do DB se for necessrio guardar valores maiores de 255 ou mais pequenos que 128. Dw no pode ser usado para declarar strings. OBTER O ENDEREO DA VARIVEL Obtendo o endereo da varivel H uma instruo LEA (Endereo efectivo de carregamento) e um operador alternativo OFFSET. Tanto a instruo OFFSET como a LEA podem ser usadas para obter o endereo da varivel offset. A LEA a melhor, pois permite que o utilizador obtenha o endereo de uma varivel indexada. Obter o endereo da varivel pode ser muito til nalgumas situaes, por exemplo, quando o utilizador precisa de passar parmetros para um procedimento.

Temos de informar ao compilador o tipo de dados, os seguintes prefixos devem ser utilizados: BYTE PTR por byte. WORD PTR - por palavra (dois bytes). Por exemplo: BYTE PTR [BX] ; Byte. ou WORD PTR [BX] ; palavra.

Prefixos mais curtos: b. - para BYTE PTR w. - para WORD PTR O assembler poder s vezes calcular o tipo de dados automaticamente.

Exemplo

Exempo, que usa o OFFSET em vez do LEA:

Os exemplos tema a mesma finalidade

Estas linhas: LEA BX, var1 MOV BX, OFFSET var1 So ainda compiladas no mesmo cdigo mquina: MOV BX, num num um valor de 16 bits da varivel offset. Por favor note que estes registos s podem ser utilizados dentro de parnteses (como a memria dos ponteiros): BX, SI, DI, BP!

Constantes As constantes so como as variveis, mas existem apenas at o programa estar compilado (assembler). Depois da definio da constante o seu valor no pode ser mudado. Para definir a constante EQU utilizado o directrio: name EQU < any expression > similar a MOV AX , 5

Podemos ver as variveis enquanto o programa executado, atravs do menu View, seleccionando variables.

A varivel pode ser vista em qualquer sistema de numerao: . HEX hexadecimal (base 16) . BIN binrio (base 2) . OCT octal (base 8) . SIGNED decimal designado (base 10) . UNSIGNED decimal indefinido . CHAR Carcter ACII (existem 256 smbolos, alguns so invisveis).

possvel por nmeros em qualquer sistema, nmeros hexadecimais devem ter o sufixo h, binrio sufixo b e octadecimal sufixo o. Os nmeros decimais no requerem sufixo. A string pode ser posta desta maneira: Hello world ,0 ( esta string termina em zero). Os Arrays podem ser postos desta maneira: 1,2,3,4,5 (o array pode ser array de bytes ou word, dependendo num entanto se a varivel seleccionada for BYTE ou WORD. As expresses so automaticamente convertidas, por exemplo: 5+2 (isto vai ser convertido para 7).

Os interruptores podem ser vistos como uma srie de funes. Estas funes tornam a programao muito mais fcil pois, em vez de escrever um cdigo para imprimir um caracter que se pode ligar a um interruptor, este que vai fazer tudo. Tambm, existem interruptores que trabalham com funes com o disco rgido e outros hardware. A estas funes chamamos de interruptores de software. Os interruptores tambm so desencadeados por diferentes tipos de hardware, a estes so chamados de interruptores de hardware. Para fazer com que haja um interruptor de software numa instruo INT, tem a seguinte sintaxe:

INT valor Sempre que um valor seja, um nmero entre 0 a 255 (ou 0 para 0FF/h), geralmente, utiliza-se nmeros hexadecimais.

Pode-se pensar que existem apenas 256 funes, mas no correcto. Cada interrupo pode ter vrias sub-funes. Para especificar uma funo de registo sub-AH, deve-se chamar o interruptor, antes de ser definido. Cada interrupo pode ter at 256 sub-funes (por isso, ficamos com 256 * 256 = 65536 funes). Em geral utilizado o AH, mas s vezes usamse outros registos. Geralmente, os outros registos so usados para passar parmetros de dados e para a sub-funo. O exemplo seguinte usa INT 10h sub-tipo de funo 0Eh uma mensagem do tipo "Ol!". Quando necessrio, esta funo exibe uma personagem, que promove o cursor e o deslocamento no ecr.

Para tornar a programao mais fcil, h algumas funes comuns que podem ser includas no programa. Para o programa usar funes definidas noutro arquivo deve-se usar a directiva INCLUDE seguida por um nome de arquivo. O compilador pesquisa automaticamente para o arquivo na mesma pasta onde est localizado o arquivo de origem, e se no encontrar o arquivo - procura na pasta Inc. Para utilizar qualquer das funes em emu8086.inc deve-se ter a seguinte linha no incio do seu arquivo de origem: inclued 'emu8086.inc " emu8086.inc define as seguintes macros: PUTC char - macro com 1 parmetro, imprime uma sada em caracteres ASCII com a posio actual do cursor. GOTOXY col, linha - macro com 2 parmetros, define a posio do cursor. PRINT string - macro com 1 parmetro, imprime a uma string. PRINTN string - macro com 1 parmetro, imprime uma string. O mesmo que PRINT mas adiciona automaticamente "carriage return" no fim da string. CURSOROFF - desactiva o cursor de texto. CURSORON activa o cursor de texto.

Para usar qualquer uma das macros acima basta digitar o seu nome nalgum lugar do seu cdigo e, se necessrio parmetros, como por exemplo: Quando o compilador processar o cdigo fonte vai pesquisar o arquivo emu8086.inc para as declaraes dos macros e substitui os nomes da macro com o cdigo real. Geralmente as macros so relativamente pequenas partes de cdigo. O uso frequente de uma macro, pode tornar o executvel demasiado grande (os procedimentos so melhores para a optimizao do tamanho).

Procedimentos O emu8086.inc tambm define os seguintes procedimentos: Para usar qualquer um dos procedimentos abaixo mencionados deve-se primeiro declarar a funo no final do seu arquivo (mas antes do fim da instruo) e, em seguida, usar a instruo CALL seguida pelo nome do procedimento. Por exemplo:

Primeiro o compilador processa as declaraes (estas vo apenas regular as macros que so expandidas para procedimentos). Quando o compilador chega instruo CALL substitui o nome com o endereo do cdigo onde o procedimento declarado. Quando a instruo CALL executada o controlo transferido para o procedimento. Isto bastante til, uma vez que mesmo que voc chame o mesmo procedimento 100 vezes o seu cdigo, voc ainda tem um executvel com um tamanho bastante pequeno.

PRINT_STRING - procedimento para imprimir uma string nula arquivada pela posio actual do cursor, recebe o endereo da string no registo DS: SI. Para us-lo, declarar: DEFINE_PRINT_STRING antes da instruo END. PTHIS - procedimento para imprimir uma string nula arquivado cursor na posio actual (tal como PRINT_STRING), mas recebe o endereo da string de pilha. A string ZERO TERMINATED deve ser definida logo aps a instruo CALL. Por exemplo: CONVITE PTHIS db 'Ol Mundo! ", 0 Para us-lo declarar: DEFINE_PTHIS antes da instruo END. GET_STRING - procedimento para obter uma string nula obtido a partir de um utilizador, a string recebida escrita para o Buffer DS: DI, o tamanho do Buffer deve ser no DX. O processo pra quando a entrada "Enter" pressionada. Para us-lo, declarar: DEFINE_GET_STRING antes da instruo END.

CLEAR_SCREEN - procedimento para limpar o ecr, (feito percorrendo toda a janela do ecr), e definir o cursor para o topo dele. Para us-lo, declarar: DEFINE_CLEAR_SCREEN antes da instruo END. SCAN_NUM - procedimento que recebe o multi-dgito, o nmero obtido a partir do teclado, e armazena o resultado no registo CX. Para us-lo, declarar: DEFINE_SCAN_NUM antes da instruo END. PRINT_NUM - procedimento que imprime um nmero designado no registo AX. Para us-lo, declarar: DEFINE_PRINT_NUM e DEFINE_PRINT_NUM_UNS antes da instruo END. PRINT_NUM_UNS - procedimento que imprime um nmero no registado no registo AX. Para us-lo, declarar: DEFINE_PRINT_NUM_UNS antes da instruo END.

EMU8086

You might also like