Você está na página 1de 109

Machine Translated by Google

CAPÍTULO I INTRODUÇÃO

1.1 Por que programar em Assembler?

Na programação de computadores existe um axioma:

“Primeiro faça um programa funcionar bem e depois faça-o funcionar mais rápido”

E se eu não conseguir tornar meu programa mais rápido? Então só há uma solução: codificá-lo em
linguagem Assembly. Um programa escrito em linguagem Assembly requer consideravelmente menos
memória e tempo de execução do que um programa escrito em linguagem de alto nível.

h
Porém, a linguagem Assembly tem uma grande desvantagem: é difícil de aprender porque, assim
como a linguagem C++, utiliza ponteiros, ou seja, endereços para memória, e também requer muito
código, o que se traduz em realizar mais trabalho do que o normal em comparação com para
linguagens de alta velocidade e, portanto, consome mais tempo de programação.

Para os cientistas da computação a produtividade sempre foi muito importante, os sistemas de


informação têm que ser desenvolvidos no menor tempo possível, e isso fez com que as linguagens
evoluíssem das linguagens de máquina, passando pela linguagem Assembly, para continuarem com
linguagens de alto nível, até atualmente alcançando linguagens visuais e orientadas a objetos,
chamadas de quinta geração.

No início da computação nas décadas de 50 e 60, a programação começou em linguagem de máquina,


ou seja, com 1’s e 0’s; A programação continuou em linguagem Assembly, que substituiu os números
binários pelos mnemônicos, que são as instruções do Assembler, e nessa busca incessante de
aumentar a produtividade dos programadores surgiram linguagens de alto nível, entre elas a linguagem
C, que evoluiu até chegou ao C++, que deslocou Pascal, e atualmente se tornou a linguagem
acadêmica nas universidades; É a linguagem que muda mais rápido, por isso dotaram-na de
capacidades para trabalhar ao nível mais baixo e também ao mais alto possível, e os seus designers
tornaram o seu código muito rápido e eficiente; Praticamente substituiu em grande medida a linguagem
Assembly.

Recentemente, muitos produtos se vangloriaram de dizer “feito inteiramente em linguagem Assembly”


para mostrar sua qualidade. Com o surgimento da linguagem C++, podemos afirmar que quase todos
os sistemas operacionais, protocolos de rede, utilitários de sistema, compiladores de linguagem, etc.,
são construídos utilizando a linguagem C++.

Porém, sempre há módulos que, apesar de serem feitos em C++, ainda são lentos.
É aí que entra a linguagem Assembly. Portanto, o binômio: “C++ & Assembler” é insubstituível, é a
ferramenta mais poderosa que existe para programar o computador.

Devido ao seu código eficiente, a maioria dos livros Assembly afirmam que a linguagem
Assembler é aprendido pelos seguintes motivos:

1. Aprenda com maior profundidade o funcionamento básico da máquina.


2. Ganhe velocidade na execução de programas.

1
Machine Translated by Google

3. Ter acesso a capacidades de máquina que são inacessíveis a outras pessoas


expressões idiomáticas.

4. Compreender melhor como funciona uma linguagem de alto nível.


5. Use as possibilidades da máquina a partir das próprias linguagens de alto nível com
interface dessas linguagens com o Assembler.

Contudo, para os cientistas da computação, há outra razão muito poderosa para aprender a programar em linguagem
Assembly: esta linguagem é formativa. Nenhuma linguagem de programação, com exceção do Assembler, mostra
ao programador como o computador funciona internamente; Esta é uma máquina estática, que se torna uma caixa
preta na qual são inseridos os dados para obter resultados. Como se faz?. Por se tratar de uma máquina que não
se move, seu funcionamento aparentemente é um mistério.

Assembler é a única linguagem de programação que não possui bibliotecas, e se não as possui não há outra saída:
é preciso construí-las; Porque sem bibliotecas programar em Assembly é muito tedioso, exige escrever muito código,
e isso desestimula qualquer pessoa a continuar programando nesta linguagem. O esforço para construir essas
bibliotecas é muito grande, e só conseguirá quem atingir níveis avançados de programação em Assembler, cuja
curva de aprendizado tem uma inclinação muito acentuada.

A atividade de programação, seja qual for a linguagem escolhida, é em geral uma arte. Porém, quando se
trata de montador torna-se uma arte de mestre. Quando você passa a entender a filosofia de como o processador
funciona internamente, essa linguagem que a princípio parece complicada e difícil se torna simples, clara, pura e vai
direto ao ponto. É como encontrar conscientemente as respostas para as seguintes perguntas:

1. Qual é o objetivo?
2. Como faço para atingir a meta?
3. Como posso otimizar o que consegui?

Vamos pesar um pouco o que foi dito acima seguindo uma lógica sequencial, em que cada passo depende do
anterior. Finalmente, das três etapas, a mais difícil é a terceira e, em alguns casos, é aí que a linguagem assembly
entra em cena.

1.1.1. COMPUTADORES E PROGRAMAS

O COMPUTADOR É UMA MÁQUINA MARAVILHOSA?

O homem moderno tem a ideia de que as máquinas reduzem parte do seu trabalho. Isto é realmente verdade porque
o propósito geral das máquinas é mover ou transformar objetos físicos. O uso intensivo de máquinas provocou um
avanço insuspeitado em nossa civilização, por isso falamos da Era Industrial, que corresponde à fase em que o
homem intensificou o uso de máquinas.

A partir do século XVIII, a revolução industrial gerou uma mudança nos sistemas de produção e introduziu um novo
sistema de produção utilizando máquinas movidas por uma nova força: o vapor. Até então as peças eram
confeccionadas manualmente por artesãos em oficinas. Dessa revolução surgiu o mundo industrial moderno e
nasceu

2
Machine Translated by Google

uma nova classe: o trabalhador industrial, que trabalha nas fábricas sob condições novas e
difíceis.

Inventaram-se máquinas com procedimentos mecânicos, surgiram novos métodos de produção,


conseguindo assim fabricar maior quantidade de itens, com menor preço e com maior rapidez.
Hoje isso é feito de forma automática quase sem intervenção humana e o que se busca acima
de tudo é a qualidade do que se produz.

Na década de 1950, o homem inventou outros tipos de máquinas, que não realizavam trabalho
físico, mas tinham a capacidade de processar informações; Estas máquinas provaram ser tão
importantes que a era atual é chamada de Era da Informação. Essas máquinas são chamadas
de computadores ou computadores.

O computador, como já referimos anteriormente, é uma máquina que não realiza qualquer
trabalho físico, mas que no entanto contribuiu para a criação de novos paradigmas em todo o
empreendimento humano, deslocando o ponto central dos recursos de capital para os recursos
humanos e de informação.

Os computadores conseguiram moldar um novo paradigma na situação geopolítica do


mundo, o que por sua vez gerou um novo paradigma no ambiente de negócios internacional.

Os computadores e as redes de computadores alcançaram a ascensão da nova empresa


aberta e interconectada que constitui um novo paradigma organizacional.

1.2. HOMEM E COMPUTADOR SÃO MÁQUINAS DE PROCESSO


DE DADOS

Cada processo de informação tem como objetivo a transformação de dados; Isto é válido
independentemente de o processamento da informação ser manual através de uma pessoa
competente ou automático quando uma máquina é utilizada.

Existem apenas duas máquinas que processam informações, o homem e as máquinas que o
homem inventou para processar informações.

Estes dados
Dados homem ou eles devem ter um
máquina Dados valor específico
de entrada de saída para o usuário

O processamento automático de informações é realizado com a ajuda de máquinas de


processamento de informações. Um exemplo difundido de máquina de processamento de
informações é a calculadora de bolso, onde os dados de entrada são fornecidos através de
um teclado e os dados de saída são retornados por meio de um display de diodo emissor de
luz ou em formato impresso. As calculadoras de bolso geralmente possuem dispositivos para
armazenar internamente uma ou mais constantes. Os dados de saída resultam, neste caso,
de um processo do qual participam dados de entrada e dados armazenados internamente.

3
Machine Translated by Google

Junto com as calculadoras de bolso, existem muitos outros tipos de máquinas de processamento de
informações. Como exemplos temos:

• a máquina de Turing
• a Matriz de Aprendizagem
• o Perceptron
• Computador Analógico
• o Analisador Diferencial Digital
• Um caso especial adicional é o computador digital ou computador, que em um conceito
mais amplo é designado como Sistema de Processamento de Dados.

Comparados a outros tipos de máquinas de processamento de informações, os computadores digitais


são muito mais eficientes. A parte predominante do processamento automático de informações hoje é
realizada por computadores digitais.

1.3. DO PONTO DE VISTA DE UM PROGRAMADOR QUE PODE


FAZER UM COMPUTADOR DIGITAL?

Os computadores recebem muitas propriedades poderosas e surpreendentes. Tudo o que eles fazem é
receber dados, chamados dados de entrada, e produzir dados de saída que tenham valor maior que os
dados de entrada. A partir desses dados de saída, o homem moderno toma decisões que de alguma
forma podem contribuir para a movimentação ou modificação de objetos físicos.

Porém, o computador só funciona com programas e é o homem quem faz esses programas. O
computador sem programas não é nada, seria um monte de ferro inútil.

E do ponto de vista de um programador, todos os computadores, sejam eles grandes ou pequenos, são
simples coleções de componentes eletrônicos que possuem sete capacidades básicas:

Primeiro: Armazene os dados em um meio físico, que chamaremos de memória principal

Segundo: Faça aritmética simples: adição, subtração, multiplicação e divisão

Terceiro: entrada e saída de dados; Sem esses dois processos essas máquinas não teriam muita
utilidade, certo?

Quarto: Capacidade armazenada do programa ; Para executar um programa você precisa


ser carregado inteiramente na memória principal.
Quinto: Tomar decisões simples , como consequência da comparação de dois números

Sexto: Persistência dos dados, em um segundo meio físico, denominado arquivo ou


memória secundária

Setima: Reutilizar, um conceito que explicaremos mais tarde

4
Machine Translated by Google

1.4. Por que usamos computadores?

Como todos os computadores possuem apenas estas sete capacidades básicas e elementares: a capacidade de
armazenar dados na memória, fazer aritmética simples, tomar decisões triviais, armazenar um programa na
memória para executá-lo, realizar entrada/saída de dados, armazenar e acessar grandes quantidades de dados
em armazenamento secundário, e reaproveitamento, então, se pensarmos um pouco, percebemos que o
homem também possui essas capacidades básicas, é natural perguntar o seguinte:

Por que usamos computadores? A resposta é esta: talvez haja três boas razões para usar essas máquinas,
apesar de suas capacidades limitadas:

1.-) NÓS OS USAMOS POR SUA VELOCIDADE

Os computadores são capazes de executar essas sete capacidades básicas


(armazenamento de dados na memória, aritmética simples, tomada de decisões simples,
carregamento de programas na memória, operações de entrada/saída, armazenamento
e acesso a grandes quantidades de informações e reutilização) a velocidades tremendas.
Para avaliar isso, digamos que o número de adições que o computador executa em um
segundo provavelmente exigiria que uma pessoa trabalhasse 40 horas por semana
durante cerca de vinte anos.
PARA
As velocidades para realizar outros tipos de operações aritméticas e tomar decisões

eu
simples são comparáveis às indicadas para adição. No entanto, as operações de entrada/
PARA saída que envolvem movimentos de componentes mecânicos de máquinas, como
impressoras ou discos rígidos, são muito mais lentas. Em um sistema de computador
M
PARA
típico com uma impressora de alta velocidade, podem ser impressas milhares de linhas
P por minuto, e em uma impressora conectada a um PC, cerca de 300 caracteres por
OU
segundo.
Ei
Ei

N N
PARA
h
2.-) NÓS OS USAMOS POR SUA PRECISÃO E CONFIABILIDADE
E
R
E Os computadores são precisos e confiáveis. Tudo o que fazem, fazem-no em alta
N velocidade e sem cometer erros. Por serem máquinas feitas por homens, ocasionalmente
T
podem quebrar e ter que ser consertadas.
E
Sim
Quando um erro é cometido em um processo de computador, é sempre culpa do homem.

3.-) NÓS OS USAMOS POR CAUSA DA CAPACIDADE DO HOMEM DE DECOMPOR


UM GRANDE PROBLEMA EM UM CONJUNTO DE PEQUENOS PROBLEMAS

PARA

eu

A razão mais importante para o uso de computadores é dada pelo fato de que o homem
h
pode resolver muitos problemas usando programas de computador devido à sua
QUALQUER

M capacidade de enfrentar a complexidade, não resolvendo diretamente problemas difíceis,


b mas, pelo contrário, resolvendo de forma equivalente um conjunto de pequenos
R
problemas - um após o outro-; com o esclarecimento de que as soluções para estes
E
pequenos problemas podem ser obtidas utilizando as capacidades limitadas que todos
os computadores possuem.

5
Machine Translated by Google

Como os computadores podem fazer todas essas coisas com precisão e em alta velocidade, a razão
para usá-los é óbvia.

Podemos resumir então que:

O COMPUTADOR É: O HOMEM É:

• Extremamente rápido. • Incrivelmente lento no tratamento de informações.

• Preciso, nunca errado. • Impreciso, propenso a cometer erros.

• Estúpida, ela é uma escrava repetitiva. • Brilhante, porque tem o poder de criar, por isso
é o mestre.

ALÉM DO MAIS:

• O computador trabalha com dados. • O homem trabalha com informação.

• Quando o computador lê, ele transfere. • Quando o homem lê, ele adquire informações e dados de
um meio eletromagnético (disco, tela, etc.) para interpretar um conjunto de dados. A leitura
outro meio eletromagnético chamado memória. É um fenômeno extraordinariamente complexo.

• Quando o computador escreve, ele transfere. • Somente o homem escreve capturando dados da
memória para outro meio de pensamento em uma linguagem.
eletromagnético (disco, tela, etc.)

Ambos constituem um binômio de riqueza incalculável.

Conhecimento é poder e o computador é uma máquina que amplifica esse poder, é um


inovador vital e fecundo. O computador cria valor ao transformar o poder cerebral dos
trabalhadores do conhecimento, com pouco
consumo de energia e de novos materiais.

Estas sete capacidades básicas são tão importantes que a sua compreensão nos mostrará a filosofia
de como um computador digital funciona internamente, e o programador compreenderá como o
computador funciona internamente, por isso as estudaremos detalhadamente no próximo capítulo; mas
para seu completo entendimento estudaremos também a ferramenta que nos ajudará a entender essas
sete capacidades básicas, estamos nos referindo especificamente ao programa debug.exe, que
aprenderemos a usar posteriormente no capítulo II.

Vamos analisar uma por uma as sete capacidades básicas de um computador digital:

6
Machine Translated by Google

1.4.1. PRIMEIRA CAPACIDADE BÁSICA

Cada computador possui circuitos eletrônicos que permitem que os dados sejam armazenados e
recuperados diretamente em sua memória, por meio de expressões chamadas instruções de atribuição.
Que tipos de dados você pode armazenar e recuperar? Apenas dados numéricos binários, compostos
por dígitos 1 e 0. Daí o nome computadores digitais.

Se um programador quiser salvar a letra “A” na memória do computador, ele utiliza o número binário
010000012 ou seu equivalente hexadecimal 4116, ou também 41h – o h significa que está no sistema
hexadecimal – e o nome de uma variável, que é um nome que começa com uma letra, por exemplo X,
e se você usa a linguagem Cobol tem que escrever: mova “ A ” para '; e no montador:

mês X, 41h

que devemos ler “armazena 41h no endereço de memória apontado por X”, ou de forma mais simples
para não falar da memória , armazena 41h em linguagem de máquina, como veremos mais adiante,
nomes de variáveis não podem ser usados, e iremos escrever: mov byte ptr [0000],41

Em que parte da memória está armazenado o valor 41h contendo X? Para o programador de uma
linguagem de alto nível como COBOL ou C, isso não importa, o sistema operacional e o respectivo
compilador se encarregam de verificar em que parte da memória o resultado está armazenado.
Mas na linguagem de baixo nível como Assembler, o programador deve previamente escolher em qual
parte da memória pode armazenar o número hexadecimal 4116.

Expressões do tipo “mov instruções de atribuição.

1.4.2. SEGUNDA CAPACIDADE BÁSICA

Cada computador possui circuitos eletrônicos diferentes da memória e que se encontram na CPU, que
são chamados de registradores e que servem para fazer aritmética. Que tipo de aritmética eles podem
fazer? Os quatro tipos de operações aritméticas: + - * /. Isto é adição, subtração, multiplicação e
divisão.

Além de realizar operações aritméticas, o computador armazena na memória os resultados parciais e


finais obtidos com essas operações e, assim como o homem, necessita armazenar esses dados em
meio físico para poder manipulá-los. É por isso que utiliza determinados recursos eletrônicos chamados
registros. Por exemplo, se quisermos calcular a soma: 3 + 5, usamos um meio registro chamado al ÿo
registro ax contém dois meios registros ah e alÿ
e procedemos assim:

mova al,3 ; al = 3
adicione al,5 ; al = al + 5

Se você quiser calcular 8 – 3, escrevemos:

mov al,8 ; em =8
subal,3 ; al = al-3

7
Machine Translated by Google

*
Se você quiser calcular 8, neste caso você deve usar dois registradores de meio nome al e bl, e
3, escrevemos:

mov al,3 ; al=3


mov bl,8 ; bl=8;
*
mul bl ah:al = 3 8

A instrução mul bl sempre multiplica o valor que está armazenado em al pelo valor que existe em bl
e o resultado é salvo em dois meios registros, que designamos assim: ah:al.

Para dividir 10 por 2, escrevemos o seguinte:

mov ah,0 ; ah=0;


mov al,10 al = 10
mov bl,2 ; bl=2;
div bl al = 8/2=4

A instrução div bl sempre divide o valor que está armazenado em ah:al pelo valor que existe em bl e o
quociente é armazenado em al, e o restante em ah.

1.4.3. TERCEIRA CAPACIDADE BÁSICA

Esta capacidade é chamada de capacidade de interface de entrada/saída e é executada por instruções de


entrada/saída. Cada computador possui um meio de se comunicar com você ou com a pessoa que o utiliza.
Enfim, se não pudéssemos inserir números e obter resultados, essas máquinas não teriam muita utilidade,
certo?

A forma mais comum de fornecer informações ao computador é através do teclado e os dados da resposta
são exibidos na tela. O teclado é usado para ler os dados e salvá-los na memória do computador. Em
contrapartida, a tela serve para exibir os dados encontrados na memória do computador. Tanto o teclado
quanto a tela estão conectados ao computador e são chamados de periféricos de entrada e saída.

Todas as linguagens de programação possuem uma maneira de ler dados do teclado e gravar dados na tela.

A linguagem assembly executa operações de entrada e saída usando chamadas para interrupções do sistema
operacional. A mais conhecida delas é a interrupção denominada int 21h, que possui diversas funções que
são especificadas no valor obtido pelo meio-registro ah. Por exemplo, se ah=1, a interrupção 21h faz com que
o computador leia um caractere ASCII do teclado e o armazene no meio registro al, e se ah=2, a interrupção
21h faz com que o computador escreva na tela o caractere ASCII cujo o valor está em dl.

Vamos ver como isso é feito:

Se quisermos ler o número 4 no teclado e salvá-lo na memória, devemos usar o nome de uma variável, por
exemplo x, que deve ter o mesmo tamanho de al. É assim que escreveremos em linguagem Assembly:

8
Machine Translated by Google

mova ah,1 ; ah=1, função para ler um caractere do teclado


int 21h ; lê o número “4” e o salva no registro intermediário quando
mova x,al ; armazena o caractere “4” na variável x na memória

Se executarmos este código, devemos digitar a chave com o número 4, o número 4 é atribuído a al e depois movido
para x que está na memória.

Se quisermos escrever na tela o número “4”, que já temos armazenado na memória no endereço apontado pela
variável x, escreveremos este outro código:

mov ah,2 ; se prepara para digitar um caractere na tela


movdl,0Ah ; em dl a quebra de linha
interna 21h; pular linha
mov dl,x ; em dl o número “4”
interna 21h; escreva “4” na tela

mov ah,4ch ; se prepara para terminar


int 21h ; encerra o programa e passa o controle para o sistema;
operando DOS

e veremos que o computador escreve o número “4” na tela.

1.4.4. QUARTA CAPACIDADE BÁSICA

Essa capacidade é chamada de capacidade de programa armazenado.

O que é um programa de computador digital?

Um computador digital é uma máquina que explora sequencialmente as informações armazenadas em sua memória,
denominada programa, e as executa seguindo o princípio de Von Neumann. É por isso que os computadores digitais
também são chamados de computadores com programas armazenados , porque para executar um programa
eles precisam carregá-lo inteiramente na memória antes de executá-lo. Esclareçamos este conceito: os computadores
ou sistemas de processamento de dados caracterizam-se pelo processamento digital da informação, bem como pela
diferenciação em instruções (programas) e dados de informação, ambos representados digitalmente no computador.

memória principal.

Todo programa possui dois componentes ou partes: o primeiro componente é o algoritmo e o segundo componente
são os dados. O professor Niklaus Wirth – inventor de Pascal e Modula 2 – intitulou um de seus livros mais famosos:
“Algoritmos + Estruturas de Dados = Programas”.
Mas... O que é um algoritmo? Respondemos: “Um algoritmo é um método para resolver um problema em um
número finito de etapas”. Cada etapa de um algoritmo é chamada de declaração ou instrução.

Um exemplo ilustrativo

A seguir está um programa escrito em linguagem de máquina – usando o programa debug.exe – que escreve a
palavra “algoritmo” na tela

9
Machine Translated by Google

1693:100 mov dx, 109


1693:103 mov ah,9
1693:105 int 21 algoritmo do programa
1693:107 int 20
1693:109 db “algoritmo$” dados

O algoritmo deste programa contém 4 instruções, começa com a instrução: mov dx,109; e termina com a
instrução int 20. A instrução “mov dx,109” está localizada no endereço relativo 100, e a pseudo instrução:
'db “algoritmo” ', está localizada no endereço relativo 109, e declara os dados.

MEMÓRIA sequências de 1 e 0

Ele é carregado na memória Programa

Dados

Programa no disco

