Skip to content

Instantly share code, notes, and snippets.

@marcialwushu
Last active September 4, 2017 04:52
Show Gist options
  • Save marcialwushu/d80b94d5cf77821987f489d7b3d54f8c to your computer and use it in GitHub Desktop.
Save marcialwushu/d80b94d5cf77821987f489d7b3d54f8c to your computer and use it in GitHub Desktop.

Curso de Assembly

             i----------------------------------------------©
             ¦ RBT   ¦   Curso de Assembly   ¦   Aula Nº 01 ¦
             È----------------------------------------------¥

Por: Frederico Pissarra

i------------©
¦ ASSEMBLY I ¦
È------------¥

A linguagem ASSEMBLY (e näo assemblER!) dá medo em muita gente! Só näo sei porque! As liguagens ditas de "alto nível" säo MUITO mais complexas que o assembly! O programador assembly tem que saber, antes de mais nada, como está organizada a memória da máquina em que trabalha, a disponibilidade de rotinas pré-definidas na ROM do micro (que facilita muito a vida de vez em quando!) e os demais recursos que a máquina oferece.

Uma grande desvantagem do assembly com relaçäo as outras linguagens é que näo existe tipagem de dados como, por exemplo, ponto-flutuante... O programador terá que desenvolver as suas próprias rotinas ou lançar mao do co-processador matemático (o TURBO ASSEMBLER, da Borland, fornece uma maneira de emular o co-processador). Näo existem funçöes de entrada-saída como PRINT do BASIC ou o Write() do PASCAL... Näo existem rotinas que imprimam dados numéricos ou strings na tela... Enfim... näo existe nada de útil! (Será?! hehehe)

Pra que serve o assembly entäo? A resposta é: Para que você possa desenvolver as suas próprias rotinas, sem ter que topar com bugs ou limitaçöes de rotinas já existentes na ROM-BIOS ou no seu compilador "C", "PASCAL" ou qualquer outro... Cabe aqui uma consideraçäo interessante: É muito mais produtivo usarmos uma liguagem de alto nível juntamente com nossas rotinas em assembly... Evita-se a "reinvençäo da roda" e näo temos que desenvolver TODAS as rotinas necessárias para os nossos programas. Em particular, o assembly é muito útil quando queremos criar rotinas que näo existem na liguagem de alto-nível nativa! Uma rotina ASM bem desenvolvida pode nos dar a vantagem da velocidade ou do tamanho mais reduzido em nossos programas.

O primeiro passo para começar a entender alguma coisa de assembly é entender como a CPU organiza a memória. Como no nosso caso a idéia é entender os microprocessadores da família 80x86 da Intel (presentes em qualquer PC-Compatível), vamos dar uma olhadela no modelamento de memória usado pelos PCs, funcionando sob o MS-DOS (Windows, OS/2, UNIX, etc... usam outro tipo de modelamento... MUITO MAIS COMPLICADO!).


i---------------------------------------------©
¦ Modelamento REAL da memória - A segmentaçäo ¦
È---------------------------------------------¥

A memória de qualquer PC é dividida em segmentos. Cada segmento tem 64k bytes de tamanho (65536 bytes) e por mais estranho que pareça os segmentos näo säo organizados de forma sequencial (o segmento seguinte näo começa logo após o anterior!). Existe uma sobreposiçao. De uma olhada:

                               64k
    +-----------------------------------------------------+
    +------------------------------------------------------------+
    ¦                                                     ¦
    ¦      ¦      ¦                                       ¦      ¦
    ¦                                                     ¦
    +------------------------------------------------------------+
    0      1      2 <- Numero do segmento
    +-------------+
       16     16
     bytes   bytes
     

O segundo segmento começa exatamente 16 bytes depois do primeiro. Deu pra perceber que o inicio do segundo segmento está DENTRO do primeiro, já que os segmentos tem 64k de tamanho!

Este esquema biruta confunde bastante os programadores menos experientes e, até hoje, ninguem sabe porque a Intel resolveu utilizar essa coisa esquisita. Mas, paciência, é assim que a coisa funciona!

Para encontrarmos um determinado byte dentro de um segmento precisamos fornecer o OFFSET (deslocamento, em inglês) deste byte relativo ao inicio do segmento. Assim, se queremos localizar o décimo-quinto byte do segmento 0, basta especificar 0:15, ou seja, segmento 0 e offset 15. Esta notaçäo é usada no restante deste e de outros artigos.

Na realidade a CPU faz o seguinte cálculo para encontrar o "endereço físico" ou "endereço efetivo" na memória:


 +-----------------------------------------------------------------+
 ¦         ENDEREÇO-EFETIVO = (SEGMENTO * 16) + OFFSET             ¦
 +-----------------------------------------------------------------+

Ilustrando a complexidade deste esquema de endereçamento, podemos provar que existem diversas formas de especificarmos um único "endereço efetivo" da memória... Por exemplo, o endereço 0:13Ah pode ser também escrito como:


    0001h:012Ah     0002h:011Ah     0003h:010Ah     0004h:00FAh
    0005h:00EAh     0006h:00DAh     0007h:00CAh     0008h:00BAh
    0009h:00AAh     000Ah:009Ah     000Bh:008Ah     000Ch:007Ah
    000Dh:006Ah     000Eh:005Ah     000Fh:004Ah     0010h:003Ah
    0011h:002Ah     0012h:001Ah     0013h:000Ah

