Asembler w TSR KURS3


MINI KURS PISANIA PROGRAMÓW TSR W ASEMBLERZE

3. USUWANIE REZYDENTA Z PAMIĘCI I JAKIE SĄ Z TYM ZWIĄZANE PROBLEMY

W poprzednim odcinku dowiedzieliśmy się, jak napisać prosty sekundnik
instalowany rezydentnie w pamięci. Cały problem w tym, że po jednorazowym
zainstalowaniu takiego TSRa zabiera on nam kawałek cennej pamięci, a gdy już
znudzą nam się cyferki wciąż widoczne na ekranie - pozostaje tylko reset
komputera. Przyszła pora na poznanie kolejnej techniki, którą będziemy
stosować, a mianowicie sposób na rozinstalowanie rezydenta, czyli powrót do
stanu sprzed zainstalowania.

Na początku należy się zastanowić - co tak właściwie musimy zrobić, aby
nasz komputer działał tak, jakbyśmy nigdy TSRa nie uruchamiali. Po pierwsze:
należy sprawdzić, czy w ogóle nasz rezydent jest obecny w pamięci.
Najprościej sprawdzić wektor przerwania, które on przechwycił podczas
instalacji (czyli w przypadku sekundnika będzie to przerwanie 8), a potem
upewnić się, że pod podanym adresem jest obecny nasz TSR. W tym celu możemy
po prostu porównać offset (przesunięcie w segmencie) początku naszej
procedury z offsetem podanym nam przez funkcję DOSu czytającą wektor
przerwania (funkcja 35h przerwania 21h). Jednakże takie proste sprawdzenie
może czasem nie przynieść dobrych rezultatów, gdy oprócz sekundnika w
pamięci są obecne inne programy TSR o tych samych offsetach procedur
podpiętych pod przerwanie zegara. Największą wiarygodność możemy uzyskać
tylko przez sprawdzenie czegoś unikalnego dla naszego rezydenta. W praktyce
wystarczy porównanie ciągu znaków pod znanym adresem z naszym wzorcem - kiedy
się zgadzają to możemy kontunuować usuwanie TSRa z pamięci komputera.

Po stwierdzeniu obecności TSRa i sprawdzeniu przechwytywanych przez
niego przerwań (w przypadku sekundnika jest to jedno przerwanie - nr 8),
możemy odczytać oryginalne wektory tych przerwań (wiemy bowiem, w którym
miejscu w rezydencie są one "zaszyte") i przywrócić je (funkcja 25h
przerwania 21h). Pozostaje już tylko zwolnić bloki pamięci zajmowane przez
sekundnik, wypisać na ekranie komunikat o pomyślnym usunięciu rezydenta i
normalnie powrócić do DOSu (funkcja 4ch przerwania 21h). Oczywiście przy
instalacji programu warto również sprawdzić, czy już wcześniej nie był
instalowany, by uniknąć dwukrotnej instalacji. Praktyczną realizację tych
kilku kroków możecie prześledzić analizując kod źródłowy podany w dalszej
części.

Chwila na krótkie wyjaśnienie: DOS przydziela programom pamięć w blokach
o długości będącej wielokrotnością 16 bajtów. Poza takimi blokami danych mogą
wystąpić jeszcze bloki z kodem programu oraz bloki z otoczeniem (tam są
przechowywane wszystkie ustawienia otoczenia programu, czyli wartości nadane
przez PATH, SET, PROMPT itp. - można je wyświetlić komendą SET). Każdy
program przy uruchomieniu "otrzymuje" swój blok z kopią otoczenia DOSowego,
które może dowolnie modyfikować (np. zmienić ścieżkę wyszukiwania PATH) i
odczytywać (chcąc pobrać parametry otoczenia). Prócz samej zawartości
otoczenia na końcu bloku jest wpisywana ścieżka dostępu i nazwa pliku
"właściciela", czyli programu, do którego należy dane otoczenie, np.
C:\MASM\PROGS\KURS\MOJPROG1.COM. Jak czytać parametry otoczenia dowiemy się
kilka odcinków dalej. Przy zakończeniu programu otoczenie jest automatycznie
zwalniane - zmiany, które program w nim poczynił są tracone. Oczywiście
zostawiając TSRa w pamięci fragment bloku z kodem programu zostaje
(wielkość fragmentu zaznaczamy w rejestrze DX przy wywołaniu przerwania 27h),
natomiast reszta jest zwalniana (czyli blok jest skracany), blok z otoczeniem
również pozostaje na swoim miejscu. Dlatego często w TSRach blok otoczenia
jest zwalniany już w czasie instalacji, aby zmniejszyć wielkość pamięci
zajmowanej przez rezydenta. Tak też będzie w nowej wersji sekundnika. Numer
segmentu otoczenia (środowiska) odczytamy ze słowa 16-bitowego umieszczonego
w segmencie programu pod adresem 002ch (czyli w obszarze PSP, o tym będzie
później).

A oto przydatne informacje:

Funkcja 49h
Nazwa: Zwalnianie pamięci
Wywołanie: AH=49h
ES - segment, w którym znajduje się zwalniana pamięć
Powrót: Ustawiony znacznik C : AX - kod błędu
Nie ustawiony C : OK

Po wywołaniu tej funkcji możemy stwierdzić, czy wystąpił błąd (np.
podaliśmy numer segmentu, który nie zaczyna nowego bloku pamięci) poprzez
sprawdzenie znacznika C:

; wcześniej nadajemy rejestrom wartości potrzebne do wywołania funkcji
int 21h
jc Blad ; skok gdy znacznik C jest ustawiony
; === nie ma błędu ===
Blad:
; === wystąpił błąd ===

Pytanie w jaki sposób rozpoznamy, czy użytkownik chce zainstalować
program, czy go rozinstalować ? Oczywiście w tym celu musimy sprawdzić
parametry podane w linii poleceń (czyli odróżnić uruchomienie: TEST.COM od:
TEST.COM /u). Dla uproszczenia przyjmijmy, że jeżeli w linii poleceń znajdzie
się litera 'u' to należy usunąć TSRa z pamięci.

Znaki podane w linii poleceń przy uruchamianiu programu są trzymane w
bloku PSP (ang. Program Segment Prefix), który w zbiorach typu COM rezyduje
na początku segmentu z programem (jak pamiętamy, program zaczyna się od
adresu 100h, wcześniej jest właśnie PSP). Kolejne znaki parametrów podanych
programowi są zapisywane począwszy od adresu 81h, pod adresem 80h leży bajt
zawierający ilość znaków, a cały ciąg kończy się znakiem o kodzie 0dh (czyli
CR). Literę 'u' znajdziemy porównując kolejne znaki aż do znaku CR albo
wcześniejszego napotkania 'u'. I znowu - konkretną implementację znajdziecie
w kodzie programu.

Przyszła pora na kolejne ulepszenie naszego sekundnika - będzie on
zmieniał swój kolor w zależności od tego, czy klawiatura będzie w stanie
CapsLock. Do tego celu przyda nam się opis zawartości komórek danych BIOSu
pod adresami: 0040:0017h (czyli wygodniej jest napisać 0000:0417h - będzie to
samo) i następnym (418h):

Adres 0:0417h
Numer bitu: Znaczenie bitu zapalonego:
0 prawy Shift wciśnięty
1 lewy Shift wciśnięty
2 dowolny Ctrl wciśnięty
3 dowolny Alt wciśnięty
4 ScrollLock zapalony
5 NumLock zapalony
6 CapsLock zapalony
7 stan Insert