Para verificar o funcionamento deste programa, que repetimos está escrito em linguagem de máquina,
linguagem muito semelhante ao Assembler, utilizaremos o programa debug.exe, que está sempre acessível
a partir do DOS. Para entrar no seu ambiente de desenvolvimento, faça o seguinte: Pressione o botão Iniciar
do Windows , no menu pop-up escolha a opção executar, na janela aberta digite cmd e você entrará
imediatamente no modo DOS do Windows. Continue digitando debug e pressione a tecla Enter, momento
em que um traço ÿ aparece, indicando que agora você pode começar a trabalhar com debug.exe. Após o
hífen digite a letra A e pressione a tecla <ENTER>. A letra a representa o comando “Assembler” para poder
inserir linhas de código em linguagem de máquina a partir do teclado; e digite o programa anterior. A seguir,
para executar o programa, digite o comando ÿg (“go”), e você verá a palavra “algoritmo” exibida na tela e na
próxima linha a mensagem “Programa encerrado normalmente”, gerada pelo debug.exe programa.

10
Machine Translated by Google

O Princípio de Von Neumann

O cientista húngaro-americano John Von Neumann concebeu o computador digital como uma
máquina que carregava um programa na memória e o executava instrução por instrução. De acordo
com o princípio de Von Neumann, a execução de cada instrução incluía dois tempos:

Leia as instruções de cor


para onde o registro IP aponta
Tempo de instrução
Decodificando, isso é interpretar
o que cada instrução significa
Instrução
Execute a instrução
Tempo de execução
Salvar resultados na memória

O programa debug.exe é uma ferramenta muito apropriada para verificar como funciona o princípio de
Von Neumann, pois ao contrário do comando –g (go), que executa nosso programa em uma velocidade
tão alta que não nos permite verificar o que está acontecendo em cada instrução, por isso usaremos o
comando –p (proceed), que nos permite executar o programa instrução por instrução, conforme
descrevemos a seguir.

Vamos começar verificando se o programa que digitamos acima está armazenado na memória do
computador. Para fazer isso, digite o comando ÿu (umAssembler, ou seja, desmonte os 1's e 0's,
decodifique e exiba o código) e dê a entrada e você obterá o seguinte:

onze
Machine Translated by Google

Observe como o processador, através do comando –u (unAssembler), permite verificar o tempo de


instrução do princípio de Von Neuman, pois decodifica – mas sem executar – todos os 1’s e 0’s
contidos na memória e mostra o resultado disso. decodificação como instruções em linguagem de
máquina listadas nas colunas três e quatro da figura acima. Da mesma forma, na primeira coluna
aparece o endereço da memória onde cada instrução está armazenada e na segunda coluna o
conteúdo da memória, interpretado não em 1 e 0, mas em seu equivalente hexadecimal. O escopo
das instruções de máquina que você vê na tela vai além do programa que digitamos inicialmente e
cobre, do offset 0100 a 011C. Seriam as instruções que seriam executadas se o programa fosse
executado com o comando –G (Go ). É por isso que um programa em linguagem de máquina deve ter
uma instrução “int 20” para finalizar o programa, caso contrário ele continuaria “decodificando-
executando” todos os 1 e 0 na memória.

1.4.5. QUINTA CAPACIDADE BÁSICA

Os computadores possuem circuitos eletrônicos que podem tomar decisões simples. O tipo de decisão
que os circuitos podem tomar não é do tipo: “Quem vai ganhar o jogo de futebol hoje à noite?” ou
"Qual é a maior cidade do Peru?" Infelizmente, os computadores só podem decidir a verdade ou
falsidade da comparação de dois números, um ou ambos devem ser armazenados não na memória,
mas sim num dos 13 registos, ou também meios registos, que já mencionamos anteriormente, que
são dispositivos que os computadores possuem para armazenar dados numéricos, assim como na
memória, e constituem dispositivos auxiliares muito importantes. Por exemplo, se os meios-registros
ch e cl contêm números, o computador pode saber se alguma das seguintes afirmações é verdadeira
ou falsa:

(1) ch <cl (o número em ch é menor que o número em cl?)


(2) ch ÿ cl (o número em ch é menor ou igual ao número em cl?) (3) ch > cl
(o número em ch é maior que o número em cl?)
(4) ch ÿ cl (o número em ch é maior ou igual ao número em cl?)
(5) ch ÿ cl (o número em ch é diferente do número em cl?)

Se quisermos que quando ch<cl for verdadeiro o valor de ch seja escrito na tela, e que quando ch<cl
for falso seja escrito na tela primeiro o calor de cl e depois o valor de ch, em espanhol, nós deve
especificar o seguinte:

Se ch <cl for verdadeiro então escreva cl na tela


Caso contrário, escreva ch e cl na tela

que traduzido para linguagem Assembly e para ch=”3” e cl=”5”, torna-se

movimento ah,2

mov ch,”5”
movcl,”3”
cmp ch, cl
jl salgo ; “jl” significa pular se for menor
mov dl,ch ; continue com int
21h; estes mov dl,0Ah ;
instruções internas 21h; se for
falso
Eu saio: mov dl,cl
int 21h

12
Machine Translated by Google

Como neste caso ch<cl é falso, ele escreverá primeiro o ASCII “5” na tela e depois o ASCII “3” na próxima linha. Essas instruções que

permitem comparar dois números são chamadas de instruções de controle ou instruções de seleção simples.

Para que mais as comparações são úteis? A resposta é simples: controlar a execução do programa; por exemplo, para garantir que um grupo

de instruções seja repetido um certo número de vezes. Isto será estudado mais adiante em detalhes. Já indicamos que uma vez carregadas
todas as instruções do programa na memória, o computador começa a executar uma instrução por vez, da primeira à última, que deve ser

uma instrução “int 20”. Para isso, o computador dispõe de um dispositivo de armazenamento magnético, denominado registrador IP, que fica

na CPU, fora da memória, cujo conteúdo indica o endereço da memória onde está armazenada a instrução que em breve será executada.

Cada vez que uma instrução é executada, o valor IP é incrementado automaticamente para apontar para a próxima instrução a ser executada.

Por ejemplo el siguiente programa ejecuta 299 instrucciones antes de terminar: (las instrucciones mov ax,1 y int 20h, 1 vez, y las instrucciones

“add ax,1”, “cmp ax,100” y “jl sigo”, 99 veces cada uma)

machado mov,1

Eu continuo: adicione ax,1

cmp machado,100 ; Compare machado com 100

jl eu continuo ; pule se for menor (se ax < 100 for verdadeiro, ramifique para o próximo)
Intervalo 20

1.4.6. SEXTA CAPACIDADE BÁSICA

Esse recurso é chamado de persistência de dados. Na maioria das aplicações, a capacidade dos computadores para armazenar e aceder a

grandes quantidades de informação desempenha o papel dominante e é considerada a sua principal característica; A sua capacidade de

contar ou computar, isto é, calcular e realizar operações aritméticas, tornou-se em muitos casos quase irrelevante.

Para obter persistência, um dispositivo de armazenamento secundário denominado arquivo é usado e não faz parte da memória.

Para entender isso melhor, vamos abstrair o que acabamos de dizer. Vamos imaginar que um arquivo é um retângulo cujo nome é 'DATA.DAT'

que está contido em um disco (veja a figura a seguir) e queremos armazenar o dado numérico 3 no disco, para utilizá-lo posteriormente, então

escrevemos o seguindo instruções em linguagem Assembly:

13
Machine Translated by Google

.modelo pequeno

.dados

arco banco de dados 'a:\DATA.DAT',0


Nhandle dw 0

dados db 33h

dados_leitura banco de dados?

.código

processo principal

mov ax,@data mov ; ler o endereço do segmento de dados


ds,ax mov ; salve este endereço no registro ds
ah,3ch xor cx,cx ; prepare-se para criar o arquivo
lea dx,arch ; cx = 0, deve ter 0 bytes
int 21h mov ; arco aponta para o nome 'a:DATOS.DAT' ; crie o
ah,3dh arquivo

mov al,1 lea ; prepare-se para abrir o arquivo


dx,arch int ; ah=1 significa para escrever
21h mov ; arch aponta para o nome 'a:\DATOS.DAT' ; abra o

arquivo e atribua x a # (handle)


Nhandle,ax mov ; Nhandle = # (número atribuído ao arquivo)
ah,40h mov ; prepare-se para escrever arquivo com #andel em bx
bx,Nhandle mov cx,1 ; identifica o arquivo pelo seu identificador
leitura ; em cx o número de bytes a serem gravados, neste caso 1
dx,dados int ; em dx o endereço de memória onde estão os dados a serem gravados
21h mov ; gravar no arquivo, mover 3 da memória para o disco

ah,3eh mov ; prepare-se para fechar o arquivo com #handle em bx

bx,Nhandle ; identifica o arquivo pelo seu identificador


interna 21h; feche o arquivo

mov ah,4ch ; se prepara para passar o controle para o DOS


interna 21h; termina e passa o controle para o DOS

terminal principal
fim principal

Os dados são movidos da memória

para disco

programa MEMÓRIA

x
DADOS.DAT dados
3
3

Quando as duas últimas instruções são executadas: mov ah, 4ch e int 21h, o programa termina e é descarregado da memória, e portanto

os dados, que são o número 3, que estavam armazenados na memória são perdidos e nunca mais poderemos recuperar isso de novo. .

Mas se carregarmos na memória e executarmos o seguinte programa:

14
Machine Translated by Google

.modelo pequeno

.dados

arco banco de dados 'a:\DATA.DAT',0


lidar com dw 0

dados db 33h

dados_leitura banco de dados?

.código

processo principal

mov machado,@dados ; ler o endereço do segmento de dados


mov ds,ax ; salve o endereço em ds

mov ah,3dh mov ; se prepara para abrir um arquivo apontado por dx


al,0h leitura ; al = 0 significa para leitura; dx aponta
dx,arch int 21h para o nome 'a:\DATOS.DAT', ; abra o arquivo e atribua
movimento em ax (# handle)
Nhandle,ax mov ah,3fh ; Nhandle = # identificador

movimento ; prepare-se para ler o arquivo de #handle em bx


bx,Nhandle movimento ; Identifique o #handle em bx

cx,1 leitura ; bytes para ler 1


dx,data_read int 21h ; dx= endereço de memória onde armazenar os dados que lê; ler arquivo, mover
dados do disco para a memória

mov dl, dados_leitura ; dl = dados lidos do arquivo

movimento ; prepara-se para escrever ASCII dl na tela; escreva ASCII de dl


ah,2 int 21h na tela

mov ah,4ch int ; se prepara para terminar


21h endp ; termina e passa o controle para o DOS

principal
fim principal

O resultado alcançado seria que o dado numérico 3 que está no arquivo A.\DATOS.DAT” seja lido e salvo na memória em data_read, este é

movido para dl e depois exibido na tela do computador, ou seja, desta forma recuperamos o valor do número 3, criado com o primeiro

programa e gravado no arquivo, que de outra forma teria sido perdido para sempre.

MEMÓRIA

programa
e
3

Disco DATA.DAT

os dados são transferidos do disco para a memória

quinze
Machine Translated by Google

1.4.7. SÉTIMA CAPACIDADE BÁSICA

Conceito de reutilização

A maioria dos programas é construída de forma personalizada , em vez de montar componentes


existentes. Considere, como comparação, a forma como o hardware do computador é projetado e
fabricado. O engenheiro de projeto constrói um esquema simples de circuito digital, faz algumas análises
fundamentais para garantir que a função adequada seja executada e acessa o catálogo de vendas dos
componentes digitais existentes. Cada circuito integrado possui um número de peça, uma função definida
e validada, uma interface bem definida e um conjunto padrão de critérios de integração. Após cada
componente ser selecionado, a compra pode ser feita.

Infelizmente, os programadores não têm o luxo descrito acima. Com algumas exceções, não existem
catálogos de componentes de software. É possível encomendar software pronto, mas apenas como uma
unidade completa, e não como componentes que podem ser remontados em novos programas.

Embora muito tenha sido escrito sobre reutilização de software, poucos sucessos tangíveis foram
alcançados até agora, sendo os mais importantes: bibliotecas de miniaplicativos
na programação tradicional, quase obsoletas, e agora por último, as bibliotecas de classes na
programação orientada a objetos e a reutilização do código binário de uma aplicação, que são pedaços
de código reutilizáveis chamados componentes, e a capacidade de usar componentes, para se
comunicarem, é chamada de interoperabilidade. Ou seja, as formas de reaproveitamento existentes
são as seguintes:

Programação tradicional (bibliotecas estáticas de módulos de objetos)

Reutilizar programação de código-fonte (bibliotecas de classes ou componentes)


Orientado para

Objetos código binário de um aplicativo (componentes binários dinâmicos)

A reutilização que descreveremos a seguir é a de bibliotecas de subprogramas, usando um applet


chamado fsqrt, que obtém a raiz quadrada de um número

Um exemplo concreto de reutilização

O computador, como dissemos antes, só pode fazer aritmética simples: somar, subtrair, multiplicar e
dividir.

Se nos depararmos com o problema de calcular a raiz quadrada de um número, como resolveremos o
problema? Muito simples, recorremos à capacidade básica do computador: reutilizar.

A seguir está um programa em linguagem Assembly que calcula a raiz quadrada de qualquer número lido
no teclado, digitado no formato float:

16
Machine Translated by Google

; Programas Ejem07B.asm e Ejem07BCap_Bas7Reutilización.asm


.modelo

pequeno
.386 .dados x dq ? mensa1 db
'Insira um número: $' mensa2 db
'Raiz
quadrada: $' .code extrn

; obtenha a raiz quadrada de x

crlf:near,read_float:near,write_float:near main proc mov ax,@data mov ds,ax read dx,mensa1 mov ah,9

A instrução que usa o recurso de reutilização é fsqrt;. Aqui o nome da variável fsqrt é o nome de uma
função que calcula a raiz quadrada de x. O que estamos fazendo é simplesmente reutilizar um
programa que calcula a função fsqrt (raiz_quadrada em aritmética flutuante), que já foi escrita e
testada anteriormente por outro programador. Não é necessário que nos gastemos escrevendo este
programa, o que temos que fazer é reutilizá-lo. Por que reinventar a roda se ela já existe? É lógico que
possamos desenhar um programa em Assembler ou outra linguagem para calcular a raiz quadrada de
um número flutuante.

Podemos afirmar que programar em Assembler, utilizando bibliotecas de objetos estáticos, é um caso
específico de reutilização. Para programar em Assembler, utilizando essas bibliotecas, existe

17
Machine Translated by Google

Você precisa conhecer instruções de máquina e instruções Assembler, saber como declarar
variáveis, construir expressões, conhecer estruturas de controle e adquirir o

conhecimento fundamental de suas habilidades para controlar a execução de ciclos de


repetição. Consequentemente, o conhecimento da linguagem Assembly é de extrema
importância, pois caso contrário dificilmente conseguiremos escrever algum código, e é isso que
Nosso objetivo com este livro: começar do 0.

18
Machine Translated by Google

CAPÍTULO II O ambiente do programa Debug.exe

2.1 Introdução.

A primeira coisa que temos que fazer é aprender quais são os passos para programar em linguagem
de máquina, que é a linguagem mais próxima do computador, ou seja, o nível mais baixo, em relação
a todas as linguagens de programação que existem e que também são usadas. Ele as chama de
línguas artificiais e são de alto nível porque estão mais próximas das línguas usadas pelo homem,
como espanhol, inglês, etc. que são chamadas de línguas naturais. Começaremos a nos familiarizar
com o ambiente do depurador. Ou seja, utilizaremos o programa chamado debug.exe, ao qual nos
referimos no primeiro capítulo, mas de forma muito superficial. Este programa nos ajudará a montar
e executar nossos primeiros programas. O nome depurador vem de “bug” que é um termo muito
utilizado em inglês para descrever uma falha na sequência de instruções de um programa, que o
impede de funcionar corretamente. Essa falha pode variar desde um erro sintático até um erro lógico.

Portanto, depurar é a ação de corrigir essas falhas, e é um dos muitos usos dados ao debug.exe.

Debug.exe é um utilitário que nos ajuda a realizar três tarefas:

• Visualize o conteúdo das memórias RAM e ROM.


• Executar um programa inteiro ou uma instrução por vez.
• Monte e execute programas dinamicamente.

Usando debug.exe podemos trabalhar imediatamente com instruções de máquina sem ter que
conhecer todos os seus requisitos formais, a fim de realizar seu poder e potencial.

2.1 Elementos iniciais do programa Debug.exe

Você pode iniciar o debug.exe da seguinte maneira:

1. Pressione o botão Iniciar do Windows . No menu pop-up, escolha a opção Executar. Na


janela Abrir , digite debug.exe e pressione o botão OK. O Windows exibe imediatamente
um traço (ÿ) na tela como uma indicação de que o programa debug.exe foi carregado na
memória.

2. Para criar um arquivo ou examinar a memória, digite debug sem especificar um nome de
arquivo: debug <enter>

3. Para modificar ou depurar um programa (.COM ou .EXE) ou para modificar qualquer arquivo
ou, por exemplo, modificar o programa test.com, que está gravado em um disquete, digite
debug com uma especificação de arquivo, como

depurar a:test.com. <entrar>

O DOS carrega o debug.exe na memória e exibe um traço (ÿ) como uma indicação de que é o
programa armazenado na memória.

19
Machine Translated by Google

Abaixo damos uma descrição de cada comando debug, em ordem alfabética, em que “endereço” é um número
de um endereço na memória.

–A (endereço) –Os parênteses indicam que a informação do endereço é obrigatória–

“A” significa Montador. É utilizado para inserir código-fonte em linguagem de máquina muito próxima da
linguagem Assembly, mas que veremos tem muitas limitações, em relação a esta última.

–D (endereço)

“D” significa Dump em inglês – esvaziar ou despejar em espanhol. Significa despejar o conteúdo de uma parte
da memória, exibindo esse conteúdo na tela em notação hexadecimal e/ou símbolos ASCII.

–E (endereço)

“E” significa entrar em inglês ou entrar em espanhol. É usado para inserir dados numéricos na memória em
base hexadecimal, dois dígitos hexadecimais por vez, e pressionar a tecla de espaço para passar para os
próximos dois dados. Os dados inseridos são armazenados no endereço que deve ser inserido após escrever a
letra E.

–G [endereço] –aqui os colchetes indicam que o endereço é opcional–

“G” significa ir em inglês e corre ou ir em espanhol. É usado para executar um programa em linguagem de
máquina que está sendo examinado, até um ponto de interrupção especificado em [endereço], que é opcional.
Se o endereço não for especificado, o programa continua até terminar.

–H (números hexadecimais)

“H” significa Hexadecimal. É usado para mostrar a soma e a diferença de dois números hexadecimais. O
comprimento máximo dos dados é de quatro dígitos hexadecimais.

–N [nome_do_arquivo]

“N” significa nome ou nome em espanhol. Nomeia um programa ou arquivo que você deseja gravar em disco.

–P [endereço] [valor]

“P” significa proceder em inglês ou procedimento em espanhol. Chama uma sub-rotina (call), faz loop, interrompe
(int) ou repete uma cadeia de instruções (REP) para a próxima instrução. O formato geral é: –P [endereço]
[valor], onde “endereço” é um número que fornece o endereço inicial, que é opcional, e valor é o número de
instruções, também opcionais, para prosseguir.

Se o endereço não for especificado, é executada a instrução apontada pelo registro IP, registro que
descreveremos mais adiante.

vinte
Machine Translated by Google

–Q

“Q” significa Sair em inglês. Usado para sair do ambiente de trabalho Debug.exe

–R [nome_do_registro]

“R” significa Registro em inglês ou registro em espanhol. Serve para exibir o conteúdo do registro que aparece
em nome_registro e abre a opção de modificar seu valor. Se [record_name] não for especificado, ele exibe todos
os registros sem opção de alterar seu conteúdo.

–T [endereço][valor]

“T” significa Trace em inglês ou rastreamento em espanhol. Executa um programa no modo de etapa única. A
entrada opcional [address] informa ao debug.exe onde iniciar o rastreamento e o valor opcional informa o número
de instruções a serem rastreadas. A omissão dos operandos faz com que o debug.exe execute a próxima
instrução apontada pelo registro IP.

–U [endereço ou intervalo]

“U” significa Unemsamble em inglês ou desmontar em espanhol. Desmonte as instruções da máquina. O registro
padrão é o par CS:IP. E se o endereço ou intervalo for omitido, ele desmonta 32 bytes do último U se houver um
anterior.

–W [endereço [número da unidade do setor_inicial_de_setores]]

“W” significa escrever em inglês e em espanhol escrever. Grave um arquivo em disco com as características de
nome e tamanho indicadas anteriormente. Caso não sejam utilizados operandos, deve-se primeiro nomear o
arquivo com o comando N, e o número de registros com o comando –R CX, que permite inserir como valor no
registro CX, o número de bytes a serem gravados.

ETAPAS PARA PROGRAMAR EM LINGUAGEM DE MÁQUINA COM DEBUG.EXE

Exemplo 0

O programa a seguir é famoso porque foi o primeiro exemplo que apareceu em 1978 no primeiro livro para
aprender a programar em C, escrito por Kermighan e Ritchie, intitulado “The C
Programming Language”, que trouxe grande atenção para esta linguagem, e que se tornou um dos livros de
ciência da computação de maior sucesso de todos os tempos:

vazio principal()
{ printf(“Olá mundo”);
getch();
}

Vamos escrever este programa em linguagem de máquina seguindo os seguintes passos (trabalhando com
Windows 2000):

vinte e um
Machine Translated by Google

PRIMEIRO PASSO

Esta etapa já foi descrita anteriormente. Começamos pressionando o botão Iniciar do Windows . No
menu pop-up, escolha a opção Executar. Na janela aberta
digite debug.exe e pressione o botão OK. O Windows exibe imediatamente um traço (ÿ) na tela como
uma indicação de que o programa debug.exe foi carregado na memória.

SEGUNDO PASSO

À direita do hífen, digite a letra A e pressione a tecla Enter. Em seguida, digite o seguinte código, uma
instrução por linha seguida de um enter para ir para a próxima linha:

–A <enter>
mov dx,109 <enter>
mov ah,9 <enter> int o $ significa fim da string
21 <enter> int 20
<enter>
db “Olá mundo, do Assembler!$” <enter>
<entrar>

O último <enter> é usado para sair do modo A (Assembler), que só é usado para inserir ou modificar o
código-fonte.

TERCEIRO PASSO

Verifique se o código inserido é idêntico ao listado acima. Não se esqueça do símbolo $ na última
instrução, antes das aspas duplas.

Para executar o programa, digite –G (Go) e o programa será executado sem problemas, desde que você
não tenha cometido nenhum erro ao inserir o código.

O resultado será o seguinte: A mensagem aparecerá na tela:

Olá mundo, da Assembler!

E então uma mensagem do DOS, indicando que o programa funcionou normalmente:


“Programa encerrado normalmente”

QUARTO PASSO

Prosseguimos dando um nome ao programa e salvando-o no disco, executando o seguinte:

Digite –N Ejem00.com <enter>, sendo “Ejem00.com” o nome que escolhemos para o programa que está
na memória.

Vamos estabelecer o tamanho em bytes que o arquivo terá no disco. Como o deslocamento vai de cs:100
a cs:012B, adicionamos 1 à diferença de 012B menos 0100 e obtemos 2C bytes (= 012B - 0100 + 1) de
comprimento do programa. No sistema decimal isso equivale a 2*16+12 = 44 bytes. Portanto esse
tamanho é salvo no registrador cx. É por isso que usamos o comando ÿR CX <enter> e depois inserimos
o valor calculado 2C e damos <enter>.

Em seguida, gravamos o programa testing.com no disco, digitando –W sem nenhum operador.


O DOS com a mensagem “Writing 0002C” nos avisa que gravou o arquivo no disco.

22
Machine Translated by Google

QUINTO PASSO

Podemos verificar o programa que está armazenado na memória usando o comando:


–U (Desmontador). Mas para que não apareça mais informação do que a necessária, digitamos: –U
100 109, que inclui o código que vai do deslocamento 100 até
109, como pode ser visto na tela a seguir:

SEXTO PASSO

Para sair, digite –Q (sair) e retorne ao painel principal do Windows.

Executando o programa Ejem00.com no DOS

Se quisermos executar novamente o programa Ejem00.com, mas agora a partir do DOS, sem recorrer
ao debug.exe, procedemos da seguinte forma:

PRIMEIRO PASSO

Pressione o botão Iniciar do Windows . No menu pop-up, escolha a opção Executar.


Na janela Abrir , digite cmd e pressione o botão OK. O Windows exibe imediatamente a tela do
sistema operacional DOS.

SEGUNDO PASSO

Vamos verificar se o programa testing.com está no disco rígido digitando:

dir Ejem00.com,

Se este programa estiver em disco, mostra seu nome, tamanho e data de criação. Caso não seja
encontrado, será exibida uma mensagem de erro e será necessário reexecutar todo o procedimento
descrito.

23
Machine Translated by Google

TERCEIRO PASSO

Para executar o programa Ejem0.com digite apenas o nome Ejem00, não é necessário utilizar a
extensão .com . O programa então exibe a mensagem na tela:

Olá mundo, da Assembler!

A tela a seguir mostra o resultado da execução do programa Ejem0.com:

NOTAÇÃO DE VISÃO

Depois de escrevermos vários programas Ejem00.com, Ejem01.com, . . . , Ejem12.com, . . . ,


Ejem26.asm, ..., etc., no caso particular de um deles, por exemplo, o nome Ejem00.com, do programa
que acabamos de criar com debug.exe, não nos diz nada sobre o que faz .o programa, e isso pode
causar confusão. Para evitar isso, recorremos à facilidade que o Windows nos oferece, que nos
permite utilizar nomes de até 255 caracteres, utilizando a chamada notação de serra, em referência
aos dentes de uma serra, que consiste em escrever o nome de um arquivo, iniciando cada palavra
no nome do arquivo com uma letra maiúscula. Desta forma manteremos dois nomes para cada
programa: o primeiro nome – que é permitido pelo DOS –, com no máximo 8 caracteres para o nome
e 3 caracteres para a extensão, e o segundo nome – que é permitido pelo Windows – , com notação
de serra, para nos lembrar o que o programa faz. Assim, por exemplo, no caso do programa
“Ejem00.com” manteremos este nome e este outro em notação de serra:
“Ejem00EscribeHolaMundo.com”. Para obter o último, digitamos o seguinte:

Copiar Exem00.com Exem00WriteHelloWorld.com

A notação curta Ejem00.com nos ajuda a executá-lo, simplesmente digitando:

Ahem00 <enter>

Da mesma forma, se quisermos modificar ou depurar o programa Ejem00.com, usamos o programa


debug.exe escrevendo:

depurar Ahem00.com <enter>.

24
Machine Translated by Google

Por outro lado, o outro com nome mais longo serve para nos dizer o que o programa faz; Neste caso
específico, o nome que atribuímos lembra-nos que este programa escreve a mensagem “olá mundo
do Assembler” na tela.

Se por algum motivo você perdeu Ejem00.com, mas mantém aquele com o nome em notação de
serra, você pode recuperar o primeiro escrevendo:

copie Exem00*.com Exem00.com <Enter>

e o programa Ejem00.com será recuperado

2.2. Os recursos de programação em linguagem de máquina e


linguagem Assembly:

A filosofia de quem projetou a linguagem Assembly deve ser muito diferente daquela utilizada pelos
projetistas de linguagens de alto nível. Neste último caso, isso foi feito para aumentar a produtividade
do programador. A sintaxe de uma linguagem de alto nível apresenta ao programador instruções
poderosas em comparação com as do Assembler.

Em média, 10 a 20 instruções de máquina são geradas para cada instrução de linguagem de alto
nível.

Por outro lado, para cada instrução Assembler é gerada uma única instrução de máquina.

É por isso que programar em Assembler é completamente diferente de como é feito em uma
linguagem de alto nível, cuja sintaxe deve ser o mais próxima possível da língua inglesa - quanto mais
próximo estiver da linguagem natural que é o inglês, maior será o seu nível. e mais aceitação terá nos
programadores; O COBOL nasceu com essa filosofia – que é a linguagem humana, na qual são
codificadas as instruções dos programas fonte de quase todos os compiladores existentes no mercado.

Se você entender bem qual é a filosofia da programação Assembly, terá maiores chances de sucesso
na difícil tarefa de programar nesta linguagem.

Um programa em linguagem Assembly é um código que combina, da maneira mais otimizada possível,
o uso dos quatro recursos a seguir:

(1) Memória

(2) Registros

(3) Perturbações e

(4) Instruções para montagem.

Passamos a descrever cada um deles:

25
Machine Translated by Google

23. Memória

A memória é um dos principais recursos dos computadores digitais. Mais tarde veremos que a primeira,
segunda, quarta e quinta capacidades básicas do computador têm a ver com memória.

A memória é um dispositivo eletromagnético que permite armazenar os dados de processamento ,


que são as instruções, e os dados processados , que são os próprios dados. Quando um programa é
executado, os dados processados interagem com os dados processados para produzir novos dados
processados, que são retornados ao usuário do programa.

O que fica armazenado na memória são 1's e 0's, e sabemos que cada unidade de armazenamento
que armazena esses 1's e 0's é chamada de bit. Assim, a string 101111102 requer que 8 bits sejam
armazenados na memória.

O tamanho da memória, que por ser um meio de armazenamento físico tem tamanho finito, é igual ao
número de bits que ela pode conter, ou seja, quantos 1’s e/ou 0’s ela pode armazenar. Como esse
número que dá o tamanho é muito grande, são utilizadas unidades de armazenamento maiores que o
bit. Essas unidades são:

• 1 nibbel que tem 4 bits


• 1 byte que possui 8 bits
• 1 kbyte (quilo byte) que equivale a 210 bytes = 1.024 bytes
= 8.192 bits
• 1 Mbyte (mega byte) que possui 220 bytes = 1.024 Kbytes =
1.048.576 bytes =
8.388.608 bits
• 1 Gbyte (giga byte), que é 230 bytes = 1.024 Mbytes
= 1.048.576 Kbytes
= 1.073.741.824 bytes
• 1 Tbyte (tera byte) que tem 1024 Gbytes = 240 bytes
= 1.048.576 MBytes
= 1.099.511.627.776 bytes

Lembremos que no sistema métrico 1 quilo significa 1000 = 103 , em vez disso, na computação
1 quilo equivale a 1,024 = 2 10, aproximadamente 1.000, mas não 1.000.

Suponha que a memória tenha 1 Mbyte =1.048.576 bytes =8.388.608 bits, ou seja, possui
aproximadamente 1 milhão de bytes, ou seja, 8 milhões de bits.

É preciso entender que todos os bits devem estar interligados, para poder salvar e recuperar o 1
ou o 0 que está armazenado; O fato é que precisamos ser capazes de endereçar o endereço da
memória em nível de bit.

Para simplificar, foi acordado usar o byte como medida de endereçamento, e a cada byte é atribuído
um número hexadecimal que é o seu endereço, que vai desde o primeiro byte ao qual é atribuído o
endereço que é o número hexadecimal 0000016 até o endereço FFFFF16 que corresponde ao último
byte 1.048.576.

26
Machine Translated by Google

2.3.1 Endereçamento absoluto e segmentado. Endereçamento


segmento segmentado:deslocamento

Fazendo uma abstração, podemos então representar uma memória RAM de 1 Mbyte da seguinte forma:

Endereço Byte Não.

0000016 1
0000116 2
0000216
0000316 3. 4

0000416 5
0000516 6
0000616 7
0000716 8
0000816 9
0000916 10
0000A16 onze

0000B16 12

.. . ... ...
8D29816 578.200
8D29916 578.201
8D29A16 578.202
8D29B16 578.203
... ... ...
FFFFC16 1.048.573
FFFFD16 1 1.048.574
FFFFE16 1.048.575
FFFFF16 1.048.576

Esta forma de endereçamento é chamada de endereçamento absoluto. Vemos então que para endereçar todos os
bytes de uma RAM de 1 Mbyte, precisamos de números hexadecimais de 5 dígitos. Como cada número hexadecimal
possui 4 bits, para endereçar a memória precisamos de 4 x 5 = 20 bits. Mas, como veremos mais tarde, os
registradores 8086 têm 16 bits, então os projetistas do processador Intel 8086 tiveram que ser criativos e recorreram
ao endereçamento segmentado. Para isso, imaginaram a memória dividida em segmentos de 64 Kbytes. Esses
segmentos foram numerados de 000016 a FFFF16, usando números 4 hexadecimais que requerem 16 bits = 2
bytes para designá-los, e esses 16 bits podem ser armazenados nos registradores de segmento. Os bytes de cada
setor de 64 Kbytes foram numerados de 000016 a FFFF16; Eles chamaram esse deslocamento de endereço em
inglês (ou deslocamento em espanhol). Ao fazer isso para endereçar a memória, são necessárias duas informações:
o número do segmento e o deslocamento dentro deste segmento. Desta forma, designaremos o endereço de
memória de qualquer byte com dois valores: segmento: offset, chamaremos este tipo de endereçamento de
endereçamento segmentado em relação ao endereçamento absoluto, que requer apenas um único dado
numérico.

27
Machine Translated by Google

Toda a programação que fizermos neste livro Assembler, faremos utilizando o segmento de
endereçamento segmentado: offset, o sistema operacional se encarregará de converter o
endereço segmentado para o endereço absoluto, que é o real. É fácil deduzir a seguinte fórmula,
que converte o endereço segmentado em um endereço absoluto ou real:
*
Segmento16:deslocamento16 = segmento16 1016 + deslocamento16 (*)

Embora possa parecer incrível, esta forma de endereçamento produz sobreposições de segmentos
(“sobreposicionamento” em espanhol). Felizmente, o sistema operacional é quem gerencia a distribuição da
memória, cuidando para que as sobreposições não causem problemas de sobreposicionamento de dados na
memória. Vejamos alguns exemplos e verifiquemos isso usando o programa debug.exe.

Exemplo

Converta os endereços segmentados, fornecidos abaixo, em endereços absolutos. Os endereços são fornecidos
em base hexadecimal.

(1) 0000:0010

(2) 0001:0000

(3) 0000:1050

(4) 0070:0950

(5) 0100:0050

(6) 0105:0000

Solução: Aplicando a fórmula (*) temos sem considerar os zeros à esquerda dos dados
numérico:

*
(1) 0000:0010 = 016 1016 + 1016 = 10 = 0001016

*
(2) 0001:0000 = 116 1016 + 016 = 1016 + 0 16 = 0001016

*
(3) 0000:1050 = 016 1016 + 105016 = 016 + 1050 16 = 0105016

*
(4) 0070:0950 = 7016 1016 + 95016 =70016 + 950 16 = 0105016

*
(5) 0100:0050 = 10016 1016 + 5016 = 100016 + 50 16 = 0105016

*
(6) 0105:0000 = 10516 1016 + 000016 = 105016 + 0000 16 = 0105016

Observamos que os endereços segmentados (1) e (2), embora estejam em segmentos diferentes, possuem o
mesmo endereço absoluto 0001016, ou seja, o endereço real.

O mesmo se aplica aos endereços segmentados (3), (4), (5) e (6), todos quatro apontando para o mesmo
endereço absoluto 0105016.

Foi isso que testamos:

28
Machine Translated by Google

Desvio Endereço
Absoluto

00000
Segmento 0 0000 00001
0001 00002
0002 .. .
0003
Segmento 1 ... 00010
0000
0001 0010
...
1050
...
FFFF 0104F
Segmento 70 01050
0000 01051
0001 FFFE ...
0002FFFF
...
0950

Segmento 100
0000
0001
...
0050

Segmento 105
0000
0001
...
...

... ...
FFFD FFFFD
FFFE FFFFE
FFFF FFFFF

Teste a sobreposição usando debug.exe

Com debug.exe testaremos a sobreposição (sobreposição) dos endereços segmentados


0070:0950 e 0100:0050. Para fazer isso, proceda assim:

PRIMEIRO PASSO

Pressione o botão Iniciar do Windows . No menu pop-up, escolha a opção Executar.


Na janela Abrir , digite debug.exe e pressione o botão OK. Em forma

29
Machine Translated by Google

O Windows exibe imediatamente um traço (ÿ) na tela como uma indicação de que o programa
debug.exe foi carregado na memória.

SEGUNDO PASSO

À direita do traço, digite -D 70:950 <enter>. A depuração irá despejar o conteúdo da memória do
endereço segmentado, e você poderá ver que este endereço de memória contém o valor 0016.
Vamos prosseguir alterando o valor 0016 para o valor CA16. Para fazer isso, procedemos assim:

Digite o comando –E 70:950 <enter> e depois CA <enter>.

A seguir, digitando –D 100:50 <enter>, você pode verificar se os dados CA16 estão armazenados
neste endereço

Tudo isso pode ser visto na figura a seguir:

2.4. Layout de memória

Cada vez que o computador digital é ligado, a memória não contém nada, pois devido à natureza
eletromagnética dos componentes do computador, tudo foi destruído quando o sistema foi
previamente desligado. Al comenzar a trabajar la computadora con la memoria vacía, mediante un
pequeño programa que se encuentra en el disco duro de la máquina, llamado boot strap, el sistema
operativo que administra la memoria, empieza colocando todos los componentes RAM y ROM del
sistema operativo en memória. Quando todos os componentes que o computador necessita para
funcionar terminam de carregar, a memória é distribuída da seguinte forma:

30
Machine Translated by Google

endereço real

00000 Mesa de serviço de interr. - Vetores


00001 Área de programa interrupção
temporário - Área de dados BIOS e DOS
00600 Área de programa do
- Programas aplicativos
0FFFF usuário
- Manipuladores
9FFFF - Sistema operacional DOS
A0000
... Tela de 128 - Exp memória calça
BFFFF Kbytes - Memória de tela
C0000 área de
CFFFF ROM
D0000 64 Kbytes
.. . memória - Memória expandida
DFFFF expandida
E0000
.. . Áreas do sistema -ROM de rede

384 Kbytes - disco ROM


- Memória de vídeo
- ROM do BIOS
FFFFE
FFFFF

Memória estendida

2.5. Registros

O processador 8086 possui 14 registradores de 16 bits (podem conter números hexadecimais de até 2 dígitos),
que são um recurso muito importante e essencial para armazenar dados que não estão na memória. Mesmo
programas muito pequenos podem ser feitos sem usar memória para armazenar dados intermediários. Além
disso, a programação usando apenas registradores é mais rápida do que uma programação semelhante usando
memória e registradores.

Praticamente os logs são usados para acompanhar tudo o que acontece no PC.

Os registradores podem conter dados ou endereços de memória.

Esses registros são divididos em seis categorias como vemos a seguir:

- Finalidade geral (dados MACHADO BX C.X. DX


e endereços) AH-AL BH-BL CH-CL DH-DL
dados do contador base do acumulador
ópera. aritmético. Operação de deslocamento de loop. aritmético.

31
Machine Translated by Google

- De segmentos C.S. D.S. H.H. É


(endereços) Segmento de código Segmento de dados Segmento de pilha Segmento extra
dir. do código dir. de isso. dir. pilha dir. Características adicionais

- Ponteiros de pilha SP BP
(endereços) Ponteiro base do ponteiro de pilha

- De índices SIM DEU

(endereços) Índice de origem Índice de Destino

- Ponteiro de instrução PI
(endereços) Ponteiro de instrução

- Um registro de indicadores de status (sinalizadores), sem nome lógico

Descrevemos agora esses registros com mais detalhes:

(1) 4 registros de uso geral. Que contenham dados e/ou endereços:

MACHADO BX C.X. DX
AH AL BH B.L. CHCL DH DL

Esses quatro registradores são duais, ou,seja, podem ser manipulados como se fossem de 8 ou 16 bits: No modo
16 bits são conhecidos como AX, BX, CX e DX. No modo de 8 bits são reconhecidos como AH, AL, BH, BL, CH,
CL, DH e DL. A parte superior é aquela que aparece com a letra H (high em inglês) e a parte inferior é aquela que
aparece com a letra L (low em inglês).

O registrador AX, como aprenderemos ao iniciarmos a programação, também chamado de acumulador, é


essencial para todas as operações de entrada/saída, trabalhando em conjunto com interrupções, e para algumas
operações em cadeia.

O registrador BX , também conhecido como registrador base, é usado para calcular endereços que acessam a
memória.

O registro ou contador CX é usado para controlar operações repetitivas ou como contador em iterações que
podem ou não envolver operações em strings. Também serve como contador em operações relacionadas a bits
individuais.

Por fim, existe o registro DX, também conhecido como registro de dados, cuja finalidade é servir como repositório
dos endereços das portas. Em combinação com o registro AX, é usado para armazenar números de 32 bits
(DX:AX) em multiplicação e divisão. Outra aplicação deste registrador é em operações de interrupção, durante as
quais preserva o deslocamento ou deslocamento do bloco de informação que será tratado. O registro DX é
geralmente usado em combinação com o registro DS, como DS:DX.

(2) Registros de segmento

O processador possui quatro registradores de 16 bits chamados registradores de segmento. O CS (segmento de


código) ou registro de segmento de código está associado ao código do programa; aponta para o segmento que
contém o código ou dados de processamento; ou seja, ele controla o código

32
Machine Translated by Google

programas e tem o registrador IP como parceiro no sentido de que a combinação CS:IP é o endereço da
próxima instrução a ser executada. O DS (segmento de dados) ou registrador de segmento de dados
contém o endereço do segmento onde os próprios dados ou dados processados são armazenados. O
ES (segmento extra) ou registrador de segmento extra geralmente tem a função de servir de “almofada”
para expansão do segmento de dados. O SS (segmento de pilha) ou registrador de segmento de pilha tem
a função de controlar a área da memória onde a pilha será criada. Tudo isso pode ser visto na figura a seguir:

endereço memória

00000
00001
...
0016F
00170
CS=0017 00171 64 kbytes
... de código
1016F

...

1027F
10280
DS = 1028 10281 64 kbytes
... de dados
?

31000
SS = 3100 31001 64 kbytes de
.. dados de pilha
?

ES = 5000
50000
50001 64 kbytes de
... dados extras
5FFFF

FFFFE
FFFFF

Os registradores DS, CS, SS e ES são essenciais para gerar o endereço de 20 bits que será colocado no
barramento de endereços da CPU. Qualquer operação que acesse a memória utilizará necessariamente um
desses registradores. Cada registro seleciona uma área que pode ou não ser contígua, com tamanho de até
FFFFh bytes, ou seja:

FFFFh bytes = 164 bytes = 216 bytes = 26x210 bytes = 64x210 bytes = 64 KBytes = 65536 bytes

33
Machine Translated by Google

Cada instrução utiliza registradores de segmento com algum deslocamento interno para acessar
informações, como aprenderemos quando iniciarmos a programação.

Não é necessário usar todos os quatro registradores de segmento; O que é essencial é o segmento
de código. Se este segmento não existir, simplesmente não há programa.

(3) Registradores de ponteiro de pilha

BP SP

Como o próprio nome indica, são registradores que apontam para algum local de memória em
geral, como pode ser visto na figura acima que aponta para o segmento 310016. O BP (ponteiro
base) ou ponteiro base é muito utilizado para manipular as informações que estão localizadas no
pilha. Um de seus principais usos é fornecer um mecanismo para passar parâmetros para rotinas.
O SP (ponteiro de pilha) é usado para apontar para o início da pilha, e o BP fornece o deslocamento
da pilha.

(4) Registros de índice

SIM DEU

Esses registradores são geralmente usados em operações com strings. Um uso muito comum
deles é através da instrução MOVSB (move string byte), que copia bytes consecutivos do endereço
especificado pelo SI (índice de origem) ou índice de origem para o endereço especificado pelo DI
(índice de destino) ou índice de destino. Também tem utilização em outros tipos de operações,
como cálculo de endereços ou passagem de parâmetros para outras rotinas.

(5) O registro do ponteiro de instrução

PI

O IP (ponteiro de instrução) é usado em combinação com o registro CS para especificar a área da


memória onde está localizada a próxima instrução a ser executada.
Este registrador altera seu conteúdo de acordo com o fluxo de execução do programa. Os
programas não podem lidar diretamente com esse registrador, mas podem fazê-lo indiretamente
por meio de instruções de desvio (quinta capacidade básica).

(6) O registro da bandeira

Este registro não possui um nome lógico como os demais registros CS, DS, etc., nome que poderia
ser utilizado no programa fonte. É um registrador de 16 bits – dos quais apenas 9 são usados –
que informa o status ou resultado de alguma operação aritmética ou lógica. Existem nove bandeiras:

3. 4
Machine Translated by Google

• Seis bandeiras estaduais

Eles registram o estado do processador, geralmente associado a uma comparação ou instrução


aritmética.

CF (bandeira de transporte) - Carregar bandeira. Indica transporte nas instruções


aritmética.
OF (sinalizador de estouro) - Sinalizador de estouro (aritmética)
ZF (bandeira zero) - Resultado zero ou sinalizador de comparação igual
SF (bandeira de sinalização) - Resultado negativo ou sinalizador de comparação
PF (sinalizador de paridade) - Sinalizador de paridade (número par de bits)
AF (bandeira auxiliar) - Bandeira auxiliar. Indica se há necessidade de ajuste no
Operações aritméticas com números BCD (decimais codificados em
binário)

• Três sinalizadores de controle.

Eles registram o modo operacional do processador.

DF (bandeira de direção) - Bandeira de direção. Controla a direção (para frente ou


para trás) em operações com cadeias de caracteres, aumentando
ou decrementando automaticamente os registros de índice SI e DI.

SE (sinalizador de interrupção) - Sinalizador de interrupções. Indica se interrupções de dispositivos


externos são permitidas ou não.
TF (sinalizador de armadilha) - Pegue a bandeira. Controla a operação no modo passo a passo
etapa (usada pelo programa debug.exe)

As posições da bandeira dentro do registro são:

15 14 13 12 11 10 9 8 76 5 4 32 1 0

DE DF SE TF SF ZF AF PF C.F.

Cada bit do registrador de flag possui duas condições: ativado ou desativado. Ou seja, pode ser igual a 1
(quando ligado) ou igual a 0 (quando desligado).

O significado de cada bit do registrador de flag é descrito abaixo.

Todas as bandeiras desativadas:

NV UP DI PL NZ NA PO NC

Todas as bandeiras acesas:

OV DN EI NG ZR AC PE CY

35
Machine Translated by Google

Sendo o significado dos bits:

• Estouro NV = sem estouro


OV = se houver
• Direção PARA CIMA = para frente
DN = para trás
• Interrupções DI = desabilitado
EI = ativado

• Assinar PL = positivo
NG = negativo
• Zero Nova Zelândia = diferente de zero

ZR = se zero

• Transporte auxiliar NA = sem transporte auxiliar


AC = há transporte auxiliar
• Paridade PO = paridade não
PE = paridade par
• Transportar NC = sem transporte
CY = se houver carry

Segmentos e registros associados

Em linguagem de máquina ou linguagem Assembly, como o endereço segmentado é composto por registro:offset,
em muitos casos, para simplificar o código, cada segmento possui um ou mais registros associados que lhe são
atribuídos. Por exemplo, em vez de escrever a instrução mov ax,DS:[BX], você apenas escreve mov ax,[BX], uma
instrução na qual [BX] significa deslocamento.

Podemos fazer isso porque o registro DS tem o registro BX como um de seus associados no seguinte relacionamento
de registros associados:

(1) CS PI (2) D.S. BX, SIM, DI

(3) SS SP, BP ( 4 ) ES BX, SIM, DI

2.6. Interrupções

Lembremos que a terceira capacidade básica de um computador digital é a capacidade de interface de entrada/
saída e é executada através de instruções de entrada/saída. As interrupções são os meios do processador para
realizar operações de entrada/saída.

De alguma forma, a CPU precisa estar ciente do que está acontecendo ao seu redor. Essa “consciência” é adquirida
por meio de interrupções. Cada vez que uma tecla é pressionada, o teclado interrompe a CPU e diz: Ei, tenho algo
para você! A CPU para o que está fazendo e presta atenção ao teclado e reage e executa uma ação pré-determinada
dependendo de qual tecla o usuário pressionou. Para cada chave a CPU reage de maneira diferente. Algo
semelhante acontece quando você deseja escrever um caractere na tela ou na impressora, ocorre uma interrupção.
As interrupções ocorrem com tanta frequência que a CPU precisa de uma maneira eficiente de lidar com elas. Uma
maneira de gerenciar interrupções, usada no ambiente MS-DOS, é manter uma tabela de vetores (ou seja,
endereços) em pouca memória (explicaremos isso em detalhes mais tarde, quando estudarmos programas
residentes em TSR). Esses vetores de interrupção apontam para outro local de memória onde o

36
Machine Translated by Google

A CPU começará a executar o código encontrado lá. Essa técnica é chamada de manutenção da
interrupção. Após executar esta tarefa, ele retorna para a próxima instrução que segue a interrupção.
Em outras palavras, uma interrupção é um desvio para um determinado local da memória (RAM ou
ROM) onde a CPU iniciará a execução de uma série de instruções, e ao terminar retornará ao
próximo local da instrução que causou a interrupção.

As interrupções são divididas em:

1. Interrupções de hardware (interrupções externas e internas)


Exemplo: mau funcionamento de um periférico ou pressionamento de tecla.

2. Software ou interrupções internas

Eles ocorrem como resultado da execução de uma instrução int, ou de uma operação de
divisão que causa overflow, ou da execução em modo passo a passo, –com debug.exe, com
os comandos T ou P, por exemplo–. Existem 256 interrupções de software (numeradas de 00h
a FFh).As interrupções de software são divididas em:

(a) Interrupções do BIOS (Sistema Básico de Entrada/Saída), que trata


interrupções 00h a 1Fh.
- Controlar periféricos e, às vezes, funções de disco
(b) Interrupções DOS (Sistema Operacional de Disco), que tratam de interrupções
20h até 3Fh.
- Gerenciar memória e disco

As interrupções do DOS são geralmente usadas carregando o parâmetro de função desejado no


registro AH, invocando a interrupção 21h. Este processo é chamado usando funções DOS. Na
prática esta interrupção acaba sendo a mais utilizada. Uma razão para isso é manter a
compatibilidade entre versões futuras do sistema operacional MS-DOS, que continua sendo uma
parte importante dos sistemas operacionais Windows.

Nesta primeira parte, que programaremos em linguagem de máquina, utilizaremos duas interrupções:
a interrupção INT 20h, que não possui funções, e a interrupção INT 21h, com algumas de suas
funções AH para os valores 01h, 02h, 08h, 09h, 0Ah, 4Ch, que descreveremos agora:

Interno 21h

AH Função

01h Espere para ler um caractere do teclado com eco


(com verificação CTRL-BREAK).
Saída: AL = caractere ASCII, lido no teclado

02h Grava na tela o caracter ASCII contido no registrador


DL

09h Grava na tela a string de memória


endereçada por DS:DX, que deve terminar em “$”

37
Machine Translated by Google

0Ah Lê uma sequência de caracteres do teclado e os armazena


em uma área de memória. O primeiro byte da área, registrado
anteriormente, deve ser diferente de zero e indica o número
máximo de caracteres a serem digitados (incluindo o retorno
carro). O segundo byte da área indica o
número de caracteres digitados (sem incluir retorno
de carro). Os dados são armazenados de
do terceiro byte.
Endereço de entrada DS:DX

04Ch Voltar para DOS

Interno 20h

Passa o controle para DOS, em programas COM

2.7. Instruções.

Já mencionamos que os computadores digitais também são chamados de computadores com programas
armazenados porque, para executar um programa, eles precisam carregá-lo inteiramente na memória antes
de executá-lo. Vamos esclarecer mais este conceito: Os computadores ou sistemas de processamento de
dados caracterizam-se pelo processamento digital da informação, bem como pela diferenciação em instruções
(programas) e dados de informação, ambos representados digitalmente na memória principal. Um programa
é uma sequência de instruções dadas por uma pessoa (programador) a uma máquina (computador), indicando
a esta com detalhe e precisão como deve agir para obter a solução de um problema, cujos dados estão
incluídos no programa. . Isto é, a máquina é informada exata e completamente o que deve fazer, através de
uma sequência de instruções, às quais a máquina deve obedecer cegamente.

O computador digital nada mais faz do que explorar sequencialmente as informações armazenadas em sua
memória, que está no programa, composto por um conjunto de instruções, e as processa seguindo o princípio
de Von Neumann: primeiro ele lê cada instrução, decodifica-a e interpreta-a, e segundo Executa-o, salvando
os resultados na memória. Cada vez que uma instrução é executada, o IP aumenta automaticamente em 1 ou
mais, dependendo do tamanho da instrução em bytes, e aponta para a próxima instrução.

O conjunto básico de instruções do microprocessador 8086, compatível com todos os microprocessadores da


família X'86, é composto por 92 instruções, agrupadas a seguir, e que estudaremos, aos poucos, com bastante
detalhe posteriormente.

Instruções de transferência de dados ................ 14


Instruções aritméticas............................................... vinte

Instruções de manuseio de bits................................. 12


Instruções de transferência de controle.................... 23
Instruções de manuseio da corrente.................................. 8

38
Machine Translated by Google

Instruções de interrupção ........................................... 3


Instruções de controle do processador.................... 12

Total ................................................ 92 instruções

Uma instrução em linguagem de máquina é composta pelo nome da instrução e 0 a 2 operandos

Exemplo: mov machado,41

nome do operando

Em linguagem de máquina todas as constantes estão em base hexadecimal, portanto no exemplo anterior 41
significa 41h, ou seja, 4116. Também não é permitido o uso de variáveis, rótulos ou comentários.

O encerramento de um programa de máquina deve ser feito com INT 20h.

A seguir, passamos a projetar alguns programas simples em linguagem de máquina.


Usaremos o programa debug.exe e seus comandos: E, A, U, D, G, P, T, Q, N, R, que já descrevemos acima.
Faremos alguns cálculos aritméticos com números hexadecimais e traçaremos os programas escritos.

Sabemos que com base na equivalência 24 = 16, mostra-se que a conversão de um número hexadecimal em
binário e vice-versa é imediata recorrendo à seguinte tabela de conversão, que pode ser decorada com muita
facilidade, porque é muito útil .

número binário número hexadecimal

00002 016
00012 116
00102 216
00112 316
01002 416
01012 516
01102 616
01112 716
10002 816
10012 916
10102 A16
10112 B16
11002 C16
11012 D16
11102 E16
11112 F16

Com esta tabela podemos converter um número de binário para hexadecimal ou vice-versa imediatamente:

39
Machine Translated by Google

101011111

quinze F
Exemplo 1

Este é um exemplo ilustrativo. É incrível, mas afirmamos que a seguinte cadeia de uns e
zeros:

1011101000001001000000011011010000001001110011010010000111001101001000000110
0001011011000110011101101111011100100110100101110100011011010110111100100100

É um programa de computador digital, que contém instruções e dados, e que escreve a palavra:
“algoritmo” na tela. Na realidade, todos: programas grandes e pequenos são sequências de uns e zeros.

Para facilitar o trabalho, utilizando a tabela de equivalência anterior, convertemos os números binários
para hexadecimais e obtemos esta outra sequência de números hexadecimais:
BA 09 01 B4 09 CD 21 CD 20 61 6C 67 6F 72 69 74 6D 6F 24

Para entrar no programa, usamos o comando –E (Enter), que podemos usar de duas maneiras diferentes:

(1) Digitamos –E 100 <enter> e depois digitamos os números hexadecimais, em pares; Após inserir cada
par, pressione a tecla de espaço. Ao terminarmos com os dois últimos números hexadecimais 2 e 4,
pressionamos a tecla <enter> e aparece o script, que é o símbolo debug.exe.

Então, para executar o programa utilizamos o comando –G (go) e vemos que aparece a string “algoritmo”
e na linha seguinte a mensagem: “O programa terminou normalmente”. Podemos ver tudo isso na seguinte
tela:

40
Machine Translated by Google

(2) Digitamos –E 100 BA 09 01 B4 09 CD 21 CD 20 61 6C 67 6F 72 69 74 6D 6F 24 <Enter>


e para executá-lo digitamos -G e obtemos:

Se pressionarmos o comando –u 100, veremos os seguintes dados:

ENDEREÇO ENDEREÇO CONTEÚDO OS 1 e 0


RELATIVO ABSOLUTO DO INTERPRETADO
DA MEMÓRIA DO MEMÓRIA NA LÍNGUA
MEMÓRIA MÁQUINA
IP=0100 IP=14BD0
••• 00000 •••
••• 00001 •••
... •••
14AD:0100 14BD0 10111010
14AD:0101 14BD1 00001001 movimento dx,109
14AD:0102 14BD2 00000001
14AD:0103 14BD3 10110100
14AD:0104 14BD4 00001001 movimento ah,09 instruções
14AD:0105 14BD5 11001101
14AD:0106 14BD6 00100001 interno 21

14AD:0107 14BD7 11001101


14AD:0108 14BD8 00100000 interno 20

14AD:0109 14BD9 01100001 para

14AD:010A 14BDA 01101100 eu

14AD:010B 14BDB 01100111 g


14AD:010C 14BDC 01101111 qualquer

14AD:010D 14BDD 01110010 R

14AD:010E 14BDE 01101001 Ei dados


14AD:010F 14BDF 01110100 t
14AD:0110 14BC0 01101101 eu
14AD:0111 14BC1 01101111 qualquer

14AD:0112 14BC2 00100100 $


. .. ... • .• .• .
14AD:FFFE 24ACE •••
14AD:FFFF 24ACF

Solicita-se gravar este programa com o nome Ejem01.com e duplicá-lo em sua notação Sierra:
Ejem01CadenaBinariaComoPrograma.com.

41
Machine Translated by Google

A seguir codificaremos em linguagem de máquina os exemplos dados ao descrever as capacidades básicas


1, 2, 3, 5, 6 e 7 do computador, com exceção da capacidade de programa armazenado 4, que acabamos
de discutir extensivamente. (Salve todos os programas como .com)

Exemplo 2. (Primeira capacidade básica: armazenar dados na memória)

Vamos verificar como os dados numéricos, como o número hexadecimal 4116, podem ser armazenados
na memória do computador. Temos que fazer algo semelhante ao que a instrução de atribuição mov X,
41h faria no Assembler. Primeiro devemos decidir em qual segmento e deslocamento devemos salvar o
número 41h. Para esta escolha, entramos em debug.exe da forma já conhecida, e descobrimos em qual
setor o sistema operacional nos designou para trabalhar. Para fazer isso, pressionamos o comando –r sem
parâmetros e obtemos a seguinte tela:

Observamos que aos quatro registradores de segmento: DS, ES, SS, CS, foi atribuído o segmento 1533 –
na sua máquina o DOS pode atribuir um valor diferente a ele. Estamos particularmente interessados
apenas no segmento de dados DS=1533. Poderíamos continuar com este mesmo endereço 1533, mas
vamos escolher um diferente, segmento 14AC e offset 0, endereço em cujo endereço armazenaremos o
número hexadecimal 41h, cujo comprimento é de 1 byte. Então o endereço escolhido é o endereço
segmentado 14AC:0000, que corresponde ao endereço absoluto ou real: 14AC * 10 + 0 = 14AC0. Em
seguida, precisamos escrever o código em linguagem de máquina que nos permita fazer isso. Usamos o
comando –A para inserir o seguinte código:

machado mov, 14AC

mov ds, machado

mov byte ptr [0000],41


interno 20

Antes de executar o programa, descobrimos qual valor hexadecimal existe naquele endereço. Para isso
utilizamos o comando –d 14AC:0000 e observamos que naquele local de memória existe o valor 00h – na
sua máquina você pode encontrar um valor diferente. Executamos o programa com a instrução –g, e então
despejamos a memória novamente com o comando –d e verificamos se em vez de 00h existe o hexadecimal
41h.

A tela a seguir mostra o resultado da execução dos passos indicados:

42
Machine Translated by Google

Vamos explicar o código escrito. Com instruções:

mov machado,14AC e mov ds,ax

O processador foi informado de que o registro DS aponta para o segmento 14AC. Duas instruções são usadas
porque o Assembler não permite que dados numéricos sejam movidos diretamente para o segmento de dados DS.
Para mover os dados para um dos quatro segmentos DS, CS, SS e ES, é necessário utilizar um registrador auxiliar,
que serve como intermediário, neste caso utilizamos o AX.

A seguinte instrução:

mov byte ptr [0000],41

diz ao processador para mover para o deslocamento 0000 do segmento de dados, o número 41h.
Observe que em Debug.exe, para nos lembrar que se trata de um deslocamento, o valor 0000 é colocado entre
colchetes. Além disso, se você não colocar os colchetes, receberá uma mensagem de erro.
A palavra byte ptr (ponteiro de byte) informa ao processador que ele só precisa armazenar dados de tamanho 1
byte.

e por fim a instrução: int 20, serve para finalizar o programa.

O programa é gravado com o nome Ejem02.com, e é feita uma cópia: Ejem02Cap_Bas1MoverDatosAMemoria.com

Exemplo 3. (Segunda habilidade básica: aritmética simples)

Primeiro verificamos a adição de 3 + 5 e a subtração 8 - 3. Usando o comando –a inserimos o seguinte código:

mova al,3
adicione al,5

43
Machine Translated by Google

mov al,8
subal,3
int 20

e procedemos à execução do programa, passo a passo, utilizando o comando –p (prosseguir) e verificamos


que no meio registro AL de AX permanece a soma 8, e então, neste mesmo registro permanece o número
5 , que é a diferença de 8 – 3. A tela a seguir mostra os resultados obtidos, passo a passo, com o comando
-P do Debug.exe:

*
Para verificar a multiplicação de 3 8 = 24 e a divisão 10/2 = 5, inserimos o seguinte código, lembrando
que debug.exe só funciona com números hexadecimais:

mov al,3
mov bl,8
mul bl
mov al,A
mov bl,2
div bl
int 20

Ao executar este código, usando o comando –p (proceed), obtemos o seguinte resultado de 1816 no
*
meio registro que é o produto de 316 816 = 1816 . Por outro lado, a divisão da A16
(dez em decimal) entre 216 dá 516 que também é armazenado em

A tela a seguir mostra o resultado da multiplicação:

44
Machine Translated by Google

e esta outra tela mostra os resultados obtidos na divisão:

O programa e a cópia são salvos com os nomes Ejem03.com e Ejem03Cap_Bas2AritmeticaSimple.com

Exemplo 4 (Terceira capacidade básica: entrada/saída)

O código a seguir em Assembler lê um caractere do teclado, armazena-o na variável x, depois pula uma
linha e escreve o caractere lido e termina.

mov ah, 1 ; se prepara para ler um caractere do teclado


interna 21h; lê e salva em AL
mov x,al ; armazena o caractere lido na variável x
mov ah,2 ; se prepara para digitar um caractere na tela
movdl,0Ah ; em dl, a quebra de linha
interna 21h; pular linha
mov dl,x ; em dl o caractere é lido int 21h ;
escreva o caractere lido na tela
mov ah,4ch ; se prepara para terminar
interna 21h; termina e passa o controle para o DOS

A seguir escrevemos o mesmo código, mas em linguagem de máquina:

100 mov ah, 1


102 interno 21
104 mov [115], al
107 mov ah,2
109 mov dl,A
10B int.21
mov 10D dl,[115]
111 int.21
113 int20
115

Quatro cinco
Machine Translated by Google

Entramos no código com o comando –A e quando é executado com –G o programa espera até inserirmos
algum caractere através do teclado; Se pressionarmos a tecla M, obtemos o seguinte resultado:

Se então procedermos ao esvaziamento (despejo) do conteúdo da memória no offset [115], com o comando
–d 115, verificamos que na memória no offset 115 aparece o hexadecimal 4Dh, que corresponde ao caracter
ASCII “M”:

Esse programa ELE registro com o Nomes Ejem04.com e


Exem04Cap_Bas3EntradaYSalida.com

Exemplo 5 (Quinta habilidade básica: tomar decisões simples)

Já mencionamos que os computadores possuem circuitos eletrônicos que podem tomar decisões simples,
que são instruções de comparação para ramificar para um determinado endereço de memória.

46
Machine Translated by Google

Quando estudamos a quinta habilidade básica, fornecemos o seguinte programa em linguagem Assembly:

movimento ah,2

mov ch,”5”
movcl,”3”
cmp ch, cl
jl eu ; “jl” significa pular se for menor
saio mov dl,ch
int 21h
mov dl,0Ah ;prepare-se para pular a linha int 21h ;
pular linha
Eu saio: mov dl,cl
int 21h
mov ah,4ch
int 21h

O que este programa faz é verificar que quando ch < cl for verdadeiro, ele deve escrever na tela o valor que
contém cl, caso contrário deve escrever ambos: primeiro o valor de ch e na linha seguinte o valor de cl.

Para ch=”3” e cl=”5”, o programa deve escrever apenas o valor de cl, ou seja, “5”, e por outro lado, se ch=5 e
cl=3, deve escrever o primeiro “5” e depois “3” na próxima linha. Vamos adaptar o programa para este segundo
caso e temos o seguinte código em linguagem de máquina.

100 mov ah,2


102 mov corr,35
104 mov cl,33
106 cmp corr, cl
108 jl 112
10A mov dl,ch
10C int21
10E mov dl,A
110 interno 21

112 mov dl,cl


114 interno 21 116

interno 20

Note-se que o número 5 – cuja representação hexadecimal num byte é 0516 = 05h = 000001012 – não é o
mesmo que o “5” ASCII, cuja representação hexadecimal é 3516 =35h= 001101012 .

O programa a seguir é o resultado da execução deste código

47
Machine Translated by Google

Ele os programa Exem05Cap_Bas5TomarDecisionesSimples.com.


ELE registro com Nomes Ejem06.com e

Exemplo 6 (sexto recurso principal: persistência de dados)

Anteriormente vimos que para obter persistência um dispositivo de armazenamento secundário chamado arquivo é usado e
não faz parte da memória. Ao descrevermos esta capacidade fornecemos o código de dois programas em linguagem
Assembly: o primeiro para criar um arquivo chamado 'a:\DATA;DAT' - que está localizado em um disquete -, e o segundo para
gravar o número 3 em este arquivo e como verificação, exibi-lo na tela. Abaixo damos o código desses dois programas,
adaptados em um, mas em linguagem de máquina. Se você não entende o código, não se preocupe, mais tarde, quando
estudarmos os arquivos, ele tirará todas as suas dúvidas sobre o funcionamento do programa. Por enquanto, você será
solicitado a inserir este código com o comando –A de debug.exe e executá-lo com o comando –G. Ao finalizar, você pode
verificar se o arquivo “a:\DATOS.DAT” foi criado, utilizando o comando:

edite a:\DATA.DAT

que usa o editor do console do Windows chamado edit.exe

Não esqueça que antes de executar o programa você deve ter um disquete na unidade A:

100 mov ah,3c 102 ;prepara-se para criar um arquivo com endereço dx)
xor cx,cx 104 lea ; cx=0 ;
dx,[156] 108 int 21 carrega o endereço dx do arquivo a ser criado
;cria arquivo cujo endereço é dx
10A movimento ah,3d ;se prepara para abrir um arquivo
10C movimento al,1 ;al=1 significa que irá gravar no arquivo
10E lea dx,[156] 112 ;carrega o endereço do arquivo em dx ;abre o
int 21 114 arquivo e salva em ax=# (# handle)
mov [164],ax 117 mov ;salve #handle na memória, deslocamento. 164
ah,40 119 mov bx, ;prepara-se para gravar o arquivo com identificador em bx
[164] ;recupera em bx=#handle

48
Machine Translated by Google

11D mov cx,1 ; diz para escrever 1 byte


120 lea dx,[155] 124 ;in dx = endereço onde o “3” deve ser escrito no arquivo
int 21 126 ;escreva o “3” no arquivo de endereço dx
mov ah,3e 128 ;preparar para fechar arquivo com identificador em bx
mov bx,[164] ;recupera em bx = #handle ;fecha
12C int21 o arquivo de identificador bx
12E mov ah,3d 130 ;prepara-se para abrir o arquivo handle bx=shift 164
mov al,00 132 lea ;al=0 significa que ele irá ler o arquivo
dx,[156] 136 int 21 ;em dx o endereço do arquivo ;abrir
138 mov arquivo de identificador bx = deslocamento do ponto. 164
ah,3f ;prepara-se para ler o arquivo handle em bx
13A mov bx,[164] ;bx = #handle do arquivo a ser lido
13E mov cx,1 ;lerá 1 byte ;dx
141 lea dx,[166] 145 = endereço. memória para salvar o byte lido; lê 1 byte do
int 21 147 arquivo e salva-o na memória offset. 166
mov dl,[166] ;dl = offset byte 166 (byte lido do arquivo)
14B movimento ah,2 ;prepara-se para escrever o ASCII que está em dl
14D interno 21 ;escreve ASCII na tela
14F mov ah,1 ;prepara-se para ler ASCII do teclado
151 int 21 ;leia <enter> e segure a tela
153 int 20 ;termina e passa o controle para o DOS
155 db 33 ;dados para gravar no arquivo
156 db “a:\DATA.DAT”,00 ; nome do arquivo criado no disquete

Abaixo está o resultado da execução deste programa:

Ele programa ELE com o Nomes: Ejem07.com e


de gravação Ejem06Cap_Bas6PesistenciaDeDatos.com

49
Machine Translated by Google

Exemplo 7 (Sétima capacidade básica: reutilização)

Ao descrever esta capacidade básica, apresentaremos um programa modular, que utiliza uma biblioteca de
programas objeto chamada LIBASS.LIB. Por esta razão este programa não pode ser codificado em linguagem de
máquina; e a única coisa que faremos agora é usar debug.exe para executar o programa Exem7.exe, cujo programa
fonte está em linguagem Assembly, a partir do ambiente DOS. Para fazer isso, digitamos o seguinte: debug
Ejem7.EXE e a seguinte tela aparece:

Digitamos –u, para ver o código fonte e então executamos o programa com o comando –G.
Seguindo as instruções do programa inserimos o número flutuante 2.00E00, que equivale a 2 x 100 = 2,00 e obtemos
a raiz quadrada 1.41421356237309x100 . Se tentarmos com outros dados, eles deverão ser inseridos no formato
flutuante D.DD..DE[+/-]DD, em que D significa um dígito decimal.

Este programa será explicado com mais detalhes quando a aritmética flutuante for estudada. O código do programa
Ejem07.asm é aquele fornecido ao descrever a sétima capacidade básica na seção 1.4.7., e é
Ejem07Cap_Bas7Reutilización.asm. Oregistro com
programa executável Os nomes:
Ejem07.exe também está disponível
Ejem07.asm
.

1.5 Algo mais sobre linguagem de máquina.

A linguagem de máquina é útil para avaliar como o processador funciona internamente. Nesse sentido é um auxiliar
insubstituível, podendo ser utilizado para depurar programas, daí o nome do programa utilitário: debug.exe. Antes
de continuar com o terceiro capítulo em que começaremos a estudar a linguagem Assembly, vamos projetar mais
alguns programas em linguagem de máquina.

Exemplo 8

Você é solicitado a escrever um programa, em linguagem de máquina, que leia uma sequência de caracteres do
teclado com no máximo 72 caracteres = (48h), armazene-a na memória e depois exiba essa sequência na tela.
Como 72 = 48h, o programa mostra 47h.

cinquenta
Machine Translated by Google

Este é um programa que tem que lidar com a capacidade básica de entrada/saída do computador, portanto temos
que usar a interrupção 21h. Como se trata de ler uma string do teclado, conforme tabela de funções do int 21h,
temos que utilizar a função AH=0Ah, para ler a string e a função AH=9h, para escrever a string.

Antes de usar a função AH=0Ah, temos que decidir duas coisas: primeiro, qual será o tamanho da string a ser lida
e, segundo, em que parte da memória iremos armazenar a string lida.
Vamos concordar que o comprimento máximo da string é de 47h caracteres, e que armazenaremos a string no
final do código do programa em linguagem de máquina.

Também concordamos em exibir duas mensagens, para solicitar que a string fosse inserida e para exibir a string
lida. Desta forma, o layout da tela é o seguinte:

Digite uma string: estou aprendendo Assembler


Leitura de string : Estou aprendendo Assembly

Como primeiro passo, inseriremos provisoriamente o código abaixo. Os endereços que aparecem neste código
são o offset 0000, que corresponde ao endereço onde será armazenada a mensagem “Digite a string:”, o valor de
offset 1111, que corresponde ao endereço de memória onde armazenaremos a string lida. O valor 2222, que
corresponde ao endereço onde armazenaremos a mensagem “string lida:”, são provisórios, e obteremos seus
valores reais após inserir o seguinte código no qual as instruções foram numeradas, apenas para efeito de
explicando o que cada instrução em linguagem de máquina faz; Para fazer isso, usamos o comando –A de
debug.exe:

1. leia dx,[0000] (deslocamento 0000 da mensagem 1)


2.mov ah,9
3. int 21
4. leia dx,[1111] (deslocamento 1111 para armazenar string)
5. movimento ah,A
6. int 21
7. mov ah,2 (prepare-se para escrever o personagem)
8. mov dl,A (uma quebra de linha)
9. int 21 (quebra de linha para escrever a segunda mensagem)
10. leia dx,[2222] (deslocamento 2222 da mensagem 2)
11.mov ah,9
12. int 21
13. read dx,[1111] (deslocamento 1111 da string lida)
14. adicione dx,2 (mais 2, para pular o 50º e o número de caracteres lidos)
15.mov ah,9
16. int 21
17. int 20
18. db “Insira uma string terminando em $:$” (primeira mensagem)
. 19. db “String lida 20. db : $” (segunda mensagem)
48, 48 dup (“$”); 48h= 72, ou seja, você pode ler até 72 incluindo o <enter>

51
Machine Translated by Google

Descrição:

1. Assumimos provisoriamente que a primeira mensagem declarada na instrução 18 é 0000, uma vez
que não sabemos qual é o seu valor. A instrução de máquina LEA dx, [0000], significa “Endereço
Efetivo de Carga”, que se traduz em espanhol como: “carregar no registro dx, o endereço efetivo
de deslocamento 0000”.

2 e 3. Escreva na tela a string encontrada no endereço ds:dx. Como acabamos de ler em dx o offset
da primeira mensagem e DS=CS=SS=ES quando se trata de código de máquina, quando essas
duas instruções são executadas elas escrevem a primeira mensagem na tela. A string a ser
exibida deve terminar em $, caso contrário o programa não funcionará bem.

4, 5 e 6. Eles lêem o deslocamento dx da string a ser lida e armazenada onde está localizada a instrução
20. Assumimos que esse deslocamento é 1111. Quando essas instruções são executadas, o
computador lê de 0 a 50 caracteres e os armazena em o endereço que corresponde ao
deslocamento 1111.

7, 8 e 9. Eles usam a função ah=2 que escreve o caracter encontrado em dl na tela.


Como dl=A16 =quebra de linha, quando estas instruções são executadas o cursor salta linha.

10, 11 e 12. Estas três instruções primeiro leem o offset 2222 da segunda mensagem e depois escrevem-
no na tela: sua função é semelhante à das instruções 1, 2 e 3.

13 Lê o offset do endereço onde a string foi armazenada, quando as instruções 4, 5 e 6 foram


executadas.

14 Adicione 2 bytes ao deslocamento dx, 1 para pular o número 28h e outro para pular o número de
caracteres lidos que são colocados após o número 28h.

15 e 16 Escreva na tela a sequência de caracteres lida e armazenada no offset 1111, sem incluir o
número 28h e a quantidade de caracteres lidos.

17 Encerre o programa e passe o controle para o DOS.

18 Declara uma string de bytes, com a mensagem “Digite uma string”, que deve terminar com o
caracter $. É por isso que a diretiva db é usada , o que significa definir bytes, que aprenderemos
mais tarde não é uma instrução, mas sim uma diretiva ou pseudoinstrução.

19 Declare uma string de bytes com a segunda mensagem “String inserida”

20 Separe 28h = 40 bytes de memória, para armazenar a string que será lida ao executar as instruções
4, 5 e 6. Como esta string será exibida com as instruções 15 e 16, ela é inicializada 40 vezes “ $”.

52
Machine Translated by Google

Abaixo temos a tela que mostra o que foi feito. Usando o comando –A, todo o código do programa acima foi inserido. Ao
terminar podemos visualizar os valores dos offsets de cada instrução que servirá para substituir os três offsets 0000,
1111 e 2222.

Nesta tela vemos o seguinte:

• que o offset da primeira mensagem seja 012B, que substitui o valor 0000;
• que o offset da segunda mensagem seja 0140, que substitui o valor 2222;
• e que o deslocamento do endereço para carregar a string de leitura seja 0155, que substitui o valor 1111.

Portanto o novo código que resolve o problema é:

leia dx,[012B]
mov ah,9
interno 21

leia dx,[0155]
mov ah, A
interno 21

mov ah,2
mov dl,A
int 21

leitura dx,[0140]
mov ah,9
interno 21

leia dx,[0155]
adicione
dx,2 mov ah,9
interno 21

interno 20

12B db “Insira uma string: $”: $” 140 db


“String lida 155 db 28, 28
dup (24)

53
Machine Translated by Google

O resultado da execução deste código é o seguinte:

O programa é gravado com os nomes Ejem08.com e Ejem08LeeYEscribeCadena.com.

Exemplo 9

Aprenderemos a multiplicar números hexadecimais, utilizando linguagem de máquina. Se tivermos dois números
decimais: a com n dígitos e b que possui m dígitos; Se calcularmos o produto de a por b, ou seja, a x b, através da
matemática sabemos que a x b tem m+n-1 ou m+n dígitos.

Por exemplo, se multiplicarmos os números decimais 5409 x 1011, o produto deverá ter 7 ou 8 dígitos; Na verdade,
5409 x 1011 = 5468499 tem 7 dígitos decimais. No caso extremo temos que o produto 9999 x 9999 = 99980001 possui
8 dígitos decimais.

Algo semelhante acontece no sistema hexadecimal. Hemos visto que para multiplicar dos números, tenemos que
utilizar dos registros que tienen 16 bits = 2 bytes, por tanto cada uno puede almacenar 4 hexadecimales como máximo,
y el producto llegará a tener 7 u 8 hexadecimales, o sea necesitamos dos registros para almacenar o produto. Por esta
razão o processador utiliza o par de registradores DX:AX para armazenar o produto.

Se tivermos dois números aeb e quisermos calcular seu produto axb, devemos necessariamente colocar um deles no
registrador AX, ou seja, movemos AX,a. Armazenamos o outro número em qualquer registro diferente de AX ou DX,
por exemplo BX, e fazemos mov BX,b; A instrução mul BX calcula axb e salva o resultado em DX:AX, a parte mais
significativa em DX e a parte menos significativa em AX.

Se quisermos calcular o produto FFFFh x FFFFh =FFFE0001h, o seguinte código em linguagem de máquina resolve o
problema:

machado mov,FFFF

mov sim, FFFF


sim, sim

interno 20

54
Machine Translated by Google

O produto é armazenado no par de registradores DX:AX: que é igual a DX=FFFEh e AX=0001h, como pode ser visto se executarmos
este programa

Este programa é gravado sob o nome Ejem09.com e Ejem09Multipliacion.com

Exemplo 10

A divisão é a operação inversa da multiplicação. Portanto o dividendo pode ter entre 1 e 8 dígitos e requer dois registros, o par DX:AX,

e o divisor pode ser qualquer outro registro que não seja DX ou AX, digamos o BX, então a divisão é realizada com a instrução divBX .
O quociente é armazenado em AX e o restante em DX. Por exemplo, se dividirmos 8 por 3, escrevemos o seguinte código

movimento dx,0

mover machado, 8

mova-se sim,3

div sim
interno 20

Se executarmos o programa obtemos em AX=2 e em DX =2, pois:

8 2
=2+ , ou seja, o quociente é 2 e o resto é 2
3 3

Com base no exemplo 9, o valor máximo que podemos colocar no par de registradores DX:AX é o número hexadecimal FFFE0001,
caso contrário receberemos uma mensagem de erro. O seguinte código em linguagem de máquina:

mov dx,FFFE
machado mov,1

mov sim, FFFF


div sim
interno 20

55
Machine Translated by Google

nos dá um quociente em AX igual a FFFFh e um resto em DX igual a 0:

Este programa é gravado sob o nome Ejem10.com e Ejem10Division.com

Exemplo 11

Vamos começar a projetar loops de repetição em nossos programas e teremos que usar novas instruções de
máquina:

As instruções cmp, jl e nop

As instruções cmp (comparar), jl (pular se for menor) permitem formar ciclos de repetição. A instrução nop (sem
operação) nos ajudará na depuração.

Por exemplo, para calcular e armazenar a soma 1+2+...+100, no registrador DX:

DX = 1 + 2 + 3 + ... + 10010 = 505010 (=13BA16)

Escreveremos o seguinte código em linguagem de máquina (6416=10010), que repete as instruções de 3 a 6


100 vezes:

1.mov si,0 (si=0)


2. mov dx,0 (dx=0) 3. 106
adicione si,1 (si=si+1)
adicione dx,si (dx=dx+si)
4. 5. cmp si, 64 (compare o conteúdo de si com 6416 = 10010) 6. jl 106
(salte para 106h se for menor que 64h) ÿ salte para o endereço 106h se for verdade que if < 64 7. (não operar) nop
8 int 20 (termina
para e passa o controle
DOS)

56
Machine Translated by Google

Quando este programa terminar ele será armazenado em DX =13BA16 (=505010) e em SI=6416=10010
como pode ser visto na tela a seguir. O programa deve ser executado com o comando –G 110, que diz ao debug.exe
para executar o programa até a instrução 110 nop, e assim os valores nos registradores DX e SI podem ser
verificados, o que não acontece se nós use –G .

Isso registra o programa ELE com o Nomes Ejem11.com e


Exem11CalculaSumatoria1a100.com.

Exemplo 12

A instrução LOOP

O par composto pelo registrador CX e pela instrução “LOOP label_name” nos permite repetir CX vezes o conjunto de
instruções que vai de label_name até a instrução LOOP. Cada vez que a instrução LOOP é atingida, o valor de CX
diminui 1, desta forma chega um momento em que CX é igual a 0, e o ciclo termina.

Assim, por exemplo, no código de máquina a seguir, como CX contém o valor 1Ah (=26), todas as instruções do
deslocamento 107 ao deslocamento 10C são repetidas 26 vezes, portanto o programa a seguir escreve as 26 letras
do alfabeto inglês, começando com o letra a:

100 mov ah,2


102 mov dl,41
104 mov cx,1A
107 int.21
109 adicionar dl,1

circuito 10C 107


10E interno 20

O teste de execução deste programa é o seguinte:

57
Machine Translated by Google

Este programa é gravado como Ejem12.com e Ejem12EscribeLetrasAlfabetoIngles.com

Exemplo 13

Instruções PUSH e POP

PUSH e POP servem para adicionar e retirar dados do STACK, o que não devemos esquecer, também faz parte da memória.
O armazenamento de dados na pilha é feito de maneira diferente da instrução MOV. As instruções PUSH e POP usam um
único operando que é o nome de um registro.

Já sabemos que JL significa pular se for menor . É por isso que o programa a seguir escreve, na tela, os 10 números
decimais, de 9 a 0, um ao lado do outro com um espaço em branco no meio:

Machado de 100 mov,0

103 machado de pressão

104 adicionar machado,1

Machado de 107 cm,A

10A jl 103 ( pule para 103 se for menor, salta para 103 se for menor)
10C movimento ah,2
10E mov cx,A 111
pop dx
112 adicionar dx,30
115 int.21

117 mov dl,20


119 int.21

circuito 11D 111


11F interno 20

O primeiro ciclo de repetição do deslocamento 103 a 10A serve para armazenar na pilha dez números de 0 a 9. Vamos fazer
uma abstração e imaginar a pilha como um array, como aparece na figura a seguir. Ao final do ciclo vemos que eles permanecem
um em cima do outro, iguais a uma pilha de números – daí o nome -, na qual o último número a entrar será o primeiro a sair:

58
Machine Translated by Google

9 horas da manhã

8h
7h
6h
5h
4h
3h
2h
1 hora

0h

O zero hexadecimal fica no final da pilha, pois foi o primeiro PUSH AX, aquele que foi executado, quando
AX continha o valor 0h.

O segundo ciclo dado pelo par CX=A16=10 e LOOP 111, faz com que as instruções 111 a 117 sejam
repetidas 10 vezes; e serve para remover elementos da pilha.

Para cada DX POP, um elemento é retirado da pilha no registro DX. Começa com 9h, que está no topo da
pilha, e termina com 0h, que está na parte inferior. Se somar 30h ao hexadecimal tomado em DX, por
exemplo 0009h, obtém-se 0039h, ou seja, em DH o valor permanece 00h e em DL resta 39h, ou seja, o
ASCII “9”, que é o caractere que é escrito no display com interrupção 21h e função ah=2. Esta função é
ativada antes de iniciar o segundo ciclo de repetição na instrução 10C.

O resultado final é que os caracteres ASCII de “9” a “0” são escritos na tela.

A tela a seguir mostra o resultado quando o código de máquina acima é executado:

59
Machine Translated by Google

Este programa ELE registro como Ejem13.com e


Exem13StackManageLeeYWriteNumeros.com

Exemplo 14

Continuaremos aprendendo como projetar ciclos de repetição, ou seja, garantir que uma série de instruções
encontradas na memória sejam repetidas um determinado número de vezes, o que é necessário para converter um
número hexadecimal em binário. Primeiro devemos resolver o problema manualmente, para ver quais passos devemos
repetir várias vezes.

Quando dividimos um número por 2, o resto só pode ser 1 ou 0. Se tivermos que converter o número 29 (=1Dh) para
binário, começamos por dividir o número 29 e depois os quocientes resultantes por 2, até obtermos um quociente 0.
De acordo À medida que esse processo avança, os restos são armazenados, conforme mostrado abaixo:

29 2
1 14 2
072
132
112
10

O resultado é o número binário 11101, formado pelos restos, mas escrito na ordem inversa em que foram obtidos.

O seguinte programa em linguagem de máquina resolve o problema

mover dx,0 (DX = 0)


mover (AX = 1Dh = número a ser convertido para 00011101; o dividendo)
machado,1D (o divisor em BX)
mover bx,2 mover cx,0 (CX servirá como contador de repetições) (dividir DX:AX
10C div bx por BX, quociente em AX, resto em DX)
push dx (salva o resto do DX na pilha)
add cx,1 (adicione um ao contador CX)
mov dx,0 (DX=0 para deletar o resto e dividir novamente) (o
cmp ax,0 quociente AX=0?)
jg 10C (se for maior que 0 salta para 10C, se não continua)
mov ah,2 (se prepara para escrever na tela DL)
11C pop dx (recupera descanso em DX)
adicionar (Adiciona 30 horas para convertê-lo para ASCII)
dx,30 (escreve na tela DL ASCII)
int 21 loop (subtraia 1 de CX e ramifique para 11C se CX ÿ0)
11C int 20 (termina, passa o controle para o DOS)

Os valores de 10C e 11C foram obtidos de forma semelhante ao feito no exemplo 8.

O resultado da execução deste programa é o seguinte:

60
Machine Translated by Google

Este programa é gravado sob o nome Ejem14.com e Ejem14EscribeNumeroBinario.com.

61
Machine Translated by Google

CAPÍTULO III LINGUAGEM DE MONTAGEM

3.1 Introdução

No Capítulo I, aprendemos quais são as capacidades básicas de um computador digital. No capítulo II


aprendemos a projetar pequenos programas em linguagem de máquina; mas percebemos que o
debug.exe tem muitas limitações; Porém, o uso da linguagem de máquina nos ajudou a pegar
conceitos de muitas coisas que usaremos agora que começamos a programar em linguagem
Assembly, que representa um nível superior de codificação, no qual podemos usar diretivas ou pseudo-
instruções, declarar variáveis, usar constantes numéricas dados no sistema binário, octal, decimal e
hexadecimal, etc.

Modularidade é um aspecto importante

E sobretudo porque a linguagem Assembly permite-nos aproveitar a terceira razão pela qual os
computadores são utilizados para resolver problemas, já mencionada no capítulo I, e é por isso que
com a sua criatividade o homem é capaz de decompor um grande e difícil problema de solução, numa
conjunto de pequenos problemas fáceis de resolver.

Repetimo-lo agora porque isto é importante: quando o homem se depara com um problema de grande
complexidade não o resolve directamente, mas pelo contrário resolve equivalentemente um conjunto
de pequenos problemas - um após outro -, com o pertinente esclarecimento de que as soluções para
Esses pequenos problemas podem ser obtidos usando os recursos básicos limitados que todos os
computadores possuem.

A linguagem assembly nos permitirá trabalhar de forma modular, decompondo um programa muito
grande em um conjunto de procedimentos ou módulos, que possuem um número de instruções não
muito grande para que seja gerenciável.

A entrada e saída de dados é um problema.

Porém, ao programar em linguagem Assembly também descobriremos que existem muitas limitações,
especialmente com instruções de entrada e saída. Já mencionamos anteriormente que a leitura e
escrita de dados está sempre implícita na representação da informação , numa linguagem que tem
essência matemática quando se utiliza o computador.

O computador digital não lê, apenas registra dados. Transfere dados de um meio magnético
denominado disco ou teclado para outro meio magnético denominado memória (armazenamento
principal).

O computador não grava, transfere ou duplica dados de uma mídia para outra, da memória
(armazenamento principal) para o disco ou para a tela.

A filosofia do processador é que tudo o que é lido no teclado é código ASCII e tudo o que está escrito
na tela também são caracteres ASCII, mas são armazenados na memória no sistema binário, em
correspondência com a tabela de códigos ASCII.

62
Machine Translated by Google

Além disso, os dados numéricos são armazenados internamente na memória do sistema binário, mas verifica-se que

sua representação está muito distante dos padrões binários usados para os 256 caracteres da tabela ASCII.