Basta fazer as contas que você verá que todas estas formas daräo o mesmo resultado: o endereço-efetivo 0013Ah. Generalizando, existem, no máximo, 16 formas de especificarmos o mesmo endereço físico! As únicas faixas de endereços que näo tem equivalentes e só podem ser especificados de uma única forma säo os desesseis primeiros bytes do segmento 0 e os últimos desesseis bytes do segmento 0FFFFh.

Normalmente o programador näo tem que se preocupar com esse tipo de coisa. O compilador toma conta da melhor forma de endereçamento. Mas, como a toda regra existe uma excessäo, a informaçäo acima pode ser útil algum dia.


+-------------------------------------------------------------------+
¦ A BASE NUMÉRICA HEXADECIMAL E BINARIA (para os novatos...)        ¦
+-------------------------------------------------------------------+

Alguns talvez näo tenham conhecimento sobre as demais bases numéricas usadas na área informata. É muito comum dizermos "código hexadecimal", mas o que significa?

É bastante lógico que usemos o sistema decimal como base para todos os cálculos matemáticos do dia-a-dia pelo simples fato de temos DEZ dedos nas mäos... fica facil contar nos dedos quando precisamos (hehe).

Computadores usam o sistema binário por um outro motimo simples: Existem apenas dois níveis de tensäo presentes em todos os circuitos lógicos: níveis baixo e alto (que säo chamados de 0 e 1 por conveniência... para podermos medi-los sem ter que recorrer a um multímetro!). O sistema hexadecimal também tem o seu lugar: é a forma mais abreviada de escrever um conjunto de bits. Em decimal, o número 1994, por exemplo, pode ser escrito como:

1994 = (1 * 10^3) + (9 * 10^2) + (9 * 10^1) + (4 * 10^0)

Note a base 10 nas potências. Faço agora uma pergunta: Como representariamos o mesmo númer se tivessemos 16 dedos nas mäos?

Primeiro teriamos que obter mais digitos... 0 até 9 näo säo suficientes. Pegaremos mais 6 letras do alfabeto para suprir esta deficiencia.

Segundo, Tomemos como inspiraçäo um odômetro (equipamento disponível em qualquer automóvel - é o medidor de quilometragem!): Quando o algarismo mais a direita (o menos significativo) chega a 9 e é incrementado, o que ocorre?... Retorna a 0 e o próximo é incrementado, formando o 10. No caso do sistema hexadecimal, isto só acontece quando o último algarismo alcança F e é incrementado! Depois do 9 vem o A, depois o B, depois o C, e assim por diante... até chegar a vez do F e saltar para 0, incrementando o próximo algarismo, certo?

Como contar em base diferente de dez é uma situaçäo näo muito intuitiva, vejamos a regra de conversäo de bases. Começaremos pela base decimal para a hexadecimal. Tomemos o número 1994 como exemplo. A regra é simples: Divide-se 1994 por 16 (base hexadecimal) até que o quoeficiente seja zero... toma-se os restos e tem-se o númer convertido para hexadecimal:


  +---------------------------------------------------------------+
  ¦ 1994 / 16     -> Q=124, R=10      -> 10=A                     ¦
  ¦ 124 / 16      -> Q=7, R=12        -> 12=C                     ¦
  ¦ 7 / 16        -> Q=0, R=7         ->  7=7                     ¦
  +---------------------------------------------------------------+
  

Toma-se entäo os restos de baixo para cima, formando o número em hexadecimal. Neste caso, 1994=7CAh

Acrescente um 'h' no fim do número para sabermos que se trata da base 16, do contrário, se olharmos um número "7CA" poderiamos associa-lo a qualquer outra base numérica (base octadecimal por exemplo!)...

O processo inverso, hexa->decimal, é mais simples... basta escrever o númer, multiplicando cada digito pela potência correta, levando-se em conta a equivalencia das letras com a base decimal:

 +-----------------------------------------------------------------+
 ¦  7CAh = (7 * 16^2) + (C * 16^1) + (A * 16^0) =                  ¦
 ¦         (7 * 16^2) + (12 * 16^1) + (10 * 16^0) =                ¦
 ¦         1792 + 192 + 10 = 1994                                  ¦
 +-----------------------------------------------------------------+

As mesmas regras podem ser aplicadas para a base binária (que tem apenas dois digitos: 0 e 1). Por exemplo, o número 12 em binário fica:

 +-----------------------------------------------------------------+
 ¦  12 / 2      -> Q=6, R=0                                        ¦
 ¦  6 / 2       -> Q=3, R=0                                        ¦
 ¦  3 / 2       -> Q=1, R=1                                        ¦
 ¦  1 / 2       -> Q=0, R=1                                        ¦
 ¦                                                                 ¦
 ¦  12 = 1100b                                                     ¦
 +-----------------------------------------------------------------+

Cada digito na base binária é conhecido como BIT (Binary digIT - ou digito binário, em inglês)! Note o 'b' no fim do número convertido...

  • Faça o processo inverso... Converta 10100110b para decimal.

    A vantagem de usarmos um número em base hexadecimal é que cada digito hexadecimal equivale a exatamente quatro digitos binários! Faça as contas: Quatro bits podem conter apenas 16 números (de 0 a 15), que é exatamente a quantidade de digitos na base hexadecimal.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment