[ Pobierz całość w formacie PDF ]
push( eax ); spowoduje ustawienie rejestru ESP na warto $00FF_FFE4 i skopiowanie bie-
cej warto ci rejestru EAX pod adres $00FF_FFE4; proces ten ilustruj rysunki 3.9 oraz 3.10.
Rysunek 3.9. Stan pami ci stosu przed wykonaniem instrukcji push
Rysunek 3.10. Stan pami ci stosu po wykonaniu instrukcji push
Wykonanie instrukcji push( eax ); nie wp ywa przy tym w aden sposób na zawarto
rejestru EAX.
Cho procesory z rodziny 80x86 implementuj 16-bitowe wersje instrukcji manipuluj -
cych pami ci stosu, to owe wersje maj zastosowanie g ównie w rodowiskach 16-bitowych, jak
system DOS. Tymczasem gwoli maksymalnej wydajno ci warto, aby warto wska nika stosu
by a zawsze ca kowit wielokrotno ci liczby cztery; program mo e zreszt w systemie takim
jak Windows czy Linux zosta awaryjnie zatrzymany, kiedy system wykryje, e wska nik stosu
zawiera warto niepodzieln bez reszty przez cztery. Jedynym uzasadnieniem dla odk adania
na stosie danych innych ni 32-bitowe jest wi c konstruowanie za po rednictwem stosu warto ci
o rozmiarze podwójnego s owa sk adanej z dwóch s ów umieszczonych na stosie jedno po drugim.
Dost p do pami ci i jej organizacja 165
3.8.2. Podstawowa posta instrukcji pop
Do zdejmowania danych umieszczonych wcze niej na stosie s u y instrukcja pop. W swej pod-
stawowej wersji instrukcja ta przyjmuje jedn z czterech postaci:
pop( rejestr16 );
pop( rejestr32 );
pop( pamie 16 );
pop( pami 32 );
Podobnie jak to ma miejsce w przypadku instrukcji push, instrukcja pop obs uguje jedynie
operandy 16- i 32-bitowe; ze stosu nie mo na zdejmowa warto ci o miobitowych. Podobnie
jednak jak przy instrukcji push, zdejmowania ze stosu warto ci 16-bitowych powinno si unika ,
chyba e operacja taka stanowi jedn z dwóch operacji zdejmowania ze stosu realizowanych pod
rz d) zdj cie ze stosu danej 16-bitowej powoduje, e warto rejestru wska nika stosu nie
dzieli si bez reszty przez cztery, co nie jest po dane. W przypadku instrukcji pop dochodzi
jeszcze jedno ograniczenie: nie da si pobra warto ci ze stosu, okre laj c w instrukcji operand
w postaci sta ej jest to zreszt ograniczenie o tyle naturalne, e operand instrukcji push jest
operandem ród owym i jako taki mo e by sta ; trudno natomiast, aby sta by operand doce-
lowy, a taki wyst puje w instrukcji pop.
Sposób dzia ania instrukcji pop mo na opisa nast puj cym pseudokodem:
operand := [ESP]
ESP := ESP + rozmiar-operandu (2 b d 4)
Operacja zdejmowania ze stosu jest, jak wida , operacj dok adnie odwrotn do operacji
odk adania danych na stosie. Instrukcja pop realizuje bowiem kopiowanie warto ci spod adresu
wskazywanego wska nikiem stosu jeszcze przed jego zwi kszeniem. Obraz pami ci stosu przed
i po wykonaniu instrukcji pop ilustruj rysunki 3.11 oraz 3.12.
Rysunek 3.11. Stan pami ci stosu przed wykonaniem instrukcji pop
166 Rozdzi a 3.
Rysunek 3.12. Stan pami ci stosu po wykonaniu instrukcji pop
Nale y podkre li , e warto zdj ta ze stosu wci znajduje si w obszarze pami ci stosu.
Zdejmowanie danej ze stosu nie oznacza zamazywania pami ci stosu; efekt znikni cia danej
ze stosu osi gany jest przez przesuni cie wska nika stosu tak, aby wskazywa warto s sia-
duj c z warto ci zdj t (o wy szym adresie). Nigdy jednak nie nale y próbowa odwo ywa si
do danej zdj tej ju ze stosu nast pne od o enie czegokolwiek na stos powoduje ju bowiem
nadpisanie obszaru, w którym owa dana si wcze niej znajdowa a. A poniewa nie wolno zak a-
da , e stos manipulowany jest wy cznie kodem programu (stos jest wykorzystywany tak przez
system operacyjny, jak i kod wywo uj cy procedury), nie powinno si inicjowa odwo a do
danych, które zosta y ju zdj te ze stosu i co do których istnieje jedynie podejrzenie (bo prze-
cie nie pewno ), e jeszcze s obecne w pami ci stosu.
3.8.3. Zachowywanie warto ci rejestrów
za pomoc instrukcji push i pop
Najwa niejszym chyba zastosowaniem instrukcji pop i push jest zachowywanie zawarto ci reje-
strów w obliczu potrzeby ich czasowego innego ni dotychczasowe wykorzystania. W architek-
turze 80x86 gospodarka rejestrami jest o tyle problematyczna, e procesor ten zawiera wyj tkowo
ma liczb rejestrów ogólnego przeznaczenia. Rejestry znakomicie nadaj si do przechowy-
wania warto ci tymczasowych (np. wyników po rednich etapów oblicze ), ale s te potrzebne
do realizacji ró nych trybów adresowania. Z tego wzgl du programista cz sto staje w obliczu
niedostatku rejestrów, zw aszcza kiedy kod realizuje z o one obliczenia. Ratunkiem mog by
wtedy instrukcje push oraz pop.
Rozwa my nast puj cy zarys programu:
// sekwencja instrukcji wykorzystuj cych rejestr EAX
// sekwencja instrukcji, na potrzeby których nale y zwolni rejestr EAX
// kontynuacja sekwencji instrukcji wykorzystuj cych rejestr EAX
Dost p do pami ci i jej organizacja 167
Do zaimplementowania takiego planu znakomicie nadaj si instrukcje push oraz pop. Za ich
pomoc mo na najpierw zachowa , a nast pnie przywróci zawarto rejestru EAX; w mi dzy-
czasie mo na za zrealizowa kod wymagaj cy zwolnienia tego rejestru:
// sekwencja instrukcji wykorzystuj cych rejestr EAX
push( eax );
// sekwencja instrukcji, na potrzeby których nale y zwolni rejestr EAX
pop( eax );
// kontynuacja sekwencji instrukcji wykorzystuj cych rejestr EAX
Umiej tnie osadzaj c w kodzie instrukcje push i pop, mo na zachowa na stosie wynik obli-
cze realizowanych za po rednictwem rejestru EAX na czas wykonania kodu, który ten rejestr
wykorzystuje w innym celu. Po zako czeniu owego fragmentu kodu mo na przywróci poprzed-
nio zachowan warto EAX i kontynuowa przerwane obliczenia.
3.9. Stos jako kolejka LIFO
Nie jest powiedziane, e stos nale y wykorzystywa do odk adania wy cznie pojedynczych
danych. Stos jest bowiem po prostu implementacj kolejki LIFO (ang. last in, first out, czyli
ostatnie na wej ciu pierwsze na wyj ciu). Obs uga takiej kolejki dla ca ych sekwencji danych
wymaga jednak uwa nego kontrolowania kolejno ci odk adania i zdejmowania danych. Rozwa my
na przyk ad sytuacj , gdy na czas realizacji pewnych instrukcji nale y zachowa zawarto
rejestrów EAX I EBX. Pocz tkuj cy programista móg by zrealizowa zabezpieczenie na stosie
warto ci rejestrów tak:
push( eax );
push( ebx );
// Sekwencja kodu wymagaj ca zwolnienia rejestrów EAX i EBX.
pop( eax );
pop( ebx );
Niestety, powy szy kod b dzie dzia a niepoprawnie! B d zawarty w tym kodzie ilustruj
rysunki 3.13 do 3.16. Problem mo na opisa nast puj co: na stos najpierw odk adany jest rejestr
EAX, a po nim EBX. Wska nik stosu wskazuje w efekcie adres pami ci stosu, pod którym sk a-
dowana jest zawarto rejestru EBX. Kiedy w ramach przywracania poprzednich warto ci reje-
strów wykonywana jest instrukcja pop( eax );, do rejestru EAX trafia warto , która pierwotnie
znajdowa a si w rejestrze EBX! Z kolei nast pna instrukcja, pop( ebx );, aduje do rejestru
EBX warto , która powinna tak naprawd trafi do rejestru EAX! Do zamiany warto ci reje-
strów dosz o w wyniku zastosowania niepoprawnej sekwencji zdejmowania ze stosu dane
powinny by z niego zdejmowane w kolejno ci odwrotnej, ni zosta y na od o one.
Stos, jako struktura odpowiadaj ca kolejce LIFO, ma t w a ciwo , e to, co trafia na stos
jako pierwsze, powinno z niego zosta zdj te w ostatniej kolejno ci. Dla uproszczenia warto
zapami ta nast puj c regu :
168 Rozdzi a 3.
Rysunek 3.13. Obraz pami ci stosu po od o eniu na niego zawarto ci rejestru EAX
Rysunek 3.14. Obraz pami ci stosu po od o eniu na niego zawarto ci rejestru EBX [ Pobierz całość w formacie PDF ]
zanotowane.pl doc.pisz.pl pdf.pisz.pl fopke.keep.pl
push( eax ); spowoduje ustawienie rejestru ESP na warto $00FF_FFE4 i skopiowanie bie-
cej warto ci rejestru EAX pod adres $00FF_FFE4; proces ten ilustruj rysunki 3.9 oraz 3.10.
Rysunek 3.9. Stan pami ci stosu przed wykonaniem instrukcji push
Rysunek 3.10. Stan pami ci stosu po wykonaniu instrukcji push
Wykonanie instrukcji push( eax ); nie wp ywa przy tym w aden sposób na zawarto
rejestru EAX.
Cho procesory z rodziny 80x86 implementuj 16-bitowe wersje instrukcji manipuluj -
cych pami ci stosu, to owe wersje maj zastosowanie g ównie w rodowiskach 16-bitowych, jak
system DOS. Tymczasem gwoli maksymalnej wydajno ci warto, aby warto wska nika stosu
by a zawsze ca kowit wielokrotno ci liczby cztery; program mo e zreszt w systemie takim
jak Windows czy Linux zosta awaryjnie zatrzymany, kiedy system wykryje, e wska nik stosu
zawiera warto niepodzieln bez reszty przez cztery. Jedynym uzasadnieniem dla odk adania
na stosie danych innych ni 32-bitowe jest wi c konstruowanie za po rednictwem stosu warto ci
o rozmiarze podwójnego s owa sk adanej z dwóch s ów umieszczonych na stosie jedno po drugim.
Dost p do pami ci i jej organizacja 165
3.8.2. Podstawowa posta instrukcji pop
Do zdejmowania danych umieszczonych wcze niej na stosie s u y instrukcja pop. W swej pod-
stawowej wersji instrukcja ta przyjmuje jedn z czterech postaci:
pop( rejestr16 );
pop( rejestr32 );
pop( pamie 16 );
pop( pami 32 );
Podobnie jak to ma miejsce w przypadku instrukcji push, instrukcja pop obs uguje jedynie
operandy 16- i 32-bitowe; ze stosu nie mo na zdejmowa warto ci o miobitowych. Podobnie
jednak jak przy instrukcji push, zdejmowania ze stosu warto ci 16-bitowych powinno si unika ,
chyba e operacja taka stanowi jedn z dwóch operacji zdejmowania ze stosu realizowanych pod
rz d) zdj cie ze stosu danej 16-bitowej powoduje, e warto rejestru wska nika stosu nie
dzieli si bez reszty przez cztery, co nie jest po dane. W przypadku instrukcji pop dochodzi
jeszcze jedno ograniczenie: nie da si pobra warto ci ze stosu, okre laj c w instrukcji operand
w postaci sta ej jest to zreszt ograniczenie o tyle naturalne, e operand instrukcji push jest
operandem ród owym i jako taki mo e by sta ; trudno natomiast, aby sta by operand doce-
lowy, a taki wyst puje w instrukcji pop.
Sposób dzia ania instrukcji pop mo na opisa nast puj cym pseudokodem:
operand := [ESP]
ESP := ESP + rozmiar-operandu (2 b d 4)
Operacja zdejmowania ze stosu jest, jak wida , operacj dok adnie odwrotn do operacji
odk adania danych na stosie. Instrukcja pop realizuje bowiem kopiowanie warto ci spod adresu
wskazywanego wska nikiem stosu jeszcze przed jego zwi kszeniem. Obraz pami ci stosu przed
i po wykonaniu instrukcji pop ilustruj rysunki 3.11 oraz 3.12.
Rysunek 3.11. Stan pami ci stosu przed wykonaniem instrukcji pop
166 Rozdzi a 3.
Rysunek 3.12. Stan pami ci stosu po wykonaniu instrukcji pop
Nale y podkre li , e warto zdj ta ze stosu wci znajduje si w obszarze pami ci stosu.
Zdejmowanie danej ze stosu nie oznacza zamazywania pami ci stosu; efekt znikni cia danej
ze stosu osi gany jest przez przesuni cie wska nika stosu tak, aby wskazywa warto s sia-
duj c z warto ci zdj t (o wy szym adresie). Nigdy jednak nie nale y próbowa odwo ywa si
do danej zdj tej ju ze stosu nast pne od o enie czegokolwiek na stos powoduje ju bowiem
nadpisanie obszaru, w którym owa dana si wcze niej znajdowa a. A poniewa nie wolno zak a-
da , e stos manipulowany jest wy cznie kodem programu (stos jest wykorzystywany tak przez
system operacyjny, jak i kod wywo uj cy procedury), nie powinno si inicjowa odwo a do
danych, które zosta y ju zdj te ze stosu i co do których istnieje jedynie podejrzenie (bo prze-
cie nie pewno ), e jeszcze s obecne w pami ci stosu.
3.8.3. Zachowywanie warto ci rejestrów
za pomoc instrukcji push i pop
Najwa niejszym chyba zastosowaniem instrukcji pop i push jest zachowywanie zawarto ci reje-
strów w obliczu potrzeby ich czasowego innego ni dotychczasowe wykorzystania. W architek-
turze 80x86 gospodarka rejestrami jest o tyle problematyczna, e procesor ten zawiera wyj tkowo
ma liczb rejestrów ogólnego przeznaczenia. Rejestry znakomicie nadaj si do przechowy-
wania warto ci tymczasowych (np. wyników po rednich etapów oblicze ), ale s te potrzebne
do realizacji ró nych trybów adresowania. Z tego wzgl du programista cz sto staje w obliczu
niedostatku rejestrów, zw aszcza kiedy kod realizuje z o one obliczenia. Ratunkiem mog by
wtedy instrukcje push oraz pop.
Rozwa my nast puj cy zarys programu:
// sekwencja instrukcji wykorzystuj cych rejestr EAX
// sekwencja instrukcji, na potrzeby których nale y zwolni rejestr EAX
// kontynuacja sekwencji instrukcji wykorzystuj cych rejestr EAX
Dost p do pami ci i jej organizacja 167
Do zaimplementowania takiego planu znakomicie nadaj si instrukcje push oraz pop. Za ich
pomoc mo na najpierw zachowa , a nast pnie przywróci zawarto rejestru EAX; w mi dzy-
czasie mo na za zrealizowa kod wymagaj cy zwolnienia tego rejestru:
// sekwencja instrukcji wykorzystuj cych rejestr EAX
push( eax );
// sekwencja instrukcji, na potrzeby których nale y zwolni rejestr EAX
pop( eax );
// kontynuacja sekwencji instrukcji wykorzystuj cych rejestr EAX
Umiej tnie osadzaj c w kodzie instrukcje push i pop, mo na zachowa na stosie wynik obli-
cze realizowanych za po rednictwem rejestru EAX na czas wykonania kodu, który ten rejestr
wykorzystuje w innym celu. Po zako czeniu owego fragmentu kodu mo na przywróci poprzed-
nio zachowan warto EAX i kontynuowa przerwane obliczenia.
3.9. Stos jako kolejka LIFO
Nie jest powiedziane, e stos nale y wykorzystywa do odk adania wy cznie pojedynczych
danych. Stos jest bowiem po prostu implementacj kolejki LIFO (ang. last in, first out, czyli
ostatnie na wej ciu pierwsze na wyj ciu). Obs uga takiej kolejki dla ca ych sekwencji danych
wymaga jednak uwa nego kontrolowania kolejno ci odk adania i zdejmowania danych. Rozwa my
na przyk ad sytuacj , gdy na czas realizacji pewnych instrukcji nale y zachowa zawarto
rejestrów EAX I EBX. Pocz tkuj cy programista móg by zrealizowa zabezpieczenie na stosie
warto ci rejestrów tak:
push( eax );
push( ebx );
// Sekwencja kodu wymagaj ca zwolnienia rejestrów EAX i EBX.
pop( eax );
pop( ebx );
Niestety, powy szy kod b dzie dzia a niepoprawnie! B d zawarty w tym kodzie ilustruj
rysunki 3.13 do 3.16. Problem mo na opisa nast puj co: na stos najpierw odk adany jest rejestr
EAX, a po nim EBX. Wska nik stosu wskazuje w efekcie adres pami ci stosu, pod którym sk a-
dowana jest zawarto rejestru EBX. Kiedy w ramach przywracania poprzednich warto ci reje-
strów wykonywana jest instrukcja pop( eax );, do rejestru EAX trafia warto , która pierwotnie
znajdowa a si w rejestrze EBX! Z kolei nast pna instrukcja, pop( ebx );, aduje do rejestru
EBX warto , która powinna tak naprawd trafi do rejestru EAX! Do zamiany warto ci reje-
strów dosz o w wyniku zastosowania niepoprawnej sekwencji zdejmowania ze stosu dane
powinny by z niego zdejmowane w kolejno ci odwrotnej, ni zosta y na od o one.
Stos, jako struktura odpowiadaj ca kolejce LIFO, ma t w a ciwo , e to, co trafia na stos
jako pierwsze, powinno z niego zosta zdj te w ostatniej kolejno ci. Dla uproszczenia warto
zapami ta nast puj c regu :
168 Rozdzi a 3.
Rysunek 3.13. Obraz pami ci stosu po od o eniu na niego zawarto ci rejestru EAX
Rysunek 3.14. Obraz pami ci stosu po od o eniu na niego zawarto ci rejestru EBX [ Pobierz całość w formacie PDF ]