Escolar Documentos
Profissional Documentos
Cultura Documentos
CAPÍTULO I INTRODUÇÃO
“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.
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
Machine Translated by Google
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.
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.
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.
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
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.
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:
Terceiro: entrada e saída de dados; Sem esses dois processos essas máquinas não teriam muita
utilidade, certo?
4
Machine Translated by Google
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:
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.
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
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.
O COMPUTADOR É: O HOMEM É:
• Estúpida, ela é uma escrava repetitiva. • Brilhante, porque tem o poder de criar, por isso
é o mestre.
ALÉM DO MAIS:
• 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.)
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
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.
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.
mova al,3 ; al = 3
adicione al,5 ; al = al + 5
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:
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.
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.
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.
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
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:
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
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
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 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:
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
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:
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:
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
machado mov,1
jl eu continuo ; pule se for menor (se ax < 100 for verdadeiro, ramifique para o próximo)
Intervalo 20
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
13
Machine Translated by Google
.modelo pequeno
.dados
dados db 33h
.código
processo principal
terminal principal
fim principal
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. .
14
Machine Translated by Google
.modelo pequeno
.dados
dados db 33h
.código
processo principal
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
quinze
Machine Translated by Google
Conceito de reutilização
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:
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
pequeno
.386 .dados x dq ? mensa1 db
'Insira um número: $' mensa2 db
'Raiz
quadrada: $' .code extrn
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
18
Machine Translated by Google
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.
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. 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
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” 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” 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” 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.
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.
QUARTO PASSO
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>.
22
Machine Translated by Google
QUINTO PASSO
SEXTO PASSO
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
SEGUNDO PASSO
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:
NOTAÇÃO DE VISÃO
Ahem00 <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:
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
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.
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:
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
Fazendo uma abstração, podemos então representar uma memória RAM de 1 Mbyte da seguinte forma:
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.
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
PRIMEIRO PASSO
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:
A seguir, digitando –D 100:50 <enter>, você pode verificar se os dados CA16 estão armazenados
neste endereço
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
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.
31
Machine Translated by Google
- Ponteiros de pilha SP BP
(endereços) Ponteiro base do ponteiro de pilha
- Ponteiro de instrução PI
(endereços) Ponteiro de instrução
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 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.
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.
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.
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.
PI
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
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).
NV UP DI PL NZ NA PO NC
OV DN EI NG ZR AC PE CY
35
Machine Translated by Google
• Assinar PL = positivo
NG = negativo
• Zero Nova Zelândia = diferente de zero
ZR = se zero
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:
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.
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:
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
37
Machine Translated by Google
Interno 20h
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.
38
Machine Translated by Google
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.
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 .
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
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
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:
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.
42
Machine Translated by Google
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:
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.
mova al,3
adicione al,5
43
Machine Translated by Google
mov al,8
subal,3
int 20
*
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
44
Machine Translated by Google
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.
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”:
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.
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 .
47
Machine Translated by Google
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
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
49
Machine Translated by Google
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
.
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:
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:
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.
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.
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.
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.
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.
• 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.
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
53
Machine Translated by Google
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
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
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
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
55
Machine Translated by Google
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 (comparar), jl (pular se for menor) permitem formar ciclos de repetição. A instrução nop (sem
operação) nos ajudará na depuração.
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 .
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:
57
Machine Translated by Google
Exemplo 13
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:
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
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.
59
Machine Translated by Google
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.
60
Machine Translated by Google
61
Machine Translated by Google
3.1 Introdução
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.
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
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.
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.
63
Machine Translated by Google
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
movimento dh,0
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
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.
Teste MASM.asm
ou este outro:
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
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
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.
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.
68
Machine Translated by Google
Diagrama conjunto das etapas para editar e montar um , link e crie o executável
programa
tela
teclado
teste.asm programa.fonte
MASM.exe
na memória o montador
OU TASM.exe
Execução do programa
Disco disquete teclado na tela
INGRESSOS
PARTIDAS
69
Machine Translated by Google
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.
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
• 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.
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:
É um campo opcional e é o nome da variável. Sua formação é definida pelas regras dos
identificadores fornecidas posteriormente.
71
Machine Translated by Google
Uma expressão pode conter vários valores constantes separados por vírgulas e limitados apenas pelo
comprimento da linha.
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:
pequeno
pequeno
.model médio
compactar
grande
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
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.
FORMATO CURTO
PEQUENO
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
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:
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.
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
termina final
principal
74
Machine Translated by Google
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
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
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.
processo principal
movimento dl,7
adicionar dl,30h
cmp dl,39h
jle pular
adicione dl,7
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
78
Machine Translated by Google
Solução
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
A seguir usamos a instrução AND para converter uma parte de um registro em 0000.
E01
000
101
DL=111001112
0Fh = 000011112
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
.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
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.
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
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 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.
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.
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.
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.
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.
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
85
Machine Translated by Google
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:
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 19
86
Machine Translated by Google
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
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
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 é:
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:
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:
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
Depois que essas alterações forem feitas, o programa .COM ficará assim:
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
Ahem19 <enter>
89
Machine Translated by Google
VERSÃO SIMPLIFICADA
; 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
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
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.
• 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
92
Machine Translated by Google
O atributo pode ser PRÓXIMO – que é o padrão, ou seja, se o atributo não for informado – ou FAR.
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
Nome PÚBLICO [, . . . ]
• 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
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.
(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
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.
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.
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
DADOS
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:
,
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.
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 ...
Observações
A linguagem assembly para passagem de parâmetros utiliza registros ou variáveis de tipo público e/ou
também pilha.
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.
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:
mover para,0.
movimento cx,0
(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 é:
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:
0,386
.código
público claro
empurrarA
mover para,0.
movimento cx,0
mov dh,24
mov dl,79
movimento bh,7
ret
limpar final;
gotoxi público
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:
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:
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.
mov machado,@dados
Eu sigo:
ligar claro
movimento dh,12
movimento dl,14
ligue para
gotoxy lea dx,
mensagem1 mov ah,9
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
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
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.
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.
Exemplos:
*
(1) Macro para calcular Z = X E
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
101
Machine Translated by Google
.modelo pequeno
.dados
microproduto X,Y,Z1,Z2
mov machado,X ; machado=X
fim
processo principal
mov machado,@dados
mov ds,ax
PRODUTO 0FFFFh,0FFFFh,parte_alta,parte_baixa mov ah,4ch
Internamente 21h
terminal principal
fim
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
adicione dl,1
laço três
fim
102
Machine Translated by Google
contínuo
ah,4ch int
21h principal endp miguel termina final principal
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
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
(1) Escreva os procedimentos clear e gotoxy, como macros, usando os mesmos nomes, e
(2) Modifique o programa PrPROCS.ASM, e já modificado, salve-o com o nome Exem21.ASM, para que ao invés de utilizar os
0,386
.dados
.código
extrn claro:perto,gotoxy:perto
processo principal
mov machado,@dados
mov é, machado
Eu sigo:
movimento dl,15
104
Machine Translated by Google
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
popa
ret
título endp
fim principal
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:
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
106
Machine Translated by Google
movimento ah,2
popa
fim
0,386
.dados
.código
mov machado,@dados
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
movimento di,1
movimento dl,15
gotoxi 18.15
leia dx, mensagem2
mova-se ah,9
int 21h
mov di,cx
adicione di,2
repita:
diga diga
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
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.
109