Se lido no teclado, o ASCII “3” é armazenado em um byte de memória, como 33h (em binário 001100112), que é muito
diferente do número hexadecimal 3h (em binário 000000112).

O mesmo problema ocorre quando temos o número 03h (000000112) na memória, se escrevermos este valor na tela,
conforme ele está armazenado, será escrito o caracter ASCII que corresponde a um número com dois dígitos
hexadecimais, o número 03h, que de acordo com a tabela de caracteres ASCII – para verificar isso, execute o
programa Ejem19.com, que exibe esta tabela na tela – é o símbolo “ÿ”, e não o 3 como seria de esperar.

Para testar isso, execute o seguinte programa em linguagem de máquina e você verá que a figura “ÿ” é exibida na tela.

movimento ah,2

mover
dl,3 int 21
interno 20

O resultado é visto na tela a seguir:

Posteriormente resolveremos o problema da saída, recorrendo ao reaproveitamento, que é uma das capacidades
básicas dos computadores; Para isso construiremos uma biblioteca estática de módulos de objetos, denominada
UPA.LIB, que conterá diversos procedimentos de objetos para saída de dados numéricos. Este tópico será discutido
mais tarde.

3.2. Programa fonte

Lembremos que quando trabalhamos com debug.exe, para inserir as instruções da máquina, utilizamos o comando –
A, e depois para executar o programa o comando –G.
Trabalhando com o compilador da linguagem Assembly, a entrada e a execução fazem parte de um conjunto de etapas
que devem ser executadas uma após a outra e que devem ser seguidas à risca. Isso ocorre porque o ambiente da
linguagem Assembly é mais sofisticado do que aquele usado com o programa debug.exe.

As etapas seguidas para construir um programa em linguagem Assembly são: 10 ) edição, 20 ) montagem, 30 )
vinculação e 4 ) execução.

Descrevemos agora cada uma dessas etapas.

63
Machine Translated by Google

PRIMEIRO PASSO: Edição.

As instruções e a definição dos dados que são codificados respeitando a sintaxe da linguagem Assembly são chamadas de
programa fonte. O programa usado para digitar essas instruções é chamado de editor. Existem vários editores que podem
ser utilizados, como por exemplo o programa edit.exe, fornecido pelo Windows como um componente do DOS.

A estrutura de um programa fonte Assembler contém mais de um segmento: um para código (que é obrigatório) e,
opcionalmente, um segmento para dados, a pilha e o segmento extra. Nesse sentido, a estrutura de um programa fonte em
linguagem Assembly é a seguinte:

segmento nome1
Suponha que cs:nome1, ds:nome2, ss:nome3, es:nome4
sim
processo nome5
e instrução 1

g instrução 2
eu ...
e Termina
n nome5 endp
t nome6 proc
qualquer instrução 1
instrução 2
d ...
e ret

nome6 final
c .. .
eu
processo de nome
instrução 1
odeio instrução 2

g ...
qualquer ret

endp nome1
termina _
segmento nome2
diretiva de definição de dados 1
diretiva de definição de dados 2
...
segundo de dados diretiva de definição de dados n
nome2 termina
pilha de segmentos name3
diretiva de definição de dados de pilha 1
bateria diretiva de definição de dados de pilha 2
...
segundo diretiva de definição de dados de pilha f
nome3 termina

segmento nome4
diretiva de definição de dados de segmento extra 1
diretiva de definição de dados de segmento extra 2
segundo extra ...
diretiva de definição de dados de segmento extra f
nome4 termina
nome final5

64
Machine Translated by Google

A seguir está um exemplo de um programa fonte em linguagem Assembly:

Programa: Test.asm e TestProgramWithFourSegments.asm


código de segmento de diretiva
assuma a diretiva cs:code,ds:data,ss:stack,es:extra
diretiva proc principal mov ax,data ; carregar endereço do segmento de dados

mov ds,ax ; segmento de dados de pontos ds


leia dx, mensagem1; carregar endereço efetivo da mensagem1
mov ah,9 ; se prepara para escrever a string ds:dx
interna 21h; faz

mov machado,"A" ; coloque em

machado de empurrar; bateria "A"

mov machado,"B" ; coloque em

machado de empurrar; a bateria "B"

mov machado,"C" ; coloque em

machado de empurrar; a pilha "C"

mov machado,"D" ; coloque em

machado de empurrar; a bateria "D"

mov ah,2 ; função para escrever caractere


mov bp,sp ; bp=sp= início da pilha em bp
mov dl, byte ptr [bp+6] ; dl=primeiro caractere colocado na pilha
interna 21h; escreve na tela

mov dl, byte ptr [bp+4] ; dl=segundo caractere colocado na pilha


interna 21h; escreva

mov ah,2 ; prepare-se para escrever personagem


mov dl,0dh ; retorno de carro CR
interna 21h; retorna

mov dl,0ah ; Quebra de linha LF


interna 21h; pular

mov machado,extra ; leia o endereço do segmento extra


mov es,ax ; es aponta para segmento extra
mov si,0 ; sim = deslocamento 0
mov cx,33 ; cx = 33 vezes
Eu sigo:

movimento dh,0

mov dl,es:outra_mensagem[sim] ; dl=letra de outra mensagem em deslocamento. Sim


adicione se,1; aumenta o deslocamento
mov ah,2 ; prepare-se para escrever o caractere dl
interna 21h; escreva

loop eu continuo; repita o ciclo cx = 33 vezes


mov bp,sp ; início da pilha em bp
mov dl, byte ptr [bp+2] ; dl=terceiro caractere colocado na pilha
interna 21h; escreva

mov dl, byte ptr [bp] ; dl=quarto caractere colocado na pilha


interna 21h; escreva

mov ah,4ch ; se prepara para sair


interna 21h; sai

o código endp diretiva

principal termina diretiva

65
Machine Translated by Google

segmento de dados
mensagem1 db "Cartas lidas segmento de dados: $" dados diretivas
terminam

pilha de segmentos
A pilha db 4 dup diretivas
("STACK") termina
segmento extra
another_message db "Cartas lidas com segmento extra:" diretivas
pontas extras
fim principal

Qualquer coisa que não esteja marcada como diretiva não é uma instrução.

A edição do programa acima pode ser feita usando Edit.exe. Previamente deve-se adotar um nome para o programa
fonte, que deve ter um nome de 1 a 8 caracteres e extensão .ASM. Para o nosso caso, vamos adotar o nome
Test.ASM, e proceder à sua edição com o seguinte comando no ambiente DOS:

Editar Test.asm

e a seguir digite o programa fonte conforme aparece acima, como pode ser visto na tela a seguir:

66
Machine Translated by Google

SEGUNDA ETAPA: Montagem.

Identificamos duas linguagens de programação de alto e baixo nível . Os programadores que


escrevem em uma linguagem de alto nível, como C ou Object Pascal, codificam comandos
poderosos, cada um dos quais pode gerar muitas instruções em linguagem de máquina. Por outro
lado, os programadores que escrevem em linguagem assembly de baixo nível codificam instruções
simbólicas como aquelas do programa fonte acima, cada uma das quais gera uma instrução em
linguagem de máquina.

Não importa qual linguagem de programação você use, ainda é uma linguagem simbólica que
precisa ser traduzida para linguagem de máquina. Uma linguagem de alto nível usa um compilador
para traduzir o código-fonte em linguagem de máquina não executável (às vezes chamada de
código-objeto). Uma linguagem de baixo nível usa um assembler para realizar a tradução. Em
seguida, um programa chamado Link.exe, para níveis alto e baixo, conclui o processo de
conversão do código-objeto em linguagem de máquina executável.

O programa assembler da Microsoft é denominado MASM.EXE e o assembler da Borland é


TASM.EXE. Para montar os programas deste livro, qualquer um dos dois montadores pode ser
usado.

Os comandos para montar o programa fonte são os seguintes:

Teste MASM.asm

ou este outro:

Teste TASM ou também TASM test.asm

Se não houver erros no programa fonte, o montador gera o programa objeto denominado test.OBJ.

Se uma lista do programa de origem for necessária em um arquivo chamado test.lst, os seguintes
comandos serão usados:

Teste MASM,,test.lst,,

ou este outro

Teste TASM,,test.lst

Após test.lst ser gerado, ele pode ser impresso ou editado com o editor DOS edit.exe usando o
comando:

Editar teste.lst

TERCEIRO PASSO: Link

Quando o programa Test.asm fica sem mensagens de erro, o montador gera o objeto de programa
test.obj. A próxima etapa é vincular o módulo do objeto.

67
Machine Translated by Google

Por que a montagem é realizada? A resposta é porque o programa vinculador Link.exe


executa as seguintes funções:

• Caso seja solicitado combinar mais de um módulo montado separadamente em um único


programa executável. Até o programa Link.exe pode combinar módulos de objetos gerados
por compiladores como C e/ou assembler.
• Gera um módulo .EXE e o inicializa com instruções especiais para facilitar seu posterior
carregamento e execução.

O comando para a montagem, no nosso caso é:

Teste de LIGAÇÃO;

E recomendamos que você não esqueça de digitar o ponto e vírgula final, pois caso contrário o LINK funciona
em modo interativo e solicitará mais informações, o que aparentemente acaba sendo óbvio, e é o ponto e
vírgula final, que evita esse diálogo com o vinculador programa Link.exe.

QUARTA ETAPA: Executando o programa .EXE

Depois que um ou mais módulos .OBJ forem vinculados a um único módulo .EXE, você poderá executar o
programa.exe quantas vezes quiser digitando o seguinte comando:

Teste <entrada>

Embora estes passos possam não ser completamente claros no início, você descobrirá que com um pouco de
experiência eles se tornarão automáticos.

O resultado da execução do programa test.exe é o seguinte:

68
Machine Translated by Google

Diagrama conjunto das etapas para editar e montar um , link e crie o executável
programa
tela

teclado

editar.exe na memória o editor

teste.asm programa.fonte

MASM.exe
na memória o montador
OU TASM.exe

Outros.obj Teste.obj programa.objeto

LINK.EXE na memória o vinculador

Teste.exe programa,exe (executável)

Execução do programa
Disco disquete teclado na tela

INGRESSOS

Nome.exe programa executável

PARTIDAS

tela Disco disquete impressora

69
Machine Translated by Google

3.3 Tipos de declarações de origem

Dissemos que um programa de computador é composto de instruções e dados; Ambos são os principais
componentes do que é chamado de programa fonte e é por isso que são chamados de instruções fonte;
Portanto, um programa fonte contém dois tipos de instruções:

1. Instruções, que são declarações que começam com um verbo na forma imperativa, como ADD e MOV,
que farão com que o processador faça alguma coisa. Posteriormente veremos que as instruções geram
código, ou seja, para cada instrução em linguagem Assembly origina-se uma instrução em linguagem de
máquina.

2. Diretivas ou pseudoinstruções, que são usadas para definir os dados, indicam onde um programa começa
e onde termina, ou indicam onde o segmento de dados, a pilha e muitas outras coisas começam e
terminam. Diferentemente das instruções, as diretivas não geram código, ou seja, são utilizadas apenas
pelo compilador, mas servem para construir a estrutura do programa.

As instruções são aplicadas em tempo de execução, enquanto as diretivas são aplicadas em tempo de
montagem.

3.3.1. FORMATO DE INSTRUÇÃO DE MONTAGEM

O formato de uma instrução contém quatro campos:

[rótulo[:]] nome_da_instrução [operandos] [;comentários]

Os colchetes [ ] significam que o campo correspondente é opcional.

Exemplo: mover: mover AX, 45h ; Atribuir 45 a AX

instrução de operandos de comentários


rótulo

3.3.1.1. Campo de etiqueta

- Pode ter até 31 caracteres


- Deve terminar com o símbolo de dois pontos “: “

3.3.1.2. Campo nome

É o nome simbólico da instrução. Pode ter de 2 a 6 letras.

3.3.1.3. Campo operando

Pode ter 0, 1 ou 2 operandos

3.3.1.4. Campo de comentário

Deve começar com ponto e vírgula “;”. Qualquer coisa escrita à direita do símbolo “;” é ignorado pelo compilador

70
Machine Translated by Google

3.3.2. Identificadores

Um identificador é um nome aplicado aos elementos do programa de origem. Os dois tipos de


identificadores são: nome ou variável, que se refere ao endereço de um elemento de dados, e
rótulo , que se refere ao endereço de uma instrução e é o primeiro campo opcional de uma instrução.

Um identificador pode usar os seguintes caracteres:

• Letras do alfabeto: de A a Z
• Dígitos: de 0 a 9
• Caracteres especiais: ponto de interrogação (), sublinhado (_), cifrão ($), arroba (@) e
ponto final (.).

O primeiro caractere de um identificador deve ser uma letra ou um dos caracteres especiais,
exceto o ponto final.

O Assembler trata letras maiúsculas e minúsculas como iguais; Por esse motivo, há momentos em
que se diz que o Assembler diferencia apenas maiúsculas de minúsculas, pois o compilador
converte letras minúsculas em maiúsculas na fase de compilação. Para o Assembler é o mesmo
escrever MOV, mov, Mov, mOv, etc. Todos eles significam o mesmo MOV.

O comprimento máximo de um identificador é 31 caracteres (247 desde MASM 6.0)

Exemplos de declarações de variáveis, ou seja, identificadores de dados, são os seguintes:

3.3.3. FORMATO DE DEFINIÇÃO DE DADOS.

Os dados são definidos no segmento de dados DS, e é utilizado o seguinte formato geral que
contém 3 campos, sendo o primeiro opcional:

Expressão da diretiva [data_name]

3.3.3.1. Campo de nome de dados

É um campo opcional e é o nome da variável. Sua formação é definida pelas regras dos
identificadores fornecidas posteriormente.

3.3.3.2. Campo diretivo

As diretivas que definem os diferentes tipos de dados ou tipos de variáveis são:

• DB Define variáveis de tipo de byte (1 byte)


É o único tipo que suporta definição de cadeia de caracteres
que excedam dois caracteres.
• DW Define variáveis de tipo de palavra (2 bytes)
• DD Define variáveis do tipo palavra dupla (4 bytes)
• DQ Define variáveis do tipo palavra quádrupla (8 bytes)
• DT Define variáveis do tipo dez bytes (10 bytes)

71
Machine Translated by Google

3.3.3.3. Campo de expressão

Uma expressão pode conter vários valores constantes separados por vírgulas e limitados apenas pelo
comprimento da linha.

Exemplos: X db 23h, 45, “olá amigo”, 101011b, 56o

hexadecimal decimal string binário octal


de bytes
E dw 0ADE4h, -0FFEh, 324567
ADICIONAR dw 2345h
_Y12 dd 234567h
$A dt 2345678

FORMULÁRIO CURTO DE PROGRAMAS DE FONTE

Quando descrevemos o primeiro passo: a edição, fizemos referência ao formato clássico. Os montadores
Microsoft e Borland fornecem uma forma abreviada de definir segmentos, o que economiza código e
tempo, por isso iremos descrevê-lo:

Um programa fonte tem a seguinte estrutura:

pequeno

pequeno

.model médio
compactar
grande

.stack stack_size (em bytes) .data

políticas de dados
.código
0,386

proc_name1
instrução 1
instrução 2
...
Termina
nome_1 endp
nome_2 proc
instrução 1
instrução 2
...
ret
nome_2 final
...
proc_nname
instrução 1
instrução 2
...
ret
nome_n endp
fim nome_1

72
Machine Translated by Google

Requisitos para cada modelo de memória

O modelo de memória pode ser minúsculo, pequeno, médio, compacto ou grande. Há também o modelo
enorme , que requer conhecimentos avançados para ser tratado e que não estudaremos neste livro.

Os requisitos para cada modelo são:

FORMATO CURTO

MODELO NÚMERO DE SEGMENTOS NÚMERO DE SEGMENTOS


CÓDIGO DE DADOS
ÿ

PEQUENO

1 (programas .COM: DS=CS=SS=ES)


Pequeno 1
Médio 1 mais que 1
Compactar mais de 1
Grande 1 1 mais que 1 mais de 1

A seguir resolveremos um problema usando ambos os formatos:

Exemplo 15

Escreva um programa em linguagem Assembly que escreva na tela, um número decimal sem sinal de 16 bits,
ou seja, um número cujo valor esteja no intervalo [0,65535] ou em hexdecimal [0h,FFFFh]

Solução

Antes de entrarmos na codificação, temos que resolver o problema manualmente. Já conhecemos as


capacidades básicas de um computador e temos que resolver o problema apenas usando essas capacidades
básicas.

Suponha que temos o número 375, como podemos separar seus 3 dígitos? A resposta é dividindo por 10, então
temos:

375
= 37 e o resto é 5
10
37
= 3 e o resto é 7
10
3
= 0 e o resto é 3
10

Como vemos, divido o número dado 375 e os quocientes sucessivos por 10, até que o quociente seja zero, os
restos sucessivos obtidos, que são 5, 7 e 3, acabam sendo os dígitos do número, mas ao contrário. Aí o
problema já está resolvido, fazemos várias divisões sucessivas até o quociente ser zero e salvamos o restante
na memória, utilizando a pilha.
Para repetir o procedimento várias vezes recorremos à habilidade básica de fazer comparações simples.

Não esqueçamos que para dividir dois números, o dividendo deve estar armazenado no par de registros DX:AX,
e o divisor em um registro que não seja DX nem AX. No nosso caso, como o número não pode ser maior que
FFFFh, definimos DX=0 e movemos o valor do número para

73
Machine Translated by Google

escrevemos em formato decimal no registrador AX, e escolhemos o registrador SI, para armazenar o divisor
cujo valor é 10. Então o algoritmo do pseudocódigo é o seguinte:

* Guardamos o restante da divisão por 10 na pilha


Cx=0 (contador)
DX=0
AX = número
SIM=10

Eu continuo: DIV SIM


Empurre DX

CX=CX+1 ; Eu conto os números da pilha em cx


CMP AX,0
Pule para o próximo se for maior que
*
zero, pegamos os restos da pilha e escrevemos na tela
Amostra: pop dx
Escreva dl na tela
LOOP eu mostro
Termina

Já temos o conhecimento necessário para codificar este programa em linguagem Assembly, que é o que
vamos fazer, primeiro no formato clássico (Exem15CL.ASM) e segundo no formato abreviado (Exem15AB.ASM);
e esclarecemos que utilizaremos apenas um único segmento. do código CS.

Codificação de formato clássico

; Programa Exem15cl.asm Exem15clWriteDecimalNumberClassicFormat.asm


Código do segmento
Suponha que cs:code
main proc
mov cx,0
mov dx,0
mov ax,9648 ; número para escrever 9648 mov
sim,10 div
Eu sigo: sim

push dx
add cx,1
mov dx,0
cmp ax,0
jg Eu ; pule se for ótimo, pule para o próximo se ax for maior que 0
continuo
mov ah,2 Eu mostro:
pop dx add
dl,30h

int 21h loop Eu


mostro mov ah,4ch ; se prepara para terminar às 21h;
termina código endp principal

termina final
principal

74
Machine Translated by Google

Codificação de formato curto

; Programa Exem15ab.asm Exem15ablWriteDecimalNumberAbbreviatedFormat.asm


.model

pequeno .código
principal
proc mov cx,0 mov dx,0 mov ax,9648 ; número a
ser
Eu sigo:

escrito:9648
mov si,10
div si push
dx add ; pule se for ótimo, pule para o próximo se ax for maior que 0
cx,1 mov
dx,0 cmp ax,0 jg
continue mov
ah,2

show: pop dx
add dl,30h int 21h loop show mov ah,4ch ; se
prepara para terminar às 21h;

fim principal
fim principal fim principal

A execução de ambos os programas é vista abaixo:

e em formato abreviado:

75
Machine Translated by Google

Exemplo 16

Escreva um programa em linguagem Assembly que escreva um número hexadecimal de 1 dígito na tela.

Solução

Usaremos apenas o formato abreviado, por ser mais funcional.

A tabela a seguir é a dos caracteres ASCII, 0, 1, 2, . . . 8, 9, :, ;, <, =, >, ?, @, A, B, C, D, E,


F.
Caractere ASCII Hexadecimal

0 30
31
1 32
2 33
3 3. 4

4 35
5 36
6 37
7 38
89 39
: 3A
3B
;< 3C
= 3D
3E
3F
40
41
42
43
44
45
ÿ ? @ABCDEF 46

76
Machine Translated by Google

De acordo com esta tabela, se em DL armazenamos qualquer número hexadecimal de 0, 1, 2,…,9; e somamos o valor 30h em
DL, então obtemos em DL o ASCII: “0”, “1”. "3", . . . ,

“9”. Por exemplo, para DL=8h = 10002, resulta DL=3h +30h = 38h, e se escrevermos o conteúdo de DL na tela, obteremos o
caracter “8”.

Se, por outro lado, temos DL = Dh = 11012, se somarmos 30h, temos DL=Dh + 30h = 3Dh. Se escrevermos o valor DL na tela

obtemos, conforme tabela acima, o caractere “=”, que não é a resposta correta.

Como resolvemos o problema? Observemos que existe uma faixa de 7 dados que está entre “9” e “A”, e portanto devemos
adicionar também 7 a DL, ou seja, se originalmente tínhamos DL = Dh, se não adicionarmos mais 30h, mas 37h, obtemos DL =
Dh + 37h = 44h. Agora se escrevermos o conteúdo de DL na tela obtemos “D”, que é o resultado correto.

Resumindo, se em DL houver um número hexadecimal menor ou igual a 9h, soma-se 30h e se o número for maior que 9, soma-
se 37h.

Portanto, para escrever um número hexadecimal de 1 dígito, o algoritmo a ser aplicado é:

• escrever um número hexadecimal de 1 dígito


mov dl,Número; dl = número hexadecimal
adicione dl,30h ; dl = dl + 30h

cmpdl,39h ; compare dl com 39h

jle pular; dl ÿ 39 vá pular adicione dl,7 ; dl > 39, dl


= dl + 7h

pular: escreva dl na tela

O programa completo é o seguinte, que gravamos com o nome ejem16.asm:

; Programa Exem16.asm Exem16WriteOne-DigitHexadecimalNumber.asm


.modelo pequeno
.código

processo principal

movimento dl,7

adicionar dl,30h

cmp dl,39h
jle pular
adicione dl,7

pular: mov ah,2


int 21h

mov ah,4ch ;
interna 21h; termina

terminal principal
fim principal

Os resultados da execução deste programa primeiro com DL=7 e depois com DL=0Dh são os seguintes:

77
Machine Translated by Google

Exemplo 17

Escreva um programa em linguagem Assembly que escreva um número hexadecimal de 2 dígitos


na tela.

78
Machine Translated by Google

Solução