Adres 0:0418h
Numer bitu: Znaczenie bitu zapalonego:
0 lewy Ctrl wciśnięty
1 lewy Alt wciśnięty
2 SysReq wciśnięty
3 stan przerwy (czyli po wciśnięciu Pause)
4 ScrollLock wciśnięty
5 NumLock wciśnięty
6 CapsLock wciśnięty
7 Insert wciśnięty

Jak widzimy, aktualny stan przełącznika CapsLock możemy odczytać
sprawdzając bit nr 6 pod adresem 0:417h, gdy będzie zapalony to znaczy, że
klawiatura jest w stanie CapsLock (chyba nie muszę tłumaczyć, na czym ten
stan polega). Sprawdzenie jednego bitu najprościej dokonać instrukcją test,
której podajemy maskę bitu (czyli jego wagę, w tym przykładzie 40h), a
otrzymujemy w wyniku ustawienie lub wyzerowanie flagi ZF, czyli przepisanie
do niej zawartości testowanego bitu (wyzerowanie ZF gdy bit był wyzerowany,
ustawienie - gdy był ustawiony). Można też instrukcję test wykonać z
parametrem nie będącym wagą jednego bitu - wtedy zostanie logicznie wymnożony
(AND) bajt sprawdzany i podana wartość oraz odpowiednio ustawione flagi,
podobnie jak działa instrukcja and - tylko bez zapamiętywania wyników. Dla
przypomnienia podam jeszcze wagi kolejnych bitów, od 0. począwszy:
1,2,4,8,16,32,64,128, a w hex. to będzie: 1,2,4,8,10h,20h,40h,80h. Popatrzmy
na fragment kodu do sprawdzenia stanu CapsLock:

xor ax,ax
mov es,ax ; zerujemy rejestr segmentowy ES
test byte ptr es:[417h],40h
jz Nie_ma_CapsLock
; CapsLock wciśnięty
Nie_ma_CapsLock:
; CapsLock nie wciśnięty

----------> Obciąć <----------
.model tiny
.code
.386
org 100h

Start:
jmp StartTutaj

; tutaj będą nasze zmienne:
staraproc dd 0
; znacznik potrzebny do sprawdzenia zainstalowania TSRa:
znacznik db 'Sekundnik, odc. 3'

NaszaProc:
push ax
push bx
push di
push es
xor ax,ax ; segment komórki ze stanem klawiatury
mov es,ax
mov bh,0ch ; standardowy kolor jasnoczerwony do BH
test byte ptr es:[417h],40h; sprawdzamy, czy włączony jest CapsLock
jnz CapsOn ; skok gdy CapsLock wciśnięty
mov bh,1 ; kolor niebieski - CapsLock wyłączony
CapsOn:
mov ax,0b800h
mov es,ax
xor di,di
xor al,al
out 70h,al
jmp $+2
in al,71h
mov bl,al
and bl,0fh
add bl,'0'
shr al,4
add al,'0'
mov ah,bh ; ładujemy do AH wcześniej ustalony kolor
stosw ; i rzucamy na ekran pierwszą cyfrę
mov al,bl
stosw ; potem drugą
pop es
pop di
pop bx
pop ax
jmp dword ptr cs:[staraproc] ; skok do oryginalnej procedury

; koniec części rezydentnej

StartTutaj:
mov ah,9 ; 09h: wydruk nagłówka na ekran
mov dx,offset Logo
int 21h
mov si,81h ; początek ciągu parametrów
cld
Petla:
lodsb ; wczytanie do AL jednego znaku z DS:SI, SI=SI+1
cmp al,'u' ; może to jest 'u' ?
je Rozinstaluj
cmp al,'U' ; a może duże 'U' ?
je Rozinstaluj
cmp al,0dh ; może kod ENTERa (CR) ?
je Instaluj
jmp Petla ; skok gdy nic nie trafimy

