Tutorial de Assembler de Adam Hyde 1.0

PARTE 2
Traduzido por Renato Nunes Bastos

Versão   :  1.2
Data       :  17-02-1996 / online by Renato 01-11-1998
Contato  :  blackcat@vale.faroc.com.au
                  http://www.faroc.com.au/~blackcat
;Renato  :  rnbastos@ig.com.br 
                 http://www.geocities.com/SiliconValley/Park/3174


Segmentos e Offsets | Uma Arquitetura Segmentada | A Pilha |


Olá de novo, futuros proramadores de Assembler. Para aqueles que perderam a primeira parte, pegue-a agora na minha homepage.

De qualquer modo, no último número eu disse que estaria discutindo sobre hexadecimal, segmentos + offsets, mais algumas intruções e algumas procedures contendo assembler que você poderia realmente usar.

Então, lá vamos nós, com segmentos e offsets!


LIÇÃO 3 - Segmentos e Offsets

Antes de explorarmos o grande e mau mundo dos segmentos e offsets, há umas terminologias que você precisar  conhecer.

     EX.:        0000 = 0    0100 = 4   1000 = 8    1100 = 12   10000 = 16
                    0001 = 1   0101 = 5   1001 = 9    1101 = 13    ...Acho que você
                    0010 = 2   0110 = 6   1010 = 10   1110 = 14   já sacou...
                    0011 = 3   0111 = 7   1011 = 11   1111 = 15

0 1 2 3 4 5 6 7 8 9 A B C D E F

     Hexadecimal é na verdade muito fácil de se usar, e, apenas como curiosidade, eu acho que os Babilônios - uma civilização antiga qualquer - usava um sistema de numeração em BASE 16. Tem algum historiador aí fora que queira confirmar isso?

     IMPORTANTE >>> Um nibble pode aguentar um valor até Fh <<< IMPORTANTE

     Um byte tem um valor máximo de 255 em decimal, 11111111 em binário, ou FFh em hexadecimal.

     Obs.:  Por causa de uma word ser quatro nibbles, é também representada por quatro dígitos hexadecimais.

     Obs.:  Isto é um número de 16 bits, e corresponde aos registradores de 16 bits. Ou seja, AX, BX, CX, DX, DI, SI, BP,          SP, DS, ES, SS e IP.

     Uma DWORD pode armazenar de 0 a 4,294,967,295, que é FFFFFFFFh, ou 11111111111111111111111111111111.  Espero que haja 32 um's lá atrás.

     A DWORD também é o tamanho dos registradores extendiddos de 32 BITS, ou seja, EAX, EBX, ECX, EDX, EDI, ESI, EBP, ESP e EIP.

Agora que já cobrimos a terminologia, vamos dar uma  olhada mais de perto como aqueles registradores são estruturados. Nós dissemos que AL e AH eram registradores de 8 bits, logo, eles não deveriam se parecer com algo assim?

AH AL
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0

   
Neste caso, ambos AH e AL = 0, OU 00h e 00h.  Como resultado, para calcular AX usamos:  AX = 00h + 00h. Quando digo + eu quero dizer, 'ponha junto' não AX = AH MAIS AL.

Assim, se AH era igual a 00000011 e AL era igual a 0000100, para calcular AX nós devemos fazer o seguinte.

1) Pegue os valores hexadecimais de AH e AL.

   00000011 = 03h   00010000 = 10h

2) Combine-os.

   AX = AH  + AL
   AX = 03h + 10h
   AX = 0310h

E aí você consegue o resultado. Não é tão macetoso assim.

Okay, agora vamos ver os registradores de 16 bits:

AX
AH AL
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0

De onde podemos ver que AX = 00000000 e 00000000, ou 0000000000000000.

Agora por último, vejamos como um registrador de 32 bits se parece:

EAX
  AX
  AH AL
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0

(by Renato - essa tabela estava errada na versão original, colocando o AX na parte mais significtiva de EAX. Eu tomei o direito de consertar. Se estiver errado - era mesmo na parte mais significativa? - me avisem)

 

Não é muito difícil, espero. E se entendeu isso, você está pronto para SEGMENTOS e OFFSETS.


Uma Arquitetura Segmentada

Há muito, muito tempo atrás, quando a IBM construiu o primeiro PC, não era costume programas terem mais de 1 megabyte - eca, os primeiros XT's tinham apenas 64K de RAM! De qualquer modo, vendo que os projetistas do XT não consideravam aplicações enormes, decidiram dividir a memória em SEGMENTOS, pequenas áreas de mem¢ria RAM que você pode colocar APENAS uma tela virtual para gráficos em modo 320x200x256.

É claro, você pode acessar mais de um megabyte de RAM, mas você tem que dividi-la em segmentos para usá-la, e esse é o problema. É obvio, com programação em 32 bits dé pra acessas até 4GB de RAM sem usar segmentos, mas isso é uma outra história.

Segmentos e offsets são apenas um método de especificar uma posição na memória.

EG:   3CE5:502A

         ^^^^  ^^^^
         SEG   OFS

Okay, aqui está a especificação:

Um OFFSET  = SEGMENT X 16
Um SEGMENT = OFFSET  / 16

Alguns registradores de segmento são:

CS, DS, ES, SS e FS, GF  - Obs.: Os últimos 2 são registradores que só existem em 386 ou superiores.

Alguns registradores de offset são:

BX, DI, SI, BP, SP, IP     - Obs.: Quando em modo protegido, você pode usar qualquer registrador de uso geral como
                                           um registrador de offset - EXCETO IP.

Alguns segmentos e offsets comuns são:

    CS:IP - Endereço do código executando no momento.
    SS:SP - Endereço da posição atual da pilha.

    OBS.: NÃO SE INTROMETA COM ELES !

Assim quando nos referirmos a segmentos e offsets, faremos dessa forma:

SEGMENTO:OFFSET

Um bom exemplo seria:

A000:0000 - que na verdade corresponde ao topo esquerdo da tela VGA em modo colorido 320x200x256.

            ** FATO ENGRAÇADO ** A RAM da VGA começa em A000h  :)


Ufa! Isso foi muito para o segundo tutorial. Contudo, ainda não terminamos.
Esse negócio de AX, AH, AL é um conceito que você pode não ter sacado ainda, então lá vamos nós:

    MOV   AX, 0     ; AX = 0
    MOV   AL, 0     ; AL = 0
    MOV   AH, 0     ; AH = 0

    MOV   AL, FFh   ; AL = FFh
                    ; AX = 00FFh
                    ; AH = 00h

    INC   AX        ; AX = AX + 1

                    ; AX = 0100h
                    ; AH = 01h
                    ; AL = 00h

    MOV   AH, ABh   ; AX = AB00h
                    ; AH = ABh
                    ; AL = 00h

Pegou?


COISAS A FAZER:

1) Aprender aquele negócio de BIT/NIBBLE/BYTE... de cor.
2) Voltar nos exemplos de segmento e offset.
3) Tenha certeza que você entendeu a relação entre AX, AH e AL.
4) Que tal um problemas de adição hexadecimal?


A Pilha

A pilha é uma característica muito útil de que podemos tirar vantagem. Pense nela como uma pilha de papéis numa bandeja de ENTRADA. Se você põe algo no topo, ela será a primeira a ser tirada.

À medida que você adiciona algo à pilha, o apontador de pilha é DECREMENTADO, e quando tira, é INCREMENTADO. Para explicar isso melhor, veja o diagrama abaixo:

A PILHA
 
  •  
  •  
  •  
  •  
 
    SP

   

 
<<<<<  Quando colocamos um byte na pilha, ele vai aqui - último a entrar, primeiro a sair.





   <<<<<<  O ponteiro de pilha se move para baixo.

 

E na prática:

   MOV   AX, 03h   ; AX = 03h
   PUSH  AX        ; PUSH AX na pilha (coloca no topo)

   MOV   AX, 04Eh  ; AX = 04Eh

                   ; Faça alguma coisa... uma soma?

   POP   AX        ; AX = 03h

Ou:

   MOV   AX, 03h   ; AX = 03h
   PUSH  AX        ; Adiciona AX à pilha

   MOV   AX, 04Eh  ; AX = 04Eh

                   ; Faça alguma coisa... uma soma?

   POP   BX        ; BX = 03h

Você acabou de aprender duas instruções:

É tudo o que você precisa de aprender sobre pilha - por enquanto.


Por último, algumas procedures que demonstram algo disso tudo. Note que os comentários foram DELIBERADAMENTE REMOVIDOS. É seu dever tentar comentá-los. Note também, que algumas novas instruções são introduzidas.

Procedure ClearScreen(A : Byte; Ch : Char);   Assembler;

Asm     { ClearScreen }
  mov   ax, 0B800h
  mov   es, ax
  xor   di, di
  mov   cx, 2000
  mov   ah, A
  mov   al, &Ch
  rep   stosw
End;    { ClearScreen }

Procedure CursorXY(X, Y : Word);   Assembler;

Asm    { CursorXY }
   mov   ax, Y
   mov   dh, al
   dec   dh
   mov   ax, X
   mov   dl, al
   dec   dl
   mov   ah, 2
   xor   bh, bh
   int   10h
End;    { CursorXY }

Procedure PutPixel(X, Y : Integer; C : Byte; Adr : Word);   Assembler;

Asm     { PutPixel }
   mov   ax, [Adr]
   mov   es, ax
   mov   bx, [X]
   mov   dx, [Y]
   xchg  dh, dl
   mov   al, [C]
   mov   di, dx
   shr   di, 2
   add   di, dx
   add   di, bx
   stosb
End;    { PutPixel }

Procedure Delay(ms : Word);   Assembler;

Asm     { Delay }
   mov   ax, 1000
   mul   ms
   mov   cx, dx
   mov   dx, ax
   mov   ah, 86h
   int   15h
End;    { Delay }

COISAS A FAZER:

1) Vá ao exemplo de pilha. Faça seu próprio código exemplo.
2) Comente as procedures acima do melhor modo que puder. Tente adivinhar o que  as novas intruções fazem. Não é tão difícil.


NA PRÓXIMA SEMANA

Se você deseja ver um tópico discutido num tutorial no futuro, escreva-me, e eu vou ver o que eu posso fazer.


Não perca!!! Baixe o tutorial da próxima semana na minha homepage:

- Adam Hyde.
- Renato Nunes Bastos.