Usando o programa Exem16.asm projetaremos um programa que escreve um número hexadecimal


de 2 dígitos.

Agora começamos a usar a instrução call procedure_name.

Suponha que temos em DL= E7h =111001112 , e o que queremos é que nosso programa escreva
a string “E7” na tela.

Fazemos o seguinte, usamos a instrução SHR DL,CL(shift right), que produz um deslocamento
dos bits CL para a direita do conteúdo de DL, da seguinte forma:

MOV CL,4
DL = E7h SHRDL,CL DL = 0Eh

11100111 00001110

e então chamamos o procedimento que escreve o valor 0Eh de DL.

A seguir usamos a instrução AND para converter uma parte de um registro em 0000.

A tabela AND é a da conjunção e é definida da seguinte maneira:

E01
000
101

Então se DL = E7h = 111001112

DL=111001112
0Fh = 000011112

E DL,0Fh = 000001112 = 07h

e novamente chamamos o procedimento que escreve 1 de hexadecimal, ou seja, o número


hexadecimal 7.

O procedimento principal do programa ejem16.asm deve ser adaptado para funcionar como um
procedimento interno, que pode ser ativado a partir de outro procedimento utilizando a instrução
de chamada.

A primeira coisa que devemos fazer é adotar como nome do procedimento um identificador que
nos lembre diretamente qual é a sua função, ou seja, o nome nos diz de forma sucinta o que o
procedimento faz. Neste caso concordamos em chamar o procedimento write_1_hexa, pois a
tarefa que ele vai executar é justamente essa: escrever um número hexadecimal de 1 dígito na
tela.

79
Machine Translated by Google

O procedimento principal do programa ejem16.asm, já convertido como procedimento interno, é o seguinte, podendo ser utilizado
por quem precisar (lembre-se do conceito de reuso):

procedimento write_1_hexa
machado
empurrar dx

adicionar dl,30h

cmp dl,39h
jle pular
adicione dl,7

saltar:

movimento ah,2

int 21h

pop dx
machado pop

ret

write_1_decimal endp

Além da mudança de nome, a instrução mov dl,7 foi excluída e duas instruções push e duas instruções pop foram adicionadas;
e no final do procedimento uma instrução ret (return). As instruções push e pop têm a função de retornar todos os registros que
são utilizados dentro do procedimento, tal como foram recebidos. Para o programador que chama um procedimento, este deve
funcionar como uma caixa preta e não deve em hipótese alguma alterar os valores dos registradores. A instrução ret (return em
inglês -retorna em espanhol-), permite retornar à instrução que segue a instrução de chamada.

Abaixo damos o programa completo, que foi gravado com o nome Exem17.asm, e a tela com os resultados da execução deste
programa

; Programa Exem17.asm Exem17WriteTwo-DigitHexadecimalNumber.asm

.modelo pequeno
.código

processo principal
movdl,0E7h
empurre dx
movimento cl,4

shr dl,cl
chame write_1_hexa

pop dx
e dl,0Fh
chame write_1_hexa
movimento ah,4 canais

int 21h

endp principal
write_1_hexa proc
machado
empurrar

dx adicionar dl,30h

80
Machine Translated by Google

cmp dl,39h
jle pular
adicione dl,7
saltar:
movimento ah,2

int 21h
pop dx
machado pop

ret
write_1_hexa final
fim principal

Exemplo 18

Escreva um programa em linguagem Assembly que escreva um número hexadecimal de 4 dígitos na


tela.

Solução

Continuamos a usar a sétima capacidade básica dos computadores: a reutilização. Para escrever um
número 4 hexadecimal, chamaremos duas vezes o procedimento write_2_hexas convenientemente
adaptado.

A seguir está um programa com seu respectivo segmento de dados, para declarar o nome da variável
number de tamanho 16 bits, ou seja, do tipo dw (define word) que descrevemos no parágrafo “3.2.3.
formato de definição de dados”. Também neste programa aparece a diretiva .386 , que é válida para
processadores 80386 e posteriores, e que utilizamos porque permite o uso das instruções pushA, que
equivale às instruções push AX, push BX. . . , pressione SIM, pressione

81
Machine Translated by Google

DI-, e a instrução popA -que é equivalente às instruções pop DI, pop SI, . . . , pop BX, pop AX-.
Usar essas instruções nos permite salvar o código. Também utilizamos a diretiva ptr , que estudaremos com
mais detalhes posteriormente, que permite mover um dado numérico para o meio registro DL de 1 byte de
tamanho, a partir da variável número que tem 2 bytes.

; Programa Exem18.asm Exem18WriteHexadecimalNumberOfFourDigits.asm .model


small .data

number dw 0B5E4h ; dados para escrever na tela .code


.386
main
proc mov
ax,@data mov
ds,ax mov
dl,byte ptr number+1 ; dl = B5h chamada
write_2_hexas mov dl,
byte número ptr ; dl = E4h chamada
writes_2_hexas mov
ah,4ch int
21h
main endp
writes_2_hexas proc; Seu parâmetro é medidor para DL.
pushA
push dx
mov cl,4
shr dl,cl
chamada writes_1_hexa
pop dx
e dl,0Fh
chamada writes_1_hexa
popA
ret
write_2_hexas endp
write_1_hexa proc
pushA
add dl,30h
cmp dl,39h
jle jump
add dl,7
jump:
mov ah,2
int 21h
popA
ret
write_1_hexa endp end
main

O programa anterior é gravado com o nome Ejem18.asm e o resultado de sua montagem, vinculação e
execução pode ser visto na tela a seguir:

82
Machine Translated by Google

83
Machine Translated by Google

CAPÍTULO IV PROGRAMAS .EXE vs PROGRAMAS .COM

4.1 Como o DOS executa programas

No ambiente MS-DOS existem três tipos diferentes de programas executáveis a partir da linha de
comando: aqueles com extensão .COM (de COMmand), aqueles com extensão .EXE (de EXEcutable)
e aqueles com extensão .BAT (de BATch ). Este último não é mais usado, mas ainda é útil. Agora
vamos nos concentrar em estudar as diferenças entre os programas .COM e :EXE e também as
semelhanças.

Se você tiver três arquivos com o mesmo nome, tente, mas com extensões diferentes .COM, .EXE
e .BAT, a ordem de prioridade na execução é:

teste.COM
teste.EXE
teste.BAT

Ou seja, se todos os três estiverem presentes e a palavra test for inserida na linha de comando do
DOS, test.COM será executado; se apenas test:EXE e test.BAT estiverem presentes, test.EXE será
executado; e se houver apenas test.BAT, este é o que é executado; e se nenhum dos três estiver
presente, o DOS grava uma mensagem de erro, como esta: “comando ou nome de arquivo inválido”.

O prefixo do segmento do programa (PSP)

O PSP (Program Segment Prefix) é uma estrutura usada para controlar certos aspectos do programa.
Possui comprimento de 256 bytes e está sempre localizado nos primeiros 256 bytes do segmento
onde o programa é carregado. Informações importantes são armazenadas nesta estrutura, o que é útil
para programação de sistemas e programação de computadores, que é um trabalho muito diferente
de criar programas aplicativos. A estrutura do PSP é detalhada abaixo. O PSP entre outros, por
exemplo, contém uma tabela manipuladora de arquivos, que é utilizada quando você precisa de mais
de 20 arquivos abertos ao mesmo tempo.

Programa carregador do sistema

Dos fornece suporte para carregamento de memória para dois tipos de programas executáveis: .COM
e .EXE. Um programa .COM consiste em um único segmento contendo código, dados e a pilha. Se
você precisar de um pequeno programa utilitário ou de um programa residente na memória (um
programa que fica permanentemente instalado e disponível enquanto outros programas estão em
execução), você escreve um programa .COM. Um programa .EXE consiste em códigos, dados e
segmentos de pilha separados e é o método usado para a maioria dos programas sérios.

4.2. Programa do tipo .COM

Os programas .COM lembram a época em que predominava o sistema operacional CP/M (que
funcionava com processadores de 8 bits, precursores do 8086 e de outras famílias). Este sistema
operacional usava a extensão COMmand para sugerir que se tratava de um programa executável (não
existiam programas com a extensão .EXE e um programa executável só poderia ser diferenciado dos
demais se tivesse a extensão .COM).

84
Machine Translated by Google

Um tipo de programa .COM é armazenado no disco exatamente como será carregado na memória
para execução. Dito de outra forma, o programa é armazenado no disco como uma imagem exata do
que será carregado na memória e executado.

O PSP de um programa .COM é carregado no deslocamento 0 a FFh e o programa .COM inicia no


deslocamento 100h. Todos os programas em linguagem de máquina são .COM.
O comprimento de um programa .COM é restrito a 64 Kbytes.

Um programa .COM possui um único segmento físico e quatro segmentos lógicos: CS, DS, SS e ES,
e todos possuem o mesmo endereço. No final do segmento uma palavra (16 bits) é usada como pilha.
Portanto, o comprimento de um programa .COM é, na verdade, 65.536 – 256 – 2 = 65.278 bytes.
Os 256 são do PSP e os 2 são da pilha.

Inicializando um programa .COM

Quando o DOS carrega um programa .COM para execução, ele inicializa automaticamente todos os
registradores de segmento com o endereço PSP. Portanto, não é necessário programar o seu
carregamento. Como o endereçamento começa com um deslocamento de 100H bytes desde o início
do PSP, uma diretiva ORG precisa ser codificada como ORG 100h, imediatamente após o segmento
ou a instrução .CODE. A diretiva ORG (Origem) diz ao montador para iniciar a geração do código
objeto em um deslocamento de 100h bytes após o início do PSP, onde o programa .COM real começa.

A pilha .COM

O registro SP que aponta para o topo da pilha é inicializado com o valor 0FFFEh e o MS-DOS
armazena um zero na pilha antes de passar o controle para o programa .COM. A pilha inicializada
com zero deve atuar como um deslocamento para o IP, se RET for usado para encerrar a execução
do programa. Se o programa .COM for grande ou se a memória for limitada, deve-se tomar cuidado
ao enviar palavras para a pilha.

Não se deve esquecer que a pilha faz parte da memória. Diremos também que existem duas formas
de recuperar dados da pilha: de forma destrutiva e não destrutiva, que estudaremos mais adiante.

Conversão para formato .COM

Se o seu programa já estiver escrito no formato .EXE, você poderá usar um editor para converter as
instruções para o formato .COM. Os formatos de codificação MASM e TASM para programas .COM
são idênticos, embora seus métodos de conversão sejam diferentes. Quando a conversão .COM for
concluída, você poderá excluir os arquivos .OBJ e .EXE.

Aqui estão os passos para converter um programa para Microsoft e Borland, assumindo que o
programa fonte denominado Test.ASM já foi criado com um editor

Arquivo MASM gerado Arquivo TASM gerado

Teste MASM Teste.OBJ Teste TASM Teste.OBJ

85
Machine Translated by Google

Teste de LIGAÇÃO; Teste.EXE Teste TLINK /T Test.COM

Teste EXE2BIN Test.COM

4.3 Programas .EXE

Por sua vez, os programas .EXE (contração da palavra EXEcutable) podem ter quatro tipos
diferentes de segmentos físicos: CS, DS, SS e ES ao mesmo tempo (Ver o programa TRUEBA.asm,
no capítulo III).

Quando o DOS carrega um programa .EXE do disco para a memória para execução, ele constrói
um PSP de 256 bytes (100h) com um limite de parágrafo de memória interna disponível e armazena
o programa imediatamente após o limite. Então o DOS faz o seguinte:

• Carregue o endereço do segmento de código no CS

• Carregar o endereço da pilha no SS; e

• Carregue o endereço PSP nos registros DS e ES

O carregador DOS inicializa os registros CS:IP e SS:IP, mas não os registros DS e ES. Entretanto,
seu programa geralmente precisa do endereço do segmento de dados no DS (e com
frequência também no ES). Como consequência, é necessário inicializar o DS com o endereço do
segmento de dados, com a instrução mov. Consulte o programa Test.asm na seção 3.2 Programa
Fonte.

Os programas .EXE podem ser tão grandes quanto a memória instalada permitir. Outra vantagem
é que são relocáveis; Isso permite que mais de um programa seja carregado na memória usando
todo o espaço disponível.

A desvantagem dos arquivos .EXE é o tamanho do cabeçalho adicionado pelo vinculador para
possibilitar a realocação.

Por outro lado, já sabemos que um programa .COM possui um único segmento físico. Quando um
programa em linguagem assembly não é muito grande, um arquivo .COM é mais que suficiente
para incluir tudo relacionado a dados, instruções e manipulações de pilha. Ao contrário do
arquivo .EXE, o arquivo .COM não é relocável e deve começar no endereço 100h. A vantagem de
um arquivo .COM sobre um arquivo .EXE é que ele reduzirá significativamente o tamanho do
arquivo executável.

EXEMPLO DE UM PROGRAMA .COM

Exemplo 19

Converta o seguinte programa Ejem19EX.asm em um programa .COM, que é um programa .EXE


e que possui 3 segmentos físicos (o segmento de pilha não é usado):

86
Machine Translated by Google

; Programa Exem19EX.asm Exem19EXProgramEXEAConvertBinarySum.asm ; O segmento de


código do programa
EXE assume cs:
código, ds: dados, ss: pilha proc principal
mov sim,
dados mov ds,
sim mov
ah, 9 leitura
dx, quadro int
21h
mov bx, x
chamada

binária leitura
dx,

sigmas int
21h mov bx ,y

chama leitura
binária
dx,sigigual
int 21h
mov bx,x
adiciona bx,y
chama
leitura binária
dx,jumps

int 21h mov


ah,4ch int 21h
main
endp
binário
proc push
ax push bx
push cx
push
dx mov
cx,16 mov
ah ,2 siga:
rcl bx,1 mov dl,0 adc dl,30h int 21h

loop eu
continuo
pop dx
pop cx
pop bx

pop ax ret
binário endp código termina

segmento de
dados x dw 13456

e dw 7685
frame db 12 dup (0ah) db 15
dup (20h),36 dup ("*"),0ah,0dh db 15 dup
(20h),"* OPERAÇÃO DE SOMA BINÁRIA *",0ah,0dh db 15 dup ( 20h),36 dup
("*"),0ah,0ah,0ah,0dh, 5 dup (20h),"$" sigmas db " + $" = $" sigigual db "
salta db 9 dup (0ah),"
dados terminam $ "os

pilha de segmentos
db 10 dup ("STACK")
pilha
termina final principal

87
Machine Translated by Google

A conversão consiste nas seguintes etapas:

1 0 ) Excluímos o segmento da pilha, eliminando as seguintes instruções:

pilha segmento pilha


db 10 dup ('STACK')
pilha termina

2 0 ) Usamos a diretiva GROUP, que é usada para agrupar dois ou mais segmentos lógicos em um
apenas segmento físico. A sintaxe desta diretiva é:

Nome do GRUPO nome_do_segmento1 [, nome_do_segmento2...]

No nosso caso, como nome usamos o identificador all, que pode ser qualquer diferente, basta começar com
uma letra. A seguinte diretiva deve ser colocada antes da diretiva de código de segmento:

todos os códigos e dados do GRUPO

e isso nos obriga a modificar a diretiva assume da seguinte maneira:

assumir: cs:todos, ds:todos

3 0 ) Antes da diretiva proc principal, colocamos a diretiva: org 100h, porque todo programa .COM começa no
deslocamento 100h.

4 0 ) Eliminamos as instruções:

mov machado, dados

mov ds, machado

porque não são mais necessários, pois o programa .COM possui apenas um segmento.

5 0 ) Eliminamos as instruções mov ah,4ch e int 21h, e em seu lugar colocamos a instrução: int 20h

que os programas .COM usam, para passar o controle para o DOS

Depois que essas alterações forem feitas, o programa .COM ficará assim:

; Programa Exem19.asm Exem19ProgramCOMBinarySum.asm ;


Programa COM
grupo todo o código,
segmento de
código de dados assume
cs:all,
ds:all org
100h
main proc
mov
ah,9 read
dx, int frame 21h mov bx,x call binary

88
Machine Translated by Google

(Continuação)

leia dx,sigmas
int 21h
mov bx,y
chame binário
leia dx,sigigual
int 21h
mov bx,x
adicione
bx,y chame
binário leia

dx,jumps
int 21h int
20h
main
endp
binário
proc push
ax push
bx push cx
push dx
mov cx,16
mov ah,2 siga: rcl bx,1 mov dl,0 adc dl,30h int 21h
loop eu

continuo pop
dx pop cx
pop bx pop ax
ret binário
endp
código termina segmento
de dados x dw 13456 e dw 7685
quadro db 12 dup (0ah) db 15 dup (20h),36 dup ("*"),0ah,0dh db 15
dup (20h),"* OPERAÇÃO DE SOMA BINÁRIA *",0ah,0dh db 15
(20h),36 dup dup
("*"),0ah,0ah,0ah,0dh,
5 dup (20h),"$" + $"
sigmas db
" sigigual db " = $" salta db 9 dup (0ah),"$" dados terminam final principal

MONTAGEM, COMPILAÇÃO E CONVERSÃO

Os comandos para montagem, vinculação e conversão para .COM são os seguintes:

TASM ahem19 <enter>

LIGAÇÃO ahem19; <entrar>

EXE2BIN ahem19 ahem19.com <enter>

Para executar o programa digite o comando:

Ahem19 <enter>

89
Machine Translated by Google

O resultado da execução deste programa é o seguinte:

VERSÃO SIMPLIFICADA

A versão simplificada do programa .COM é a seguinte:

; Versão simplificada do
programa .COM; Programa Exem19VS.asm Exem19VSProgramCOMBinarySum.asm

.model
tiny

.386 .data
BINARY
*",0ah,0dh db 15 dup
(20h),36 dup ("*"),0ah,0ah,0ah,0dh,
5 dup (20h),"$" + $" sigmas db " sigigual db " = $ " salta db 9
dup (0ah),"$" .code org 100h main proc mov ah,9 read dx,
frame int
21h mov bx,x call
binary read dx,sigmas int
21h
mov bx,
y chama
leitura
binária

dx,sigigual
int 21h mov
bx,x
adiciona
bx,y chama
leitura binária

dx,jumps
int 21h
int 20h
main endp

; encerrar o programa .COM

90
Machine Translated by Google

(continuação)

binário proc
pushA
mov cx,16
mov ah,2
siga: rcl bx,1
mov dl,0
adc dl,30h
int 21h
loop siga
popA
ret
binário endp
fim principal

91
Machine Translated by Google

CAPÍTULO V PROCEDIMENTOS vs MACROS

5.1 Programação modular

A ideia de programação modular é produto do desenvolvimento de métodos teóricos para design


de programas. Basicamente, a programação modular consiste em dividir um programa em
unidades menores, que podem ser testadas separadamente e depois integradas em um programa
que atenda aos objetivos de projeto originalmente propostos.
Esta definição nada diz sobre o tamanho dos módulos, nem indica quais critérios devem ser
utilizados para defini-lo, seja em termos abstratos ou em termos de número de linhas de código.
Felizmente, foram feitos esforços consideráveis para responder a estas questões. Cada módulo
deve realizar uma única tarefa que deve ser independente daquelas realizadas pelos demais
módulos e contida na sua totalidade, com uma única entrada e uma única saída. Na linguagem
assembly, a programação modular é feita por procedimentos. Estes últimos já foram estudados
em vários programas e, em muitos casos, constituem uma boa aproximação para pequenas
tarefas ou partes maiores de uma tarefa.
5.2 Procedimentos

Até agora, os segmentos de código consistiam apenas em procedimentos próximos, codificados


como:

PROCEDURE_NAME PROC
...
...

RET
ENDP PROCEDURE_NAME

Neste caso, a diretiva PROC informa ao sistema que o endereço indicado é o ponto de entrada
para a execução do programa, enquanto a diretiva ENDP define o final do procedimento.

Entretanto, um segmento de código pode ter qualquer número de procedimentos, todos


diferenciados por PROC e ENDP. Um procedimento (também sub-rotina ou módulo) ativado por
uma instrução CALL é uma seção de código que executa uma tarefa claramente definida (como
colocar o cursor em uma determinada posição na tela ou obter entrada do teclado).

Organizar um programa em procedimentos proporciona os seguintes benefícios:

• Reduz a quantidade de código, já que o procedimento comum pode ser chamado diversas
vezes e de qualquer lugar no segmento de código
• Fortalece a melhor organização do programa.
• Facilita a depuração do programa, pois os erros podem ser mais isolados
clareza.
• Auxilia na manutenção progressiva dos programas, uma vez que os procedimentos são
rapidamente identificado para modificação.

A diretiva PROC

A diretriz PROC (PROCedure ou procedimento em espanhol) tem o seguinte formato:

PROC procedimento_nome [atributo]

92
Machine Translated by Google

Indica o início do procedimento “nome_procedimento”, que consiste em um bloco de instruções utilizado


para realizar uma tarefa específica e que pode ser invocado a partir de vários pontos do programa.

Um procedimento pode ser executado pela instrução CALL.

O atributo pode ser PRÓXIMO – que é o padrão, ou seja, se o atributo não for informado – ou FAR.

Um procedimento NEAR só pode ser chamado a partir do segmento definido.

Ao chamar um procedimento NEAR, apenas o offset (valor IP) da instrução seguinte ao CALL é salvo na
pilha, que é recuperado ao retornar de um procedimento com a instrução RET.

Um procedimento FAR pode ser chamado de qualquer segmento. Ao chamar um procedimento FAR, o
segmento (valor CS) e o deslocamento (valor IP) são armazenados na pilha e recuperados com a
instrução RET.

Diretiva PÚBLICA

É possível desenvolver um programa que consiste em um programa principal vinculado a um ou mais


subprogramas montados separadamente. Assim, se quisermos que o procedimento ou dado ou rótulo
seja acessível a partir de um ou mais procedimentos PROC montados separadamente com o linker
LINK.EXE, deverá ser utilizada a diretiva PUBLIC, que possui o seguinte formato:

Nome PÚBLICO [, . . . ]

Onde o nome pode estar:

• O nome de um procedimento
• O nome de uma variável
• Uma etiqueta

(1) Exemplo, se quisermos que o procedimento ADD seja acessível a partir de outros módulos separados,
escreveremos:

ADIÇÃO PÚBLICA

ADICIONAR PROC [PERTO ou DISTANTE]; Início do procedimento


...
RET
ADICIONAR PEND; Fim do procedimento

Neste caso, o módulo ativador deve declarar que o módulo SUMAR é externo, utilizando a diretiva
EXTRN (EXTERN ou externo em espanhol), que identifica os elementos que foram declarados públicos
em outro módulo separado.

