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 : Contato
http://www.geocities.com/SiliconValley/Park/3174 (meu site antigo, agora está fora do ar)
http://www.krull.com.br
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!
Antes de explorarmos o grande e mau mundo dos segmentos e offsets, há umas terminologias que você precisar conhecer.
- O BIT – a menor parte de dados que podemos usar. Um bit – um oitavo de um byte pode ser ou um 1 ou um 0. Usando esses dois dígitos podemos fazer números em BINÁRIO ou BASE 2.
EX.:
0000 = 0 0100 = 4 1000 = 8 1100 = 12
0001 = 1 0101 = 5 1001 = 9 1101 = 13
0010 = 2 0110 = 6 1010 = 10 1110 = 14
0011 = 3 0111 = 7 1011 = 11 1111 = 15
10000 = 16 … Acho que você já sacou…
- O NIBBLE, ou quatro bits. Um nibble pode ter um valor máximo de 1111 que é 15 em decimal. É aqui que o hexadecimal entra. Hex é baseado naqueles 16 números, (0-15), e quando escrevemos em hex, usamos os ‘dígitos’ abaixo:
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
- O BYTE – o que mais usaremos. O byte tem 8 bits de tamanho – isso é 2 nibbles, e é o único valor que você vai conseguir colocar num registrador de 8 bits. EX.: AH, AL, BH, BL, …
Um byte tem um valor máximo de 255 em decimal, 11111111 em binário, ou FFh em hexadecimal.
- A WORD – outra unidade comumente usada. Uma word é um número de 16 bits, e é capaz de armazenar um número até 65535. Isso é 1111111111111111 em binário, e FFFFh em hex.
Obs.: Como uma word equivale a 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.
- A DWORD, ou double word consiste de 2 words ou 4 bytes ou 8 nibbles ou 32 bits. Você não vai usar muito as double words nestes tutoriais, mas vamos mencioná-las mais tarde quando falarmos de PROGRAMAÇÃO EM 32 BITS.
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.
- O KILOBYTE, é 1024 bytes, NÃO 1000 bytes. O kilobyte é igual a 256 double-words, 512 words, 1024 bytes, 2048 nibbles ou 8192 BITS. Eu não vou escrever todos os um’s.
- O MEGABYTE, ou 1024 kilobytes. Isso é 1,048,576 bytes ou 8,388,608 bits.
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.
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.
Exemplo:
3CE5:502A
^^^^ ^^^^
SEG OFS
Ok, aqui está a especificação:
Um OFFSET = SEGMENTO x 16
Um SEGMENTO = 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 o registrador 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 ESSES DOIS!!!
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 é 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:
- PUSH <registrador> – PUSH (coloca algo na pilha), e
- POP <registrador> – POP (retira ele de volta).
É 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
- Muito mais instruções, todos os JUMPS.
- O que são flags?
- As procedures acima com comentários.
- Um programa só em assembler. Você vai precisar pelo menos do DEBUG, embora TASM e TLINK sejam uma boa idéia.
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:
- http://www.faroc.com.au/~blackcat
- http://www.krull.com.br
– Adam Hyde.
– Renato Nunes Bastos.
Muito bom estou estudando seu tutorais tenho que praticar o2 tutoral ajuda é benvinda nos dias normais sou eletricista trabalho com clp obrigada vou seguindo em frente pois assembli é otimo