Rozinstaluj:
mov ax,3508h ; 35h: pobranie wektora przerwania
int 21h
cmp bx,offset NaszaProc ; sprawdzamy, czy się zgadzają offsety
jne NieMa
mov si,offset znacznik ; adres lokalnego znacznika do DS:SI
mov di,si ; i znacznika sprawdzanego do ES:DI
mov cx,17 ; długość znacznika w bajtach
cld
repe cmpsb ; sprawdzamy aż do różniącego się bajtu
jnz NieMa ; skok gdy się nie zgadzają znaczniki
; Teraz już nie ma przeciwwskazań do rozinstalowania TSRa
mov dx,word ptr es:[staraproc] ; czytamy oryginalny wektor
mov ax,word ptr es:[staraproc +2] ; z bloku TSRa
mov ds,ax
mov ax,2508h ; 25h: ustawienie wektora przerwania
int 21h
mov ah,49h ; 49h: zwolnienie bloku pamięci z TSRem
int 21h ; w ES mamy segment TSRa
mov ax,cs
mov ds,ax ; przywracamy do DS segment naszego programu
mov ah,9 ; 09h: wydruk napisu na ekran
mov dx,offset Uninst
int 21h ; drukujemy komunikat o pomyślym usunięciu TSRa
mov ax,4c02h ; 4ch: powrót do DOSu, w AL kod błędu
int 21h

NieMa:
mov ah,9 ; 09h: wydruk napisu na ekran
mov dx,offset Brak
int 21h
mov ax,4c04h ; 4ch: powrót do DOSu, w AL kod błędu
int 21h

Instaluj:
mov ax,word ptr ds:[2ch] ; numer segmentu środowiska odczytamy z PSP,
mov es,ax ; wrzucimy do ES
mov ah,49h ; 49h: zwolnienie bloku pamięci
int 21h
mov ax,3508h ; 35h: pobranie wektora przerwania
int 21h ; wynik wpadł do ES:BX
mov word ptr cs:[staraproc],bx ; trzeba jeszcze go gdzies zapamietac
mov word ptr cs:[staraproc +2],es
mov ax,2508h ; 25h: ustawienie wektora przerwania
mov dx,offset NaszaProc ; DS:DX - wektor naszej procedury
int 21h
mov ah,9 ; 09h: wydruk napisu na ekran
mov dx,offset Napis
int 21h
mov dx,offset StartTutaj ; do DX wpisujemy adres pierwszego bajtu,
int 27h ; który ma być zwolniony, wcześniejsze
; zostają w pamięci na stałe

Logo db 'Sekundnik 1996.',13,10
db ' parametr /u - usunięcie programu z pamięci',13,10,'$'
Napis db 'Program zainstalowany w pamięci.',13,10,'$'
Brak db 'Program nie był wcześniej instalowany w pamięci.',13,10,'$'
Uninst db 'Program usunięty z pamięci.',13,10,'$'

end Start
----------> Obciąć <----------

W zależności od stanu CapsLock ustawiamy odpowiednio kolor wpisywanych
na ekran znaków - niech to będzie jasnoczerwony dla CapsLock włączonego oraz
niebieski dla CapsLock nie aktywnego. Właściwie nie pozostaje już nic innego
jak tylko poczytać listing. Co zrobić, gdy program jest w pamięci, ale został
po nim zainstalowany inny rezydent oraz jak wykryć taką sytuację dowiemy się
w następnym odcinku (przy okazji poznamy bardzo użyteczne przerwanie 2fh,
zwane przez znawców tematu Multiplex Interrupt).


Wyszukiwarka

Podobne podstrony:
Asembler w TSR KURS2
Asembler w TSR KURS0
Asembler w TSR KURS5
Asembler w TSR KURS4
Asembler w TSR SPIS TRE
Asembler w TSR KURS1
Asembler linux
TASM operacje asembler
21 Pisanie i uruchamianie programów w asemblerze
Procedury arytmetyczne w języku Asembler ST7
OAK W11 Asembler Pentium
asembler
Asembler Podstawy programowania w Windows
Praktyczny kurs asemblera

więcej podobnych podstron