ADIÇÃO EXTRN:[PERTO ou DISTANTE]

(2) Se quisermos que uma variável X, do tipo byte, seja acessível a partir de um módulo separado,
escreveremos:

PÚBLICO
X BD 34h,567

O que requer a diretiva EXTRN no módulo ativador no seguinte formato:


EXTRN X:BYTE

93
Machine Translated by Google

Para outros tipos de variáveis são utilizados: WORD para tipo DW (2 bytes), DWORD (4 bytes) para
tipo DD.

Instruções CALL e RET

A instrução CALL transfere o controle para um procedimento chamado e a instrução RET retorna do
procedimento chamado para o procedimento original que fez a chamada. RET deve ser a última
instrução em um procedimento chamado.

Parâmetros para passar dados para um procedimento PROC.

Quando um procedimento é ativado ou chamado, é necessário passar dados para ele e o


procedimento também deve retornar dados. É uma troca de informações

Tal como as pessoas podem comunicar e trocar informações, podemos fazer com que os programas
comuniquem e troquem informações.

Um exemplo prático de comunicação é aquela que ocorre entre professor e aluno, no processo de
ensino-aprendizagem. O professor envia uma mensagem ao aluno, o aluno recebe a mensagem e
deve enviar uma mensagem de resposta, ou seja, deve ocorrer um ciclo fechado de troca de
informações: professor-aluno e aluno-professor; tudo isso para que o processo de ensino-
aprendizagem seja bem-sucedido. Isso pode ser visto na figura a seguir:

dados

professor estudante

dados

Da mesma forma, dois programas podem trocar informações. Em vez do professor podemos
imaginar um programa ativador - que atua como mestre - e em vez do aluno podemos imaginar
outro programa ativado - que atua como escravo - ambos algoritmos ,

94
Machine Translated by Google

eles trocam dados. O processo de troca de dados é sempre iniciado pelo algoritmo de ativação, daí o
seu status de mestre. Concordamos que chamaremos o programa ativado de subprograma (ou
também rotina ou módulo).

DADOS

programa ativador programa ativado


(amor) (escravo)

DADOS

Vamos estudar os miniaplicativos em detalhes.

Nas linguagens de programação de alto nível existem dois tipos de subprogramas. Eles são chamados
de miniaplicativos de procedimento e miniaplicativos de função. Existem mais semelhanças do
que diferenças entre os dois tipos e ambos podem fazer a mesma tarefa sem grandes alterações e,
portanto, a escolha depende muito das preferências do programador. Poderíamos afirmar que cada
programa de função possui um programa de procedimento equivalente e vice-versa. Mas há situações
em que um programa de função é mais adequado que seu programa de procedimento equivalente,
porque economiza linhas de código.

Algumas linguagens trabalham com os dois tipos de subprogramas – a maioria das linguagens estão
nesta categoria – outras, porém, como a linguagem C, só funcionam com subprogramas de função e
este arcabouço filosófico para a concepção de programação dá a esta linguagem uma muito poder.
Por outro lado, a linguagem Assembly só funciona com subprogramas procedurais, que são os que
descrevemos.

SUBPROGRAMAS DE PROCEDIMENTO

Antes de dar outro exemplo, seria apropriado resumir as ideias desenvolvidas até agora. Isso pode ser
ilustrado examinando a estrutura do seguinte esquema:

pn = um NOME DO PROCEDIMENTO (p1,p2,p3,...,pr; pr+1,...,,pn)


* ...
Programa principal
p2=a2
p1=a1 p1pppp

NOME DA CHAMADA (a1, a2, a3,...,an)


ÿÿÿ

ar+1=pr+1, ar+2=pr+2, ÿÿÿ ,an=pn

,
retorna
Instrução que segue a instrução CALL

Em uma linguagem de alto nível, quando a instrução Call (ou equivalente) é executada, a sequência
de eventos é a seguinte:

1. Os valores dos argumentos a1, a2, a3, ÿÿÿ ,an são atribuídos aos parâmetros p1,p2,p3, ÿÿÿ
, pág.

2. O controle é passado para a primeira instrução executável do procedimento.

95
Machine Translated by Google

Quando uma instrução de retorno (RET em Assembler) é executada (pode haver vários RETs), a
sequência de eventos é esta:

1. Somente os valores dos parâmetros de referência pr+1,pr+2, ÿÿÿ ,pn são atribuídos aos argumentos
de referência ar+1, ar+2, ÿÿÿ ,an ...

2. O controle é passado para a instrução após a instrução CALL

Observações

• Naturalmente o número de argumentos deve ser o mesmo na lista de argumentos e na lista de


parâmetros. • Não
só isso, eles também devem ser do mesmo tipo.

A linguagem assembly para passagem de parâmetros utiliza registros ou variáveis de tipo público e/ou
também pilha.

EXEMPLOS DE PROGRAMAÇÃO MODULAR.

A seguir desenharemos procedimentos externos, ou seja, aqueles que estão em um arquivo separado
e que estão vinculados através do programa LINK:EXE. Não devemos esquecer que o assembler (seja
MASM.EXE ou TASM.EXE) gera um programa objeto, que embora esteja em linguagem de máquina,
ainda não é executável, pois faltam outros componentes. É o utilitário LINK.EXE que gera o que
chamamos de programa relocável, adicionando um cabeçalho adicional ao arquivo .OBJ já gerado pelo
montador. Com isso, o vinculador habilita o programa para que o sistema operacional possa colocá-lo
em qualquer memória disponível.

Além disso, o programa LINK.EXE permite montar diversas rotinas que foram construídas em arquivos
separados, conforme estudaremos.

5.3 Geração do programa PROCS.ASM com módulos objeto

Escreva dois procedimentos externos, (1) o primeiro denominado clear, que clareia a tela, e (2) o
segundo gotoxy para posicionar o cursor na tela. Esses dois procedimentos devem ser registrados no
arquivo PROCS.ASM

De acordo com o manual de interrupção dos processadores da família Intel X'86, para limpar a tela ou
posicionar o cursor devemos utilizar a interrupção do BIOS: int 10h, associada à tela.

(1) Para limpar a tela, usaremos a função AH=6, que rola a página ativa para cima. São necessárias as
seguintes entradas , ou seja, devem ser fornecidas antes de ativar a interrupção:

AL = número de linhas. As linhas na parte inferior são apagadas. Se AL=0 toda a janela (tela) é
excluída.
CH = linha do canto superior esquerdo
CL = Coluna do canto superior esquerdo
DH = linha do canto inferior direito
DL = Coluna do canto inferior direito
BH = Atributo para usar nos caracteres da linha em branco

96
Machine Translated by Google

Sendo o atributo

0 Preto
Azul
1 Verde
2 Azul-Verde (ciano)
3 Vermelho

4 Magenta
5 Marrom
67 Branco

De acordo com esses requisitos, o código do procedimento claro para clarear a tela para que os caracteres
sejam desenhados em branco (atributo bh=7), sobre fundo preto, que é a cor padrão da tela, é o seguinte:

; Procedimento para limpar tela, fundo branco


público claro
limpar proc próximo; nenhum parâmetro necessário
empurrarA

mover para,0.

movimento cx,0

mov dh,24 entradas de função AH=6


mov dl,79
movimento bh,7

mov ah,6 ; solicitação de função de limpeza;


Int 10h prossiga para limpar
popA
ret
limpar final

(2) Para posicionar o cursor usaremos a função AH=2, que requer as seguintes entradas:

DH = Linha (0 – 24)
DL = Coluna (0-79)
BH = Número da página. A tela tem quatro páginas disponíveis
que são identificados com os números 0,1,2 e 3, para o modo normal de 80 colunas. Por
padrão, a página 0 é usada.

Neste caso necessitamos de dois parâmetros, o DH para a linha e o DL para a coluna. O procedimento
resultante é:

; Procedimento para posicionar o cursor


gotoxi público
gotoxy proc próximo; Parâmetros DH = linha DL = coluna
empurrarA

mov bh,0
mov ah,2 ; solicitação para posicionar o cursor
int 10h ; posiciona-o
popA
ret
gotoxy endp

97
Machine Translated by Google

Embora esses procedimentos possam ser salvos separadamente em arquivos próprios, para simplicidade de
operação, iremos armazená-los em um único arquivo, que chamaremos de PROCS.ASM.
Posteriormente adicionaremos, um por um, novos procedimentos a este arquivo que também será público, e nos
ajudará a construir uma biblioteca de módulos de objetos. Quando reunidos em um único arquivo denominado
PROCS.ASM, independentemente da ordem em que são colocados, a disposição em que permanecem é a seguinte:

; Programa PROCS.asm PROCSProceduresClearGotoxy.asm


.modelo pequeno

0,386

.código

; Procedimento para limpar tela, fundo branco

público claro

limpar proc próximo; nenhum parâmetro necessário

empurrarA

mover para,0.

movimento cx,0

mov dh,24

mov dl,79

movimento bh,7

mov ah,6 Int ; solicitação de função de limpeza; prossiga


10h popA para limpar

ret

limpar final;

Procedimento para posicionar o cursor

gotoxi público

gotoxy proc próximo; Parâmetros DH = linha DL = coluna


empurrarA

mov bh,0

mov ah,2
dentro das 10h

popa
ret

gotoxy endp
fim

Este programa é apenas montado, pois está interessado apenas em gerar o módulo objeto PROCS.OBJ, que será
suficiente para nossos propósitos. Por este motivo apenas o comando é usado:

PROCESSOS TASM <enter>

O resultado da montagem do programa fonte PROCS.ASM é o seguinte:

98
Machine Translated by Google

Exemplo 20

Escreva o programa Ejem08.com, do exemplo 8, que lê uma string do teclado, armazena-a na memória e depois exibe essa
string na tela.

O programa deve ser interativo e deve utilizar as rotinas clear para limpar a tela e gotoxy para posicionar as mensagens. O
layout da tela é o seguinte:

Digite uma string: estou aprendendo Assembler


Leitura de string : Estou aprendendo Assembly

Quer continuar (s/n)?:

Como a lógica do programa já foi explicada detalhadamente ao projetar o algoritmo do exemplo 8, nos concentraremos nas
mudanças que devem ser feitas para usar as rotinas clear e gotoxy e para tornar o programa interativo. As alterações no
programa original e as novas instruções foram escritas em negrito para que possam ser apreciadas.

; Programa Ejem20.asm Ejem20ReadsAStringAndWritesItOnScreen.asm


.modelo pequeno
.dados

mensagem1 db “Digite uma string: $”


mensagem2 db “String lida :$”

mensagem3 db “Deseja continuar (s/n)?: $”


string db 50,”$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$” .código

extrn claro:perto, gotoxy:perto


processo principal

mov machado,@dados

mov ds, machado

Eu sigo:
ligar claro
movimento dh,12

movimento dl,14

ligue para
gotoxy lea dx,
mensagem1 mov ah,9
int 21h

leia dx, string


mov ah,0Ah
int 21h

mov ah,2
mov dl,0Ah int
21h mov

dh,13
movimento dl,14

ligue para
gotoxy lea dx, mensagem2

99
Machine Translated by Google

mov ah,9
int 21h
ler dx,string
adicionar
dx,2 mov
ah,9 int
21h mov
dh,15 mov
dl,14 chamar
gotoxy ler

dx,mensagem3
mov
ah,9 int 21h
mov ah,1 int 21h cmp al,” s” hee eu continuo mov ah, 4ch int 21h principal endp final principal

Este programa é montado, vinculado e executado, com os seguintes comandos:

TASM ahem20 <enter>


LINK ahem20 PROCESSOS; <entrar>
Ahem20 <enter>

O resultado de sua execução é o seguinte:

5.4 Uma alternativa: macros

O mesmo que pode ser feito com os procedimentos PROC pode ser conseguido de uma forma muito diferente,
utilizando a directiva macro.

Uma macro é um bloco de instruções em linguagem Assembly que usa uma série de parâmetros.

100
Machine Translated by Google

O formato da diretiva macro é o seguinte:

Nome MACRO lista_parâmetros


...
instruções em linguagem assembly
...
ENDM

A primeira diretiva, que é o cabeçalho da macro, começa com um identificador que é o nome da macro e
termina com uma lista de parâmetros separados por vírgulas. O final da macro é indicado pela diretiva ENDM.
Ambas as directivas incluem as frases
que constituem o corpo da macro.

Os parâmetros devem ser incluídos nas instruções da macro.

A invocação de uma macro consiste em especificar o nome da macro, juntamente com os argumentos, que
na maioria dos casos são iguais em número e tipo aos parâmetros da macro, pois a macro é muito flexível
nos casos em que não atende a isso doença:

nome_da_macro lista_de_argumentos

Cada argumento corresponde a cada parâmetro e quando a macro é invocada faz com que ela seja incluída
no bloco de instruções que constituem o corpo da máquina, substituindo os parâmetros da macro pelos
argumentos. Este processo é chamado de “macroexpansão”.
Na lista do programa fonte montado, as linhas geradas são indicadas pelo sinal “+” na coluna 31. A coluna 32
fica em branco. A coluna 33 corresponde à coluna 1 do módulo de origem.

Nós fazemos as seguintes observações:

• Macros podem existir sem parâmetros

• O número de argumentos em uma invocação de macro não precisa corresponder ao número de


parâmetros. Se houver mais argumentos do que parâmetros, os argumentos extras serão ignorados.
Se houver menos argumentos do que parâmetros, os parâmetros ausentes serão convertidos em
nulos.

Exemplos:

*
(1) Macro para calcular Z = X E

PRODUTO MACRO X,Y,Z1,Z2

mov ; machado=X

machado,X ; sim=S
*
mov ; DX:AX=X E
si,Y mul si ; Z1=dx
mov Z1,dx mov Z2,ax ; Z2=eixo
ENDM

Um programa de ativação para multiplicar 0FFFFh x =FFFFh é o seguinte

101
Machine Translated by Google

.modelo pequeno

.dados

parte superior dw?


parte_inferior dw ?
.código

microproduto X,Y,Z1,Z2
mov machado,X ; machado=X

mov se,Y ; sim=S


*
sim; DX:AX=X move Z1,dx ; Z1=dx E

mov Z2,ax ; Z2=eixo

fim

processo principal

mov machado,@dados

mov ds,ax
PRODUTO 0FFFFh,0FFFFh,parte_alta,parte_baixa mov ah,4ch

Internamente 21h

terminal principal
fim

A expansão resultante desta última instrução é:

mov machado,0FFFFh
mov sim,0FFFFh
mul sim

mov parte_superior,dx
mov parte_inferior,machado

Se o programa for executado na parte superior o valor FFFEh é armazenado e na parte inferior 0001h é armazenado.

(2) A seguir está uma macro que quando ativada, escreve o caracter encontrado no identificador um quantas vezes for
indicado pelo valor de dois

lista de macros um, dois, três


mov dl, um
mov cx, dois
movimento ah,2

três: int 21h

adicione dl,1

laço três
fim

Por exemplo, se você executar o seguinte programa:

102
Machine Translated by Google

; Programa TestMC.asm TestMCTestAMacro.asm

lista de macro um,dois,três


mov dl,um
mov cx,dois
mov ah,2
três: int 21h
add dl,1
loop três
endm
miguel segmento
assumir cs:Miguel
lista de
proc principal
'A',10,sigo lista 'K'
,11,mov

contínuo
ah,4ch int
21h principal endp miguel termina final principal

Ocorrem duas expansões, que são:

mov dl,”A”
mov cx,10
mov ah,2
continuo: int
21h add
dl,1 loop continuo

mov dl,”K”
mov cx,11
mov ah,2
contínuo: int 21h
add dl,1
loop contínuo

Vamos armazenar o programa com o nome TestMC.asm, e se o programa for executado ele escreve a string
ABCDEFGHIJ seguida da string KLMNOPQRSTU, como pode ser visto na tela a seguir

103
Machine Translated by Google

Assim como começamos a construir um arquivo de procedimento PROCS.ASM, que posteriormente converteremos em uma biblioteca,

podemos criar uma biblioteca de macros. Para usar esta biblioteca de macros, a diretiva INCLUDE é usada da seguinte maneira:

INCLUIR C:\MACROS.LIB

Sendo MACROS.LIB, o arquivo que contém as macros. Vejamos um exemplo:

Exemplo 21

O programa abaixo, chamado PrPROCS.ASM, que lê um número como uma string e o escreve de trás para frente, utiliza os

procedimentos clear e gotoxy . É solicitado:

(1) Escreva os procedimentos clear e gotoxy, como macros, usando os mesmos nomes, e

salve-os em um arquivo chamado macros.lib

(2) Modifique o programa PrPROCS.ASM, e já modificado, salve-o com o nome Exem21.ASM, para que ao invés de utilizar os

procedimentos utilize a biblioteca macros.lib, criada na parte (1).

; Programa PrPROCS.asm PrPROCSTestProceduresClearGotoxy.asm


.modelo pequeno

0,386

.dados

título1 db "*********************************************** *************************$"


"*
título2 banco de dados Arquivo Procs:PPROCS.ASM *$" *$"
"*
título3 banco de dados
Testando os módulos clear e gotoxy *$"
"*
título4 banco de dados
Programa: PrPROCS.asm Lê um
"*
título5 banco de dados
número como uma string e o escreve ao contrário *$"
title6 db "*********************************************** *************************$"

message1 db "Digite um número message2 :$"

db "Número lido de trás para frente: $"

pergunta do banco de dados "Deseja continuar (s/n)? : $"


banco de dados número 255

.código

extrn claro:perto,gotoxy:perto
processo principal

mov machado,@dados

mov ds, machado

mov é, machado

Eu sigo:

mov dl,17h ; letras_azul_fundo-brancas


ligar claro

título da ;title é um procedimento interno


chamada mov dh,17

movimento dl,15

ligue para gotoxy

leia dx, mensagem1


mova-se ah,9
int 21h

104
Machine Translated by Google

ler dx, número


mov ah,0ah
int 21h
mov di,1
mov cl,número[di]
mov dh,18
mov dl,15
chamar
gotoxy ler

dx,mensagem2 mov
ah,9 int
21h
mov di,cx
adicionar
di,2 repetir :
dez di mov
dl, número[di]
mov ah,2
int 21h
loop
repete
mov dh,20
mov
dl,15

chamada
gotoxy lea

dx,pergunta
mov ah,9
int 21h mov
ah,1 int 21h
cmp al,"s"
Eu sigo
mov ah,
4ch int 21h
main endp
title proc
pusha
mov
dh,8 mov
dl,15 call
gotoxy lea dx, title1 mov ah,9 int 21h mov dh,9 mov dl,15 call gotoxy lea dx, title2 mov ah, 9 int 21h mov dh,10 mov dl,15 c

105
Machine Translated by Google

ler dx, título 3


mov ah, 9
int 21h
mov dh, 11
mov dl, 15
chamada
gotoxy ler dx,
título 4
mov
ah, 9 int 21h
mov dh, 12
mov dl, 15
chamada
gotoxy ler
dx,
título 5 mov
ah, 9 int
21h mov
dh,13 mov
dl,15
chamada gotoxy lea dx,titulo6 mov ah,9 int 21h

popa
ret

título endp
fim principal

(1) Conversão dos procedimentos clear e gotoxy em macros

A conversão é muito simples. A macro clear não terá parâmetros e a macro gotoxy terá dois parâmetros, fil, para
indicar a linha e col, para indicar a coluna. O arquivo macros.lib contém as duas macros conforme mostrado abaixo:

;Macros.LIB MacrosContainTheMacrosClearGotoxy.LIB limpar macro


pushA mov al,0

mov
cx,0 mov
dh,24 mov
dl,79 mov
bh,7 mov
ah,6 Int
10h popA ; solicitação de função de limpeza;
endm prossiga para limpar

gotoxy macro arquivo,col ; Parâmetros DH=linha DL=coluna


pushA
mov dh,fil
mov dl,col
mov bh,0

106
Machine Translated by Google

movimento ah,2

dentro das 10h

popa
fim

(2) Converta o programa PrPROCS.ASM e salve-o como Exem21.ASM, para usar o


macros

A seguir está o programa ejem21.asm, que é o resultado da conversão do programa


PrPROCS.ASM original para usar as macros clear e gotoxy.

; Programa Exem21.asm Exem21ReadsANumberAndWritesItBackwardsWithMacros.asm


.modelo pequeno

0,386
.dados

título1 db "*********************************************** ********** *****************$"


"*
título2 db *$" Biblioteca MACROS.LIB
"*
titulo3 db Teste das macros clear e gotoxy *$" *$"
"*
title4 db Programa: Exem21.asm Lê um número como uma
"*
title5 db title6 string e o escreve ao contrário *$"
db "********************************************* ********* *******************$"

message1 db "Digite um número message2 :$"

db "Número lido de trás para frente: $"


pergunta do banco de dados "Deseja continuar (s/n)? : $"
banco de dados número 255

.código

inclua macros.lib ; usar macros proc principais

mov machado,@dados

mov ds, machado

mov é, machado

Eu sigo:

claro
título da chamada

movimento dh,17

movimento dl,15

gotoxi 17.15
leia dx, mensagem1
mova-se ah,9
int 21h

leia dx, número


mov ah, 0ah
int 21h

movimento di,1

mov cl, número[di]


movimento dh,18

movimento dl,15

gotoxi 18.15
leia dx, mensagem2
mova-se ah,9
int 21h

mov di,cx
adicione di,2

repita:
diga diga

mov dl, número[di]


movimento ah,2

107
Machine Translated by Google

int 21h

loop repetir
gotoxy 20,15
ler dx, pergunta
mov ah,9
int 21h
mov ah,1
int 21h

cmp al,"s"
Eu
continuo mov
ah,4ch

int 21h
principal
endp
título proc
pusha gotoxy
8,15 ler
dx,

title1 mov
ah,9 int 21h
gotoxy
9,15 ler

dx,title2 mov
ah,9 int 21h
gotoxy
10,15

ler dx,title3
mov ah,9 int
21h gotoxy
11,15

ler dx,title4
mov ah,9 int
21h gotoxy
12,15

leitura dx,
título5 mov
ah,9 int
21h gotoxy 13,15 leitura dx, título6 mov ah,9 int 21h

popa
ret
título endp
fim principal

Primeiramente é necessário montar o arquivo Macros.LIB, para verificar se possui erros


de sintaxe, e obtemos o seguinte resultado:

108
Machine Translated by Google

O erro: “Fim de arquivo inesperado encontrado” é gerado porque o código da macro não
possui a instrução End. Por isso não lhe damos qualquer importância.

O resultado da execução do programa Ejem21.asm é o seguinte:

109

Você também pode gostar