Rezidentní programy jsou obecně takové programy, které zůstávají v paměti i po ukončení. Definice je jednoduchá, stejně tak je jednoduché i psaní rezidentních programů. Je ale potřeba znát některé důležité věci, bez kterých končí první vyvolání rezidentní rutiny krachem systému.
Poznámka: Od teďka se již vůbec nebudu zmiňovat o tom, že si to a to můžeš přečíst v SYSMANovi. Znalost veškerých parametrů služeb, adres portů, zde nepopsaných instrukcí atd. budu brát jako samozřejmnost.
Již u popisování instrukce INT jsem se lehce zmínil o tom, že existují dva druhy přerušení. Lépe řečeno - žádné druhy nejsou, jen některá přerušení jsou na určitý podnět sama volána řadičem přerušení(příchod znaku z portu, časovač, stisknutí/uvolnění klávesy ...). K tomu je třeba dodat několik věcí :
A SEGMENT ASSUME CS:A,DS:A ORG 100H .386 START: JMP SETUP ; Skočím na inicializační část programu VISIM: INC CS:[CAS] ; Přičtu si svůj interní časovač TEST CS:[CAS],15 ; Jsou jeho 4 dolní bity=0 ? JNZ SEM ; Ano, neboli časovač je dělitelný 16-ti PUSH ES AX ; Uložím hodnoty ES a AX MOV AL,20H OUT 20H,AL ; Viz. vysvětlení MOV AX,0B800H MOV ES,AX ; Adresa videopaměti(v text. módu) do ES MOV AX,CS:[CAS] SHR AX,4 ; Do AX jde čas dělený 16-ti(které písmeno vykreslit) ADD AL,65 ; Přičtu ASCII hodnotu písmena "A" MOV ES:[0],AL ; Dám do videopaměti POP AX ES ; Původní registry SEM: DB 0EAH ; Viz. vysvětlení PUVOB DD 0 ; Adresa původní obsluhy přerušení CAS DW 0 ; Můj časovač SETUP: MOV AX,3508H INT 21H ; Zjištění adresy obsluhy přerušení MOV WORD PTR CS:[PUVOB],BX MOV CS:[PUVOB+2],ES ; Uložím si ji do proměnné PUVOB MOV DX,OFFSET VISIM ; Adresa nové obsluhy přerušení(mojí) MOV AX,2508H INT 21H ; Nastavení adresy MOV DX,OFFSET SETUP+1 INT 27H ; Ukončí program, ale nechá ho v paměti A ENDS END STARTA teď to vysvětlím(napsat to zabere tak půl hodiny...) :
O původní obsluze přerušení 8 se vrátím ještě později. Teď k druhé části otázky.
Služby 35 a 25 zjišťují a nastavují adresu obsluhy přerušení. To je
známá věc, ale proč používat nějakých služeb, když si přece můžu adresu
sám nastavit v paměti na adrese 0:(číslo přerušení*4) ? Použít služeb DOSu
je kratší a jednodušší. Nemusíš nastavovat segm. registr(nejspíš ES) na 0
a přesouvat nějaké hodnoty.
A teď si ještě uvědom, jak překladač přeloží instrukci INC CAS.
Překladač ji(celkem logicky) přeloží jako INC WORD PTR DS:[OFFSET CAS]
(samozřejmě ne jako tenhle text, ale jako kód odpovídající tomuto textu).
Takže v rez. rutině by byl právě tento příkaz : Přičti číslo na adrese DS:[něco]
o jedna. Ale registr DS ukazuje někam do Nortona a přičítání by se nejen
provedlo na špatném místě, ale zřejmě by(po nějaké době) vedlo ke zboření
nortona.
Proto musíš použít buď INC CS:[CAS] nebo předtím nastavit registr
DS na CS. Pak bys mohl používat normální INC CAS.
Při psaní normálních programů v assembleru ses zřejmě ještě nepotkal
s tím, že by registr DS ukazoval jinam, než na tvůj datový segment(jak
víš-v COM souborech platí, že CS=DS(po spuštění)). Jenže si představ
situaci rezidentní rutiny - Běží nějaký normální program(třeba Norton)
a najednou se vyvolá přerušení 8, čímž se aktivuje ona rezidentní rutina.
Jenže jak je to s registry. Veškeré registry kromě CS a IP(a trochu
změněných flagů) jsou v takovém stavu, jak je nechal Norton.
To už je vlastně vysvětlené o bod výš. ES a AX jsou jediné registry, které
používáš a musíš zařídit, aby po návratu do Nortona obsahovaly to
co jsi ty dostal na začátku. Proto si je zálohuješ.
Tahle věc není v tomto konkrétním rezidentu nutná, ale pro názornost
jí tam píšu. Když řadič přerušení zavolá nějaké hardwarové přerušení,
zapamatuje si, že od teďka nesmí žádné další vyvolat. Impulsem, že
již může je právě poslání čísla 20H na port 20H. Teď to není nutné,
protože vždy volám původní obsluhu(níže) a ona to na ten ředič pošle
za nás. Zkus si představit stav, když zapomeneš tyto dvě instrukce
uvést - Nemůže nastat žádné hardwarové přerušení, neboli počítač není
schopen zachytit(spíš zpracovat) žádný podnět zvenku(stisk klávesy,
myš ...). Co se asi stane ?
Jak vypadá instrukce FAR-JMP přepsaná do jazyka procesoru ? Je to číslo 0EAH, následuje čtyř-bytová adresa, kam skočit. Už se rozednívá ? Procesor mi sice "vleze" do proměnných, jenže ty mají tak fikaný hodnoty, že to procesor přečte jako skok na původní obsluhu. Tak zabere skok vlastně jen jeden byte(adresa tam tak jako tak je).
Jde to udělat i bez použití takovýchto fíglů - Stačí napsat JMP DWORD PTR CS:[PUVOB]. Přeložím to - Skoč na adresu, která je uložená na adrese CS:[PUVOB]. Instrukce přečte 4 byty(DWORD) z adresy CS:[PUVOB] a skočí na ni.
Poznámka pro ty, kteří nečtou text odzhora dolů : Pokud nechápeš, co má Norton společného s rezidenty, přečti si třetí bod vysvětlení. Pochopíš, že to je jen příklad.
A SEGMENT ASSUME CS:A,DS:A ORG 100H START: .286 JMP SETUP VISIM: CMP AH,41H ; Služba DOSu "Smaž soubor" JZ NEMAZ CMP AH,14H ; Služba DOSu "Smaž soubor přes FCB" JZ NEMAZ CMP AH,3AH ; Služba DOSu "Smaž adresář" JZ NEMAZ JMP SEM ; Nic se nemaže, skočím na pův. obsluhu NEMAZ: PUSH BX ; Mazat se nebude ! MOV BX,SP OR WORD PTR SS:[BX+6],1 ; Nastavím vlajku CF(=nastala chyba) MOV AX,5 ; Nějaký chybový kód POP BX IRET SEM: DB 0EAH PUVOB DD 0 SETUP: MOV AX,3521H ; Klasická inicializační část, no comment. INT 21H MOV WORD PTR CS:[OFFSET PUVOB],BX MOV WORD PTR CS:[PUVOB+2],ES MOV AX,2521H MOV DX,OFFSET VISIM INT 21H MOV DX,OFFSET SETUP INT 27H A ENDS END STARTJeště to vysvětlit a můžu konečně začít pařit Dunu 2000(mimochodem, pro ty, kteří hráli DUNU II je to pěkně chabý. A jednoduchý).
Pokud bych se vykašlal na nastavování CF a rovnou udělal IRET, program, který se snažil smazat soubor by vůbec nepoznal, že se mazání neuskutečnilo. Ale já chci, aby se to program(a hlavně uživatel) dozvěděl. Proto do AX dám nějaké číslo(to si klidně vymyslím, hlavně že tam je) a nastavím CF.
PUSHF PUSH CS, PUSH IP IF <- 0, TF <- 0 ; Tohle musím taky někdy vysvětlit ...A instrukce IRET pak zase všechno POPne. Takže pokud nastavím CF a pak zavolám IRET, CF se mi zase nastaví na nula(předpokládám, že už předtím bylo nula). Já to musím zařídit tak, aby instrukce POPla vlajky s nastaveným CF. Neboli - musím změnit uložené flagy přímo v zásobníku. Ale kde je najít ?
Stačí si spočítat, kolikrát se do zásobníku něco uložilo poté, co se tam daly hledané vlajky. Počítáme : Dalo se tam CS, IP a BX. Takže 3 16-bytová čísla = 6 bytů. A protože se do zásobníku ukládá odzhora dolů, musím těch 6 k aktuálnímu SP přičíst. Protože je CF umístěn hned v nultém bitu vlajek, stačí to ORnout jedničkou.
Uvedené rezidenty |
.
.
Pokud někdo vlastní právě tuto verzi mého dokumentu, tak ať ví, že zde bude v budoucnosti pokračovat další výklad ...
.
.
Z vlastní zkušenosti doporučuji používat Volkov Commander při psaní rezidentů. Má jednu funkci k nezaplacení - dokáže odstranit(Alt-F5) všechny (jednoduché) rezidentní programy, které z něj spustíš. To je neocenitelná věc, protože většina tvých rezidentů bude nejspíš neodinstalovatelná. A reset po každém nepodařeném pokusu je hrozná ztráta času ...
Jak tak přemýšlím nad tím, co jsem teď napsal a vzpomínám na doby před třemi čtymi lety, dospívám k názoru, že by nebylo úplně od věci napsat úvahu na téma "Význam rezidentních programů v době WINDOWS 95 a hlavně WINDOWS NT." Fakt je ten, že ve woknech nemají rezidenty valný význam. Jinými slovy - nechodí.
Ale mě se stejně podařilo napsat vira, který používá pouze DOSovské služby a dokáže se množit i ve WIN 95. Pokud je spuštěn už před startem woken(třeba v autoexecu), dokáže se množit v DOSovských programech puštěných z WIN 95(pustíš Volkova z woken a vir se šíří).
Úvodní stránka | Zbylé instrukce | První program |
Stránku připravuje Lukáš Valenta,
1. v celostátním kole soutěže v programování, kategorie mládež.