Assebler pro blbe

Transkript

Assebler pro blbe
Assembler pro blbe
Neda vno jsem narazil na perfektnıtext o assembleru a grafice. Prokousal jsem se tım a naucil se to.
Myslım, z e to bude zajımat vıce lidı, takz e z toho vyrobım seria l na pokracova nı.
Ra d bych upozornil, z e jsem taky zaca tecnık. Prosım tedy stare zkus ene Assemblerovske psy aby neva hali a radili a
kritizovali.
C asto pouz iju dvř instrukce mısto jedne, a o spoustř fint nema m urcitř ani tus enı.
Oceka va m taky, z e mi va z enıctena ri budou psa t maily s poz adavky co nepochopili tak docela uplnř. Ra d svou rychlost
prizp˚sobım vas emu cha pa nı. Takz e mř klidnř brzdřte. Popoha nřnı asi budete mıt marne, protoz e jsem docela blbej a
nem˚z u va m to vysvřtlovat rychleji, nez se to stacım ucit.
Takz e do toho skocıme rovnyma nohama:
Registry
Registry jsou nřco jako promřnne ve vys s ıch programovacıch jazycıch. Pr˚ser je ovs em v tom, z e je jich dost ma lo.
Registry jsou vřts inou 16 bitove. Nřktere se dajı rozdřlit na dva 8mi bitove. Treba 16ti bitovy registr AX muz ete
pouz ıvat jako dva 8mi bitove jmenem AL a AH. Kdyz vrazım do registru AX treba hodnotu 0ABCDh (zvyknřte si psa t
pred hexa cıslici nulu, pokud to je pısmeno), bude AL obsahovat 0CDh a AH bude obsahovat 0ABh, jasan? Jestli ne,
tak pis te, pis te. Takto m˚z ete rozp˚lit kaz dy registr, ktery koncıiksem. Dostenete potom dva kousky jeden H a jeden L
Podıva me se, co tu ma me:
AX - Takovy jeden nejpouzıvane jsıregistr.
BX - Dalsıpodobny
CX - Umıto co ti nad nım, ale navıc se pouzı
va jako c ı
tac ve smyc ce.
DX - Poslednız třto c tverice
DS, ES, CS, SS - Segmentovř registry. Viz da le
SI, DI - Indexovř registry, pouzıvajıse pro pra ci s rete zci a poli.
A pak je tu jes tř pa r dals ıch, ty si necha me az napak (az je pochopım)
Segment & Offset:
Kdyz kdysi da vno (kdyz na zemi vla dli dinosauri) pa ni na vrha ri vynalezali procesor Intel 8086, rozhodli se, z e ho
vynaleznou tak, aby mřl 16ti bitove registry a aby s ırka jeho adresove sbřrnice byla 20 bit˚.
Chvıli jen tak sedřli a byli ze sve geniality uplnř paf a pak se jeden z nich pos kra bal na hlavř a povıda :
"Toz chlapi, sak to je na kř divnř ne?"
"Esli ma me 20bitovu adresu, toz to mozeme mıt prı
stup k jednřmu megabajtovi, fı
ııha toz to ja."
"Ale chlapi esli ma me v jednřm registru enřm 16 bitu, tak sa k temu nemozeme nijak dostaŠ.
S ak 16bitu to stac ıenřm na 64 kilobajtu."
Tak zase chvilku sedřli, nervoznř krcili pocıtacove sjetiny, az jeden na to ka pnul:
"Ja to ma m, na prı
stup k pame ti pouzijeme registry dva!"
Jak rekli, tak udřlali, ale udřlali sloz itř.
Predstavte si pamřň jako radu pamřň ovych bunřk. Tyto bunky jsou ocıslova ny od 0 po 0FFFFFh, je to celkem
megabajt. Pokud chcete zjistit hodnotu, ktera je uloz ena na nřktere adrese, m˚z ete rıct treba, z e chcete hodnotu z ad
resy 1ABCh. To m˚z ete rıct vy, ale ne procesor. Ten ma celou pamřň rozdřlenou na kusy o velikosti s estnacti bajtu.
Kdyz pristupujete na nřjakou adresu uda te nejdrıve cıslo one s estna ctice. To je tzv Segment, jako druhy udaj doda te
offset, coz je posunutı od zaca tku va mi zadaneho segmen tu. Sıla co?
Takz e treba adresa 0000:0000 (Segment a Offset se od sebe oddřlujıdvojteckou) je vlastnř adresa 0. Adresa
0000:0100h, je totez jako "prıma adresa 0100h. Ovs em tuto adresu m˚z ete zapsat take jako 0001:00F0h a nebo
000A:0060h, vs echny tyto adresy ukazujı na stejne mısto, tedy na 0100h bunku pamřti.
Skutecnou adresu zıska te takto:
16*Segment+Offset
Naucte se tyto adresy neprepocıta vat, naucte se myslet v segmentech a offsetech. Toto je ta nejtřz s ı ca st strojoveho
programova nı.
Takz e prvnıch par instrukcı:
MOV AX, 0FFFFh
Do registru AX uloz ı hodnotu 0FFFFh
MOV AX, BX
Hodnotu,ktera je v registru BX, zkopıruje do AX (AX = BX)
MOV AX, [0000:1234]
Hodnota ktera je uloz ena v pamřti na adrese 0000:1234 se zkopıruje do AX (AX=Mem[0000:1234])
MOV AX, [1234]
Je to totez jako vys e, ale nenı zde zada n segment. V takovem prıpadř se segmentova ca st adresy vezme z registru DS
(Data Segment) (AX=Mem[DS:1234])
MOV AX, [CS:1234]
Opřt stejne, ale tentokra t jsem prımo uvedl, z e segmentovou ca st chci vzıt z registru CS (Code Segment)
MOV AX, [DS:SI]
Jasne z e? Segmentova ca st je v DS a offset je v SI.
Vs imnřte si, z e AX je 16bitovy registr. Obsahem pamřň oveho mısta je ovs em bajt, tedy 8 bit˚, takz e takoveto prirazenı
nacte bajt ze zadane adresy ten uloz ıdo AL a nacte bajt z adresy+1 a uloz ıjej do AH.
TeÍ si predvedeme hra tky s registrem CX. Tento registr se kromř jineho pouz ıva jako cıtac. Existuje instrukce LOOP,
ktera zmens ı CX o jednicku a pokud nenı nulovy, skocına zadane na vřs tı, takz e treba:
mov
SMYCKA:
cx,
100
;Smycku budu opakovat stokrat.
;Navestı, sem se budu vrhat
;Tady neco pocıtam, atd...
ble, ble, ble
ble
ble
ble, ble
a furt pryc
loop SMYCKA
;A znova dokola, stokrat.
A co treba indexove registry: Budu chtıt znulovat oblast pamřti velkou 100 bajt˚ od adresy 100:200h
mov
ax,
100h
;Do DS nemuzu priradit hodnotu primo
mov
ds,
ax
;musim pres druhy registr
mov
di,
200h
;ted mi DS:DI ukazuje na prvnı bajt
; nulovanů oblasti
mov
ax,
0
;Nuluju, tak je to nula
mov
cx,
100
;Nuluju 100 bajtu
Nuluj:
mov
[ds:di],
ax
;Vrazim nulu na adresu DS:DI
inc
di
;A posunu se na dalsı adresu
loop Nuluj
;To celů stokrat
Jasan? Indexovy registr je vlastnř ukazatel v ra mci jednoho segmentu. Dıky tomu, z e je to registr a jeho hodnota se tedy
m˚z e mřnit, m˚z u stejnym programem adresovat r˚zna mısta.
C asem pozna te i vykonřjs ı instrukce, ktere dřlajı hromadu vřcına jeden prıkaz.
Mym dnes nım za mřrem je uka zat, z e je stroja k rychlejs ı nez cokoliv, takz e zkusme vyrobit stras nř rychle presouva nı
pamřti.
=============================================================
.MODEL SMALL
.CODE
.386
Obrazovka
dw
0B800h
;adresa bloku v pameti
Kusanec
dw
1000
;Kolik 4bajtu b udu presouvat
Kus2
dw
2000
;Kolikrat budu sunout
START:
;Tady zacina program
mov
cx,
[cs:Kus2]
mov
ds,
[cs:Obrazovka]
mov
es,
[cs:Obrazovka]
Smycka:
push cx
mov
si,
2
;DS:SI odkud presouvam
mov
di,
0
;ES:DI kam presouvam
mov
cx,
[cs:Kusanec]
;Kolik presouvam
rep
movsd
;CXkrat presunu [ES:DI] = [DS:SI]
pop
cx
loop Smycka
mov
ax,
4c00h
;Konec programu, navrat do DOSu
int
21h
END START
=====================================================================
Tu cast, ktera je mezi rovnitkovymi carami, vykopirujte do samostatneho fajlu. Dejte mu priponu ASM a predhodte jej
assemblerovi.
TASM.EXE nazev
TLINK.EXE nazev.OBJ
A je z toho EXE. Udelejte si batak, ktery tento program spusti alespon desetkrat. Ted si napiste ve vasem oblibenem
vyssim programovacim jazyku program, ktery presune 2000krat 4000bajtu z adresy 0B800:0002 na adresu 0B800:0000.
To je to, co dela programek nahore. Vyrobte batak na 100 opakovani a merte.
Takze co to vlastne dela.
.MODEL SMALL
Podle toho, jak velky bude vas program, reknete kopileru jaky ma pouzit pametovy model. Pouzivame model SMALL.
To znamena, ze budu pouzivat po jednom segmentu pro kod a pro data.
.CODE
Takto je oznacen zacatek CS. DOS pri spusteni programu nastavi CS, aby ukazoval zde.
.386
Budou se pouzivat instrukce pro procesor 386 a vyse. Je to tam kvuli instrukci MOVSD. Tuto instrukci nizsi procesory
neumi.
Pokud nezadate tuto direktivu, predpoklada kompilator, ze se preklada pro 8086 a na radku s instrukci MOVSD oznami,
ze procesor, ktery je nyni zvolen tuto instrukci neumi.
Obrazovka
Kusanec
Kus2
dw
dw
dw
0B800h
1000
2000
;adresa bloku v pameti
;Kolik 4bajtu budu presouvat
;Kolikrat budu sunout
Toto je definice pametovych promennych. Vyrabim tri promenne. Obrazovka, Kusanec a Kus2. Zaroven jim prirazuji
misto v pameti a pocatecni hodnotu. DW znamena Define Word, promenne je vyhrazen jeden word, tedy dva bajty. Do
techto dvou bajtu se ulozi hodnota uvedena za dw.
START:
Misto odkud ma zacit vykonavani programu, se oznacuje takto. Ted trochu predbehnu. Nejdrive si vysvetleme jak
funguje instrukce MOVSD. Tato instrukce presouva v pameti jeden Double Word, tedy ctyri bajty. Presouva se z
adresy urcene DS:SI na adresu v ES:DI. Jako pomucka pro zapamatovani je tu SI - Source Index (zdrojovy index) a DI
- Destination Index (cilovy index). Po presunu tato instrukce posune oba ukazatele dale prave o ctyri bajty. Opakovanim
teto instrukce muzete tedy presouvat souvisly usek pameti.
Opakovani zajistuje instrukce REP. Ta provede instrukci uvedenou jako argument, snizi CX o jednicku, je-li CX <> 0,
opakuje cely postup, provede, snizi, atd.. Takze danou instrukci provede tolikrat, kolik je zadano v registru CX.
Krome MOVSD, existuje i MOVSB - presouva jeden bajt, a MOVSW - presouva Word, neboli dva bajty. Tyto
instrukce posouvaji ukazatele o jeden, nebo dva bajty. Zbytek programu slouzi pouze pro naplneni registru spravnymi
hodnotami.
Program ma postupne odrolovat celou textovou obrazovku po jednom znaku. Textova obrazovka obsahuje 80x25
znaku. To je celkem 2000 znaku. Znaky jsou ulozeny jako ASCII hodnoty ve videopameti v segmentu 0B800h. Za
ASCII hodnot ou kazdeho znaku nasleduje jeden bajt, ktery obsahuje informace o barve daneho znaku. Pro kazdy znak
vychazi tedy dva bajty. Znaku je 2000. Tedy pujde o 4000 bajtu. Posun musime provadet o dva bajty. Pokud bychom
posouvali o bajt, posun uli bychom ASCII na barvu a barvu na ASCII.
mov cx, [cs:Kus2]
Jak jsme si rekli MOVSD presouva CXkrat, takze do CX si dame pocet znaku na obrazovce, abychom odscrolovali
prave vsechny znaky.
mov
mov
ds,
es,
[cs:Obrazovka]
[cs:Obrazovka]
Presouvame z 0B800:0002 na 0B800:0000, tyto dve hodnoty musime nacpat do ES:DI a DS:SI. Zde plnim DS a ES,
oba stejne hodnotou 0B800h.
Smycka:
Takto se oznacuje navesti, tedy misto, na ktere se budu v programu odkazovat. Treba sem budu skakat odjinud.
push cx
Registr CX ulozim do zasobniku, protoze budu jeho hodnotu menit.
mov
si,
2
;DS:SI odkud presouvam
mov
di,
0
;ES:DI kam presouvam
Toto jsou ona dve posunuti ve zdrojove a cilove adrese.
Ted uz mam v DS:SI = 0B800:0002 a v ES:DI = 0B800:0000.
mov cx, [cs:Kusanec]
Uvnitr hlavni smycky, ktera zajistuje, ze probehne 2000krat scroll, je jeste druha ktera zajistuje, ze kazdy scroll se
sklada z 1000 presunu ctyr bajtu. Ted tedy zahajuji tuto vnitrni smycku. Proto jsem si pred chvili ulozil CX na zasobnik
abyc h neprisel o pocitadlo z vnejsi smycky. Az skonci vnitrni smycka, vytahnu si pocitadlo ze zasobniku abych mohl
odpocitat vnejsi smycku.
rep movsd
A uz to frci. 1000 presunu ctyr bajtu pamet-pamet.
pop cx
Vytahuju pocitadlo pro vnejsi smycku ze zasobniku.
loop Smycka
prikaz LOOP funguje podobne jako REP. Snizi CX o jednicku a pokud neni CX=0, skoci na zadane navesti.
mov
int
ax,
21h
4c00h
Tyto dve instrukce jsou standardni konec, kazdeho EXE. Budou soucasti kazdeho vaseho programu.
END START
Konec casti START.
Minule jsem zacal trosku slozitejsim prikladem, takze ted se vratime zpatky na zem a zacnu klasickym Hello World.
Tedy programem, ktery na obrazovce vypise napis "Hello World".
MODEL SMALL
.STACK 200
.DATA
Napis
db 'Hello World$'
.CODE
START:
mov ax, seg Napis
;DS:DX ukazuje na napis
mov ds, ax
mov dx, offset Napis
;DS:DX ukazuje na text
mov ah, 9
;funkce zobraz retezec
int 21h
mov ax, 4c00h
;Konec programu, navrat do DOSu
int 21h
END START
Objevuje se nam tu poprve volani sluzby DOSu. To je to int 21h. Je to vyvolani preruseni cislo 21h. Muzete si to
predstavit jako vyvolani nejake procedury cislo 21h. Tato procedura potrebuje parametry, aby vedela co ma delat. V
nasem pripade jsou to parametry dva. V AH zadame cislo sluzby. V nasem pripade 9 coz znamena vystup retezce. V
DS:DX je ulozena adresa tohoto retezce. Retezec se ukoncuje znakem $.
Prikaz mov ax, seg Napis ulozi do ax segmentovou cast adresy promenne Napis. mov dx, offset Napis ulozi do dx cast
offsetovou.
Preruseni int 21h umi spoustu veci, ktere by se musely jinak programovat rucne. Umi to napriklad otevirat, cist a
zapisovat soubory. Spoustet dalsi programy. Cist klavesnici, psat po obrazovce, atd... Toto preruseni se vyvolava vzdy s
cislem sluzby v AH a dalsimi parametry v ostatnich registrech.
Ukazeme si napriklad vyuziti sluzby cislo 30h (Zjisti verzi DOSu)
MODEL SMALL
.STACK 200
.DATA
Napis
db 'Cislo verze DOSu je: $'
.CODE
START:
mov ax, seg Napis
;DS:DX ukazuje na napis
mov ds, ax
mov dx, offset Napis
;DS:DX ukazuje na text
mov ah, 9
;funkce zobraz retezec
int 21h
mov ah, 30h
;funkce 30, zjisti verzi
int 21h
;Hlavni cislo verze je ted v al
add al, 48
;prictu 48, abych dostal ascii kod cisla
mov dl, al
mov ah, 2
;funkce tisk jednoho znaku z DL
int 21h
mov ax, 4c00h
;Konec programu, navrat do DOSu
int 21h
END START
Sezente si nekde program jmenem SYSMAN, to je hypertext prave o takovych vecech. Mimo jine je tu i seznam vsech
techto preruseni. Dozvite se, co musite kam strcit a co, po skonceni INT, kde hledat.
Muzeme se treba podivat na praci se souborem:
Odkazy na soubor probihaji pomoci veci, ktera se jmenuje FileHandle. Je to 16-ti bitove cislo. DOS ma nekde v pameti
tabulku ve ktere ma ulozeny vsechny dulezite udaje o souboru. Aktualni pozici, jeho velikost, atd... FileHandle je potom
ukazatel do teto tabulky. Zadate-li v CONFIG.SYS FILES=20, rikate tim dosu, aby si v pameti vyhradil misto na
tabulku pro 20 souboru.
OTEVRENI SOUBORU:
Vstup:
AH = 3Dh
AL = mod otevreni
bity 7-3 = Nezajimave veci
bity 2-0 = Zpusob pristupu
000 jen pro cteni
001 jen pro zapis
010 cteni i zapis
DS:DX = ukazatel na jmeno souboru v ASCIIZ
ASCIIZ je text v normalnim ASCII ukonceny bajtem 0.
Vystup:
CF = 1 chyba
AX = cislo chyby, nam staci, ze pokud je nastaveno carry, nepodarilo se
otevrit soubor
CF = 0 bez chyby
AX = FileHandle, toto si nekam ulozte, to je jedina cesta jak muzete
pracovat s timto souborem!
UZAVRENI SOUBORU
Vstup:
AH = 3Eh
BX = FileHandle
Vystup:
CF = 1 Chyba
CTENI SOUBORU
Vstup:
AH =
BX =
CX =
DS:DX =
Vystup:
3Fh
FileHandle
Pocet nacitanych bajtu.
Ukazatel do pameti, kam maji byt umistena nactena data.
AX = Kolik bajtu bylo nacteno.
ZAPIS DO SOUBORU
Vstup:
AH =
BX =
CX =
DS:DX =
Vystup:
40h
FileHandle
Kolik bajtu zapsat
Kde jsou v pameti data, ktera maji byt zapsana na disk.
AX = Kolik bajtu bylo zapsano, jestli se to lisi od pozadovaneho poctu, mame nekde chybu.
VYTVORENI SOUBORU
Vstup:
AH = 3Ch
CL = atribut souboru
bit
bit
bit
bit
bit
bit
bit
0: read-only
1: hidden
2: system
3: volume label
4: sub directory
5: Archive
6&7: nepouzivat
DS:DX= ukazatel na ASCIIZ nazev vytvareneho fajlu
Vystup:
CF = 1 chyba
AX = kod chyby
CF = 0 bez chyby
AX = FileHandle
SMAZANI SOUBORU
Vstup:
AH = 41h
DS:DX = ukazatel ne ASCIIZ jmeno fajlu
Vystup:
CF = 1 chyba
AX = kod chyby
2 = file not found,
3 = path not found
5 = access denied
CF = 0 bez chyby, soubor je pryc
PRESUN UKAZATELE V SOUBORU
Vstup:
AH = 42h
BX = FileHandle
CX:DX = 32 bit ukazatel do souboru, kam se bude sunout.
AL = 0 CX:DX je posun od zacatku fajlu.
= 1 CX:DX je posun od aktualni pozice.
= 2 CX:DX je posun od konce souboru.
Vystup:
CF = 1 chyba AX = chybovy kod CF = 0 bez chyby, posunuto. DX:AX soucasna pozice v souboru.
ZMENA ATRIBUTU
Vstup:
AH = 43h
DS:DX = ukazatel na jmeno souboru v ASCIIZ
AL = 0 v CX vrati aktualni atributy.
AL = 1 nastavi atributy podle CX
Vystup:
CF = 1 chyba
AX = Chybovy kod
2 = file not found,
3 = path not found.
5 = access denied
CF = 0 bez problemu
Jak jsem minule slıbil, zkusıme si vyrobit program pro konverzi ces tiny. Prvnı na vrh vypadal asi takto:
MODEL SMALL
.STACK 200
.DATA
FTabulka db 'TABULKA.TAB',0
;nazev prev. tabulky
FVstup
db 'VSTUP.TXT',0
;nazev vstupniho fajlu
FVystup
db 'VYSTUP.TXT',0
;nazev vystupniho fajlu
FH2
dw 0
;filehandle vstupniho
FH2
dw 0
;filehandle vystupniho
MTabulka db 256 DUP (0)
;sem se nacte tabulka
Buffer
db 30000 DUP (0)
;buffer pro nacitana data
.CODE
START:
Tabulka
;Nactu prevodni tabulku
Otevri
;Otevru zdroj
Vytvor
;Vytvorim cil
Smycka:
Nacti
;Nactu do bufferu kus textu
Preved
;Prevedu jej
Zapis
;Zapisu prevedeny text do fajlu
jne Smycka
;a furt dokola, cely soubor
Zavri1
;Zavru zdrojovy
Zavri2
;Zavru cilovy
mov ax, 4c00h
;Konec programu, navrat do DOSu
int 21h
END START
Je to vlastnř hruby na vrh. Vypada to, z e by to takto mohlo fungovat, teÍ zbyva "jenom" naprogramovat jednotlive
procedury. Procedura je kus kodu zacınajıcı prıkazem PROC. Za nım je uveden na zev procedury, pak na sledujı
norma lnı assemblerovske prıkazy a cele to koncı prıkazem ENDP a za nım opřt na zev procedury. Takz e treba
procedura, ktera pricte jednicku k AX (mimochodem přkna kravina).
PROC Pricti
inc ax
ret
ENDP Pricti
Potom m˚z ete uvest v hlavnım programu prıkaz call Pricti, ktery zp˚sobı zvys enıax o jednicku. Prıkaz call je vola nı
procedury.
D˚lez ita je instrukce ret, ktere zp˚sobına vrat z procedury.
Jes tř bych mřl vysvřtlit co dřla DUP.
MTabulka db 256 DUP (0)
zp˚sobı, z e promřnna MTabulka bude zpoca tku obsahovat 256 nul.
Zacneme vyrobou procedury Tabulka, ta ma za ˚kol nacıst ze souboru prevodnıtabulku do pamřti. Takz e otevrenı
souboru, nactenı 256 bajt˚ (to je cela tabulka) a uzavrenısouboru.
PROC Tabulka
mov
ax,
mov
dx,
int
21h
mov
push
mov
mov
mov
int
bx,
bx
ah,
cx,
dx,
21
3D00h
offset FTabulka
;Otevreni sou boru, read only
;DS:DX ukazuje na nazev fajlu
ax
;filehandle do bx
;uschovat na pozdeji
;cteni souboru
;FF bajtu (256)
;DS:DX kam nacist
3Fh
0FFh
offset MTabulka
pop
bx
mov
ah,
3Eh
int
21
ret
ENDP Tabulka
Dals ıje Otevri a Vytvor, mřlo by to byt lehke.
PROC Otevri
mov
ax,
3D00h
mov
dx,
offset FVstup
int
21h
mov
FH1,
ax
ret
ENDP Otevri
;vyndat uschovane filehandle
;zavre ni souboru
;Otevreni souboru, read only
;DS:DX ukazuje na nazev fajlu
;schovat filehandle
PROC Vytvor
mov
ah,
3Ch
;Vytvoreni souboru
mov
cl,
0
;Zadny specialni atribut
mov
ds
offset FVystup
;DS:DX jmeno vyrabeneho fajlu
int
21h
mov
FH2, ax
;Schovat filehandle
ret
ENDP Vytvor
Procedura Nacti by mřla vz dy nacıst do bufferu bajty ze vstupnıho souboru. Kdyz jich nactu menř, nez jsem zadal,
znamena to, z e jsem na konci souboru.
PROC Nacti
mov
bx,
FH1
;filehandle do bx
mov
ah,
3Fh
;cteni souboru
mov
cx,
30000
;30000 bajtu, cely buffer
mov
dx,
offset Buffer
;DS:DX kam nacist
int
21
push ax
;ulozit kolik bajtu bylo nacteno
ret
ENDP Nacti
Dalsi procedura, prevadi podle tabulky. Tabulka je vlastnř 256 cısel. Jestliz e ma treba AL hodnotu 15, najde se v
tabulce 15-ty udaj a ten se uloz ı do AL. Takz e tabulka, ktera neprova dı z a dny prevod, bude obsahovat postupku
0,1,2,3,4,5,6,7,8,9,10,11,....255.
PROC Preved
cld
;Ukazatele se budou zvysovat
mov
bx,
offset MTabulka
;Ukazatel do tabulky
mov
si,
offset Buffer
;Ukazatel do bufferu (cteni)
mov
di,
si
;Ukazatel do bufferu (zapis)
mov
cx,
ax
;Kolik bajtu budu prevadet
xor
ah,
ah
;Znuluju AH
Kolco:
push bx
;Schovam si zacatek tabulky
lodsb
;AL = [DS:SI]
add
bx,
ax
;Posunu se v tabulce
mov
al,
[ds:bx]
;Prevedu
stosb
;Zapisu zpatky do bufferu
pop
bx
;Zase uk azuji na zacatek tab.
loop Kolco
;a dalsi bajt bafru
ret
ENDP Preved
Dals ıvřc je opřt jednoducha , za pis prevedeneho bufferu do fajlu.
PROC Zapis
mov
ah,
40h
;Zapis fajlu
mov
bx,
FH2
;filehandle
pop
cx
;kolik bajtu zapsat
push cx
;jeste se to bude hodit
mov
dx,
offset Buffer
;Kde jsou zapisovana data
int
21h
ret
ENDP Zapis
Takz e to sepıs u dohromady a vykas lu se na procedury, jelikoz z a dnou z nich nevykona va m vıckra t, nemajısmysl a
navıc jes tř prida vajı ret, coz je malilinkata ztra ta casu.
MODEL SMALL
.STACK 200
.DATA
FTabulka db 'TABULKA.TAB',0
;nazev prev. tabulky
FVstup
db 'VSTUP.TXT',0
;nazev vstupn iho fajlu
FVystup
db 'VYSTUP.TXT',0
;nazev vystupniho fajlu
FH1
dw 0
;filehandle vstupniho
FH2
dw 0
;filehandle vystupniho
Buffer
db 30000 DUP (0)
; buffer pro nacitana data
MTabulka db 256 DUP (0)
.CODE
START:
mov
ax,
seg FTabulka
;Nejdrive nastavim DS
mov
ds,
ax
mov
es,
ax
;A ES
mov
mov
int
ax,
dx,
21h
3D00h
offset FTabulka
;Otevreni souboru, read only
;DS:DX ukazuje na nazev fajlu
mov
push
mov
mov
mov
int
bx,
bx
ah,
cx,
dx,
21h
ax
3Fh
0FFh
offset MTabulka
;filehandle do bx
;uschovat na pozdeji
;cteni souboru
;FF bajtu (256)
;DS:DX kam nacist
pop
mov
int
bx
ah,
21h
3Eh
;vyndat uschovane filehandle
;zavreni souboru
mov
mov
int
mov
ax,
dx,
21h
FH1,
3D00h
offset FVstup
;Otevreni souboru, read only
;DS:DX ukazuje na nazev fajlu
mov
mov
mov
int
mov
ah,
cl,
dx,
21h
FH2,
3Ch
0
offset FVystup
;Vytvoreni souboru
;Zadny specialni atribut
;DS:DX jmeno vyrabeneho fajlu
ax
;S chovat filehandle
FH1
3Fh
30000
offset Buffer
;filehandle do bx
;cteni souboru
;30000 bajtu, cely buffer
;DS:DX kam nacist
ax
;schovat fil ehandle
Smycka:
mov
bx,
mov
ah,
mov
cx,
mov
dx,
int
21h
push ax
cld
mov
bx,
mov
si,
mov
di,
mov
cx,
xor
ah,
Kolco:
push bx
lodsb
add
bx,
mov
al,
;ulozit kolik bajtu bylo nacteno
offset MTabulka
offset Buffer
si
ax
ah
;Ukazatel do
;Ukazatel do
;Ukazatel do
;Kolik bajtu
;Znuluju AH
tabulky
bufferu (cteni)
bufferu (zapis)
budu prevadet
ax
[ds:bx]
;Schovam si zacatek tabulky
;AL = [DS:SI]
;Posunu se v tabulce
;Prevedu
stosb
pop
bx
loop Kolco
mov
mov
pop
push
mov
int
ah,
bx,
cx
cx
dx,
21h
pop
ax
cmp
ax,
jnb Smycka
;Zapisu zpatky do bufferu
;Zase ukazuji na zacatek tab.
;a dalsi bajt bafru
40h
FH2
offset Buffer
;Zapis fajlu
;filehandle
;kolik b ajtu zapsat
;jeste se to bude hodit
;Kde jsou zapisovana data
30000
;vytahnu si pocet nactenych bajtu
;byl to cely bafr?
;a furt dokola, cely soubor
mov
mov
int
ah,
bx,
21h
3Eh
FH1
;zavreni fajlu
;filehandle
mov
mov
int
ah,
bx,
21h
3Eh
FH2
;zavreni fajlu
;filehandle
mov ax, 4c00h
;Konec programu, navrat do DOSu
int 21h
END START
Vřts inu třchto instrukcızna te, zbyva vysvřtlit tri nove:
LODSB
NaplnıAL hodnotou, kterou vezme z [DS:SI], potom posune SI, tak, aby ukazoval na dals ı bajt. BuÍto jej
zvys ı, nebo snız ı o jednicku. Jestli se bude zvys ovat, nebo sniz ovat, za lez ına nastavenı DF (Direction Flag),
DF je prıznak, kterym smřrem probıhajı takoveto operace.
STOSB
Obra cena instrukce k LODSB. Uloz ı AL do pamřti na adresu urcenou ES:DI a pote opřt upravıukazatel (v
tomto prıpadř DI), buÍ jej zvys ı, nebo snız ı.
CLD
Tohle je pra vř to co urcuje, jestli se ukazatele budou zvys ovat, nebo sniz ovat. Tımto prıkazem nastavıte DF,
tak, aby se ukazatel zvys oval. Pro nastavenına sniz ova nıje instrukce STD.
Aha jak se tak dıva m, tak ono je tu novřjs ıch vřcı vıc, takz e:
ZA SOBNI K
Za sobnık je kus pamřti slouz ıcık odkla da nı udaj˚. Hlavnı pouz itı bude asi pro uchova va nı na vratovych adres pri skoku
do podprogramu. Jestliz e je nřkde v programu instrukce CALL (vola nıpodprogramu) provede procesor na sledujıcı
akce:
1.
2.
3.
Uloz ı si do za sobnıku na vratovou adresu, tedy adresu instrukce, ktera na sleduje po instrukci call.
Skocı do podprogramu, tento prova dı, az narazı na instrukci RET
Vyta hne ze za sobnıku na vratovou adresu a skocı na ni, tedy pokracuje ve vykona va nıza instrukcı call.
Za sobnık je pamřň typu LIFO (Last In First Out), to znamena , z e, to co tam da te naposledy vyta hnete jako prvnı.
Predstavte si to jako hromadu hlinřnych desticek. Tu kterou poloz ıte jako poslednına hromadu, musıte zvednout jako
prvnı. V pamřti je to ale tak, z e desticky prida va te dospodu stohu. Takto vypada zjednodus enř Stack Segment (SS) tedy
ca st pamřti, kde se nacha zı za sobnık. Na vrs ek hromady ukazuje SP (Stack Pointer).
FFFFh
X5 nejstarsı polozka zasobnıku
X4 druha nejstarsı
X3
X2
X1
<---- Sem ukazuje SP
0000
Jestliz e nřco do za sobnıku prida te, vrazı se to dospodu a SP se SNIZI. Po vytaz enıze za sobnıku se SP opřt ZVYSI.
Pro uloz enı hodnoty na za sobnık slouz ıinstrukce PUSH. Jejım argumentem je vřts inou s estna ctibitovy registr. Takz e
treba PUSH AX uloz ıobsah AX do za sobnıku. opakem PUSH je POP, ktera hodnotu vyjme, takz e POP AX vezme
poslednı hodnotu, ktera byla uloz ena na za sobnık a uloz ı ji do AX. Takz e finta pro prohozenı dvou registr˚:
PUSH AX
;na vrsku zasobniku je AX
PUSH BX
;na vrsku zasobniku je BX
POP AX
;BX z vrsku jsem presunul do AX
POP BX
;vyjmutim BX se na vrsek dostalo AX a to dam do BX
Za sobnık je svinř a pokud s nım chcete kouzlit, buÍte hodnř opatrnı, je to jedna z lehcıch cest, jak si resetnout pocıtac.
Uffff!!!