Tutorial 8086 Parte

Propaganda
Tutorial do assembler 8086 para principiantes (parte 3)
Variáveis
Variável é um local na memória. Para o programador é muito mais fácil ter um
valor armazenado em uma variável chamada "var1" do que em um endereço
5A73:235B, especialmente quando se tem 10 variáveis ou mais.
Nosso compilador suporta dois tipos de variáveis: BYTE e WORD.
Sintaxe para a declaração de variáveis:
nome DB valor
nome DW valor
DB - representa Define Byte.
DW - representa Define Word.
nome – pode conter qualquer letra ou números, porém deve iniciar com uma letra. É possível
declarar variáveis sem especificar um nome na declaração (essa variável terá um endereço mas não
terá nome).
valor – deverá conter somente números em qualquer sistema numérico suportado (hexadecimal,
binário, ou decimal), ou o símbolo "?" para variáveis não inicializadas.
Como você provavelmente já conhece da parte 2 deste tutorial, a instrução
MOV é usada para copiar valores de uma origem para um destino.
Vamos ver outro exemplo com a instrução MOV:
ORG 100h
MOV AL, var1
MOV BX, var2
RET
; encerra o programa.
VAR1 DB 7
var2 DW 1234h
Copie o código acima e cole no editor de códigos, e tecle F5 para compilar e
carregar o programa no emulador. Você deverá ver algo como:
Como você pode ver isso parece muito com o nosso exemplo, exceto que as
variáveis são substituídas pelo seu endereço real na memória. Quando o
compilador gera o código de máquina, ele substitui todos os nomes de variáveis
pelos seus offsets. Por padrão o segmento é carregado no registro DS (Quando
arquivos COM são carregados é atribuído ao valor do registro DS o mesmo
valor do registro CS - code segment).
Na listagem de memória a primeira coluna é o offset, a segunda coluna é o
valor hexadecimal, a terceira coluna é o valor decimal, e a ultima coluna é o
valor ASCII representado por um caractere.
O compilador não é case sensitive (diferenciar maiúsculas de minúsculas), logo
"VAR1" e "var1" referem-se a mesma variável.
O offset de VAR1 é 0108h, e o endereço completo é 0B56:0108.
O offset de var2 é 0109h, e o endereço completo é 0B56:0109, Essa variável
é uma WORD logo ocupa 2 BYTES. É assumido que a parte mais baixa é
armazenada no endereço mais baixo, então 34h é localizado antes de 12h.
Como você pode ver existem algumas instruções depois da instrução RET, Isso
acontece por que o disassembler não tem idéia de onde começam os dados, ele
apenas processa os valores na memória e entende como instruções 8086
válidas (nós aprenderemos sobre elas mais tarde).
Você pode até escrever o mesmo programa usando somente diretivas DB:
ORG 100h
DB 0A0h
DB 08h
DB 01h
DB
DB
DB
DB
8Bh
1Eh
09h
01h
DB 0C3h
DB 7
DB 34h
DB 12h
Copie o código acima para o editor de códigos, e tecle F5 para compilar e
carregar o programa no emulador. Você deverá ver o mesmo código
desmontado (disassembled), e a mesma funcionalidade!
Como você deve estar imaginando, o compilador apenas converte o código
fonte em uma série de bytes, que é chamado de código de máquina, o
processador entende o código de máquina e o executa.
ORG 100h é uma diretiva do compilador (ela diz ao compilador como ele deve
manejar o código fonte). Essa diretiva é muito importante quando trabalhamos
com variáveis. Ela diz ao compilador que o arquivo executável será carregado
no offset 100h (256 bytes), então o compilador irá calcular corretamente o
endereço para todas as variáveis quando substituir seus nomes por seus
offsets. As diretivas nunca são convertidas para nenhum código de máquina
real.
Por que os arquivos executáveis são carregados no offset 100h? O sistema
operacional mantém algumas informações sobre o programa nos primeiros 256
bytes do CS (code segment), tais como parâmetros informados na linha de
comando e etc.
Mas isso só é verdadeiro para arquivo COM, Arquivos EXE são carregados no
offset 0000, e geralmente usam segmentos especiais para variáveis. Talvez
nós falaremos mais sobre arquivos EXE mais tarde.
Arrays (vetores)
Arrays podem ser vistos como correntes de variáveis. Uma string de texto é um
exemplo de array de bytes, cada caractere é representado por seu valor ASCII
(0..255).
Aqui estão alguns exemplos de definição de arrays:
a DB 48h, 65h, 6Ch, 6Ch, 6Fh, 00h
b DB 'Hello', 0
b é uma cópia exata do array a, quando o compilador vê a string entre aspas
ele automaticamente a converte para um conjunto de bytes. A tabela abaixo
mostra a parte da memória onde esses arrays estão declarados:
Você pode acessar o valor de qualquer elemento no array usando colchetes, por
exemplo:
MOV AL, a[3]
Você também pode usar qualquer registro de índice de memória BX, SI, DI,
BP, por exemplo:
MOV SI, 3
MOV AL, a[SI]
Se você precisar declarar um array grande, você pode usar o operador DUP.
Sintaxe para o operador DUP:
numero DUP ( valor(es) )
numero – quantidade de replicações (duplicate) a fazer (qualquer valor
constante).
valor – expressão que o DUP vai duplicar.
por exemplo:
c DB 5 DUP(9)
É uma maneira alternativa de declarar:
c DB 9, 9, 9, 9, 9
outro exemplo:
d DB 5 DUP(1, 2)
É uma maneira alternativa de declarar:
d DB 1, 2, 1, 2, 1, 2, 1, 2, 1, 2
Logicamente você pode usar DW em vez de DB se for preciso armazenar
valores maiores que 255, ou menores que -128. O DW não pode ser usado
para declarar strings.
Obtendo o Endereço de Uma Variável
A instrução LEA (Load Effective Address ou carregar o endereço real) e o
operador alternativo OFFSET. Ambos, OFFSET e LEA, podem ser usados para
carregar o endereço offset de uma variável.
A instrução LEA é mais poderosa por que permite que você obtenha o endereço
de variáveis indexadas. Obter o endereço de uma variável pode ser muito útil
em algumas situações, por exemplo quando você precisa passar parâmetros
para uma procedure.
Lembrete:
Para informar ao compilador qual o tipo de dados, os seguintes prefixos devem ser usados:
BYTE PTR - para byte.
WORD PTR - para word (dois bytes).
Por exemplo:
BYTE PTR [BX] ; acesso à byte.
ou
WORD PTR [BX] ; acesso à word.
O assembler também suporta abreviações dos prefixos:
b. - para BYTE PTR
w. - para WORD PTR
em certos casos o assembler pode calcular o tipo de dados automaticamente.
Aqui está o primeiro exemplo:
ORG 100h
MOV
AL, VAR1
; checa o valor de VAR1 copiando-o para AL.
LEA
BX, VAR1
; guarda o endereço da variável VAR1 em BX.
MOV
BYTE PTR [BX], 44h
; modifica o conteúdo de VAR1.
MOV
AL, VAR1
; checa o valor de VAR1 copiando-o para AL.
RET
VAR1
DB
22h
END
Aqui está outro exemplo, que usa OFFSET em vez de LEA:
ORG 100h
MOV
AL, VAR1
; checa o valor de VAR1 copiando-o para AL.
MOV
BX, OFFSET VAR1
; guarda o endereço da variável VAR1 em BX.
MOV
BYTE PTR [BX], 44h
; modifica o conteúdo de VAR1.
MOV
AL, VAR1
; checa o valor de VAR1 copiando-o para AL.
RET
VAR1
DB
22h
END
Ambos os exemplos têm a mesma funcionalidade.
As linhas:
LEA BX, VAR1
MOV BX, OFFSET VAR1
são até mesmo compiladas em um mesmo código de máquina: MOV BX, num
num é um valor de uma variável offset de 16 bits.
Note que você só pode usar colchetes (como ponteiro de memória) para os
registros: BX, SI, DI, BP!
(veja a parte anterior do tutorial).
Constantes
Constantes são como variáveis, porém elas só existem até que o programa seja
compilado (assembled). Após a definição de uma constante o seu valor não
pode ser modificado. Para definir uma constante a diretiva EQU é usada:
nome EQU < qualquer expressão >
Por exemplo:
k EQU 5
MOV AX, k
O exemplo acima é funcionalmente idêntico ao código:
MOV AX, 5
Voce pode visualizar as variáveis enquanto seu programa é executado
selecionando "Variables" no menu "View" do emulador.
Para vizualizar arrays você deve clicar sobre a variável e selecionar a
propriedade Elements para o tamanho do array (array size). Na linguagem
assembly não existem tipos restritos de dados, então qualquer variável pode
ser apresentada como um array.
As variáveis podem ser visualizadas em qualquer um dos seguintes sistemas
numéricos:






HEX - hexadecimal (base 16).
BIN - binario (base 2).
OCT - octal (base 8).
SIGNED - decimal com sinal (base 10).
UNSIGNED - decimal sem sinal (base 10).
CHAR – caractere ASCII (existem 256 símbolos, alguns símbolos são
invisíveis).
Você pode editar o valor de uma variável em tempo de execução, é só dar um
duplo clique na variável, ou selecionar e clicar no botão Edit.
É possível digitar os números em qualquer sistema de numeração, números
hexadecimais devem ter o sufixo "h", binários o sufixo "b", octal o sufixo "o",
os números decimais não precisam de sufixo. Strings podem ser digitadas desta
maneira:
'hello world', 0
(esta string é terminada com um zero).
Arrays devem ser digitados desta maneira:
1, 2, 3, 4, 5
(O array pode ser um array de bytes ou words, vai depender se a variável
selecionada para edição é do tipo BYTE ou WORD).
Expressões são automaticamente convertidas, por exemplo:
quando esta expressão é digitada:
5+2
vai ser convertida para 7 e etc.
Download