Scrierea programelor rezidente pentru MS DOS
Articolul descrie pașii de bază folosiți la scrierea programelor rezidente în asamblare pentru sistemul de operare MS DOS. La sfârșitul articolului, un exemplu de program rezident este discutat în detaliu.
Un program rezident pentru MS DOS este un fragment de cod care se află în memoria calculatorului și se numește atunci când apar anumite condiții. Apoi, vă vom arăta cum să scrieți un program rezident în asamblare care este permanent în memorie și apelat atunci când apare o întrerupere în sistem. Mai întâi, ia în considerare definițiile și principalele tipuri de întreruperi pentru procesoarele x86.
O întrerupere pentru procesoarele x86 este un eveniment din sistem care necesită o prelucrare. Dacă se produce o întrerupere, cu excepția unui caz, executarea programului curent este întreruptă și întreruperea este procesată. După procesarea întreruperii, executarea programului întrerupt continuă.
Pentru procesoarele x86 există următoarele tipuri de întreruperi: întreruperi hardware, software și procesoare interne. Întreruperile hardware, la rândul lor, sunt împărțite în măști și cele care nu pot fi mascate. Masinile hardware intrerupte in anumite conditii pot fi ignorate de catre procesor, iar intreruperile non-mascabile sunt intotdeauna prelucrate.
Întrerupere hardware poate fi definită ca o cerere de la un dispozitiv periferic (tastatură, port serial, unitatea floppy, și așa mai departe. D.) Din acest dispozitiv de prelucrare a datelor, gestionarea sau apariția o excepție de la acest aparat. În cazul unei astfel de cereri, programul actual este întrerupt (în cazul în care întreruperea nu este mascat), iar procedura se numește un handler de întrerupere. Operatorul de întrerupere efectuează acțiunile necesare pentru a obține date de la sau pentru a controla dispozitivul periferic și readuce controlul la programul întrerupt.
întreruperi software sunt apelați orice servicii sau funcții ale sistemului de operare și aplicații folosind comanda INT XX în care XX - număr de întrerupere de la 0 la 255. Procesorul intern întrerupe apar atunci când programul de operații care cauzează erori fatale (de ex împărțirea cu 0, depășirea în divizare, depășirea unui segment etc.) și, de asemenea, atunci când se utilizează modul de depanare.
În orice caz, în cazul în care apare o întrerupere de orice tip, se solicită procedura de întrerupere a procesorului, care este o procedură special creată. Pentru întreruperile hardware, dispozitivul de întrerupere trebuie să funcționeze, împreună cu dispozitivul care a provocat întreruperea operațiilor, pentru a controla hardware-ul mecanismului de întrerupere al procesorului x86.
Luați în considerare procesul de scriere a procedurii pentru procesorul de întrerupere în asamblare, numit atunci când apare o întrerupere de software. Structura generală și sintaxa pentru programul de întrerupere a programului:
NAME ID-ul specifică numele procedurii de tratare, care poate fi orice secvență de caractere permise în adunare, dar trebuie să existe un funcționar sau un cuvânt rezervat.
În secțiunea 1, toate registrele care sunt modificate în procedura de manipulare sunt stocate. Acest lucru este necesar pentru ca, după ce controlul revine la programul întrerupt, primește registrele în aceeași formă ca înainte de a fi programată întreruperea software-ului. Dacă întreruperea ar trebui să returneze unele rezultate în registrele care au denumit programul, atunci valoarea acestor registre nu este necesară.
În secțiunea 2 inițializează DS, ES sau segment SS înregistrează handlerul de întreruperi pentru manipularea procedurilor la datele sale interne, stiva sau unele segmente suplimentare. Valorile registrelor inițializate trebuie să fie stocate în secțiunea 1.
În secțiunea 3, de fapt, a efectuat codul principal al procedurii de tratare a întreruperii, acțiunile necesare și valorile înregistrate în registre atunci când o întrerupere trebuie să revină la unele rezultate în registrele cauzate de programul său.
În secțiunea 4, valorile sunt restabilite pentru registrele manipulatorului de întrerupere, modificate de procedură, cu excepția registrelor în care programul care a numit întrerupe returnă rezultatele.
Comanda IRET revine din rutina procesorului de întrerupere la programul de apel.
Să analizăm în detaliu ce acțiuni au efectuat comenzile INT și IRET.
Stivele sunt stocate în următoarea secvență: registrul de steaguri, registrul segmentului CS, registrul indicatorului de instrucțiuni IP. Steagurile IF și TF sunt resetate în registrul de steaguri.
Se calculează offsetul față de începutul tabelului de vectori de întrerupere: offset = XX * 4, unde XX este numărul de întrerupere.
În segmentul CS segmentat, valoarea segmentului handler de întrerupere este scrisă din tabela vectorială de întrerupere calculată din tabela vectorială de întrerupere calculată și decalajul handlerului de întrerupere din registrul IP.
Comanda este transferată la dispozitivul de întrerupere a software-ului. În acest caz, toate registrele cu excepția CS, IP și registrul de steaguri își păstrează valoarea așa cum a fost înainte de a fi apelată comanda INT XX.
Astfel, atunci când intrați în programul de întrerupere a programului, valorile CS, IP și registrul steagurilor sunt în stivă. Aceste valori au fost înregistrate în aceste registre înainte ca comanda INT XX să fie apelată. În partea de sus a stivei se află valoarea registrului IP.
Când apelați comanda IRET, se efectuează următoarele acțiuni:
Valoarea registrului IP este restabilită din stack.
Valoarea registrului CS este restabilită din stack.
Valoarea registrului de steaguri este restabilită din stivă.
Există un transfer de control la programul întrerupt, la comanda imediat din spatele programului de comandă întrerupe INT XX.
După executarea comenzii IRET, structura stivei devine aceeași ca înainte de a fi apelată comanda INT XX.
Acestea sunt punctele principale folosite în scrierea întreruperilor. Luați în considerare acum structura și funcționarea handler-ele de întrerupere hardware.
Spre deosebire de programele de întrerupere a programelor, manipulatorii de întrerupere a hardware-ului sunt invocați nu de comanda INT, ci de procesor în sine. Sa spus mai sus că atunci când se scriu handlers de întrerupere a hardware-ului, aceștia trebuie să efectueze și anumite acțiuni pentru a controla hardware-ul mecanismului de întrerupere al procesorului x86. În cel mai simplu caz, structura unui astfel de handler arată astfel:
Comanda OUT 20h, AL efectuează acțiuni pentru a controla hardware-ul mecanismului de întrerupere al procesoarelor x86. Mai exact, acesta trimite un semnal EOI (End of Interrupt) către controlerul de întrerupere, informându-l că procesul de întrerupere a hardware-ului este complet.
Comanda OUT 20h, AL, numită la sfârșitul handlerului de întrerupere hardware, deblochează controlerul de întrerupere, permițându-i să funcționeze cu întreruperile dezactivate anterior.
În cazul în care este necesar pentru a scrie un handler întrerupere hardware, care are doar pentru a efectua anumite acțiuni, atunci când are loc o întrerupere hardware (de exemplu, pentru a emite un sunet atunci când este apăsată o tastă), activitatea de sistem adecvat de gestionare a echipamentelor pot fi atribuite unui handler de întrerupere hardware. În acest caz, structura manipulatorului va fi după cum urmează:
În acest caz, echipa JMP SYS_HANDLER efectuează sari departe la sistemul de tratare a întreruperii, astfel încât la sfârșitul handler-ul nostru nu are nevoie pentru a invoca comanda IRET - este numit în procesorul de sistem.
Odată ce se stabilește modul în care procedura de a emite un hardware sau software de tratare a întreruperii, ia în considerare acțiunile necesare pentru a se asigura că această procedură de tratare se numește atunci când apare o întrerupere.
Luați în considerare acum operațiile necesare pentru setarea segmentului și offset-ul din tabel pentru programul de procesare sau întreruperea hardware-ului, în care va fi apelat operatorul de sistem al acestei întreruperi. Pentru a face acest lucru, înainte de a scrie în tabel noile valori ale segmentului și offset-ului, trebuie mai întâi să salvați valorile segmentului și offset-ul sistemului de operare:
Dacă setați valorile segmentului și offsetul handlerului de întrerupere a hardware-ului, trebuie mai întâi să resetați flagul IF (comanda CLI), iar după setarea noilor valori, setați flagul IF (comanda STI). Acest lucru este necesar pentru a vă asigura că nu există întreruperi hardware în timpul setării valorilor segmentului și a decalajului.
La scrierea manualului de întrerupere a hardware-ului, trebuie să țineți cont de faptul că trebuie să fie finalizată înainte de următoarea întrerupere hardware a acestui handler. Dacă această condiție nu este îndeplinită, atunci, în cel mai bun caz, întreruperea care a apărut se va pierde. În cel mai rău caz, nerespectarea acestei condiții poate duce la pierderea de date sau la un accident de computer. De exemplu, atunci când scrieți un handler de întrerupere hardware dintr-un cronometru, codul de manipulare trebuie să fie executat în timp mai mic de 1/18 secunde. deoarece întreruperile temporizatorului sunt generate în mod implicit de 18,2 ori pe secundă. Același lucru se poate spune despre manipularea hardware-ului de întrerupere de la tastatură - codul handler-ului ar trebui să fie executat nu mai mult decât întârzierea repetării simbolului.
De asemenea, atunci când scrieți un handler de întrerupere, trebuie să inițializați registrul segmentului DS dacă manipulatorul accesează locațiile de memorie internă. În schimb, puteți accesa celulele de memorie utilizând prefixul de înlocuire a segmentului (de exemplu CS: [BX]), dar acest lucru crește mărimea comenzii corespunzătoare. Utilizarea prefixului de înlocuire a segmentului este eficientă atunci când numărul de apeluri către celulele de memorie internă ale handlerului este mic (2 - 3).
Luați în considerare acum mijloacele pentru finalizarea programului rezident și stocarea unora din codul său în memorie pentru o utilizare ulterioară atunci când apar întreruperi.
Întreruperea DOS INT 27h. Întreruperea intenționează să pună capăt programului și să îl stocheze în memorie. Pentru aceasta, numărul de octeți pentru partea memorată a programului plus un octet trebuie introdus în registrul DX. Începutul programului stocat coincide cu un raport de offset la 0000h segmentului de cod, astfel încât pentru programul COM trebuie să țină seama de dimensiunea prefixul segmentului de program (PSP - Programul Segment Prefix) - 256 bytes.
Întrerupeți DOS INT 21h, funcția 31h. Rutina de întrerupere DOS INT 21h efectuează aceleași acțiuni ca întreruperea DOS INT 27h, însă registrul DX stochează dimensiunea părții de program salvate în paragrafe (16 blocuri de memorie octet). De asemenea, este posibil să se determine codul de retur atunci când programul rezident termină (este introdus în registrul AL).
Mai jos este structura generală a programului rezident:
; datele pentru partea rezidentă a programului
HANDLER ENDP
; date pentru partea nerezidentă a programului
; partea principală a programului (nerezident)
Următorul fragment de cod oferă un exemplu de definire a structurii principale a unui program rezident în asamblare (tipul de program COM):
Luați în considerare funcționarea programului.
Procedura de decodificare convertește un număr zecimal binar în registrul AL în două caractere ASCII corespunzătoare valorii orelor, minutelor sau secundelor (aceasta depinde de valoarea specifică înregistrată în registrul AL). Procedura se adaugă la valoarea de biți (LSB stocate în primele patru biți ai AL înregistra senior - în partea superioară a patru biți) codul ASCII pentru caracterul „0“, generând astfel de cifre de cod ASCII pentru descărcarea mai tineri sau mai în vârstă. Apoi, acest cod ASCII este scris în poziția curentă a șablonului. După înregistrarea unui pointer la curent șablon model caracter este crescut cu 3 (două cifre pentru ore, minute sau secunde, plus simbolul „:“).