| STATYSTYKI |
Od 06.09.2000
|
Optymalizacja: 1024x768, IE5 |
|
| Stos |
Co to takiego?
Stos jest strukturą danych. Służy do chwilowego przechwywania informacji.
Podstawową cechą stosu jest to,że w danej chwili mamy dostęp jedynie do
elementu leżącego na jego szczycie (np. możemy ten element zdjąć ze stosu),
czyli element odłożony jako ostatni będzienmy zdejmować jako pierwszy.
Stos wskazują dwa rejestry :SS i SP.
SS - jest nr segmentu stosu;
SP - jest wskaźnikiem szczytu stosu, czyli przesunięciem ostatnio wstawionej wartości.
Gdy wstawiamy na stos nową wartość, to wskaźnik stosu SP zmniejszy się o 2.
Wstawianie elementów na stos
PUSH - jest to instrukcja wstawiająca wartości na stos
Jej paramertrem jest: rejestr,zawartość komórki pamięci bądź wartość natychmiastową(only >=286), np.:
push ax ;wstaw zawrtość rejestru ax na stos
push ds ;wstaw zawartość rejestru ds na stos
TABLICA dw 2000 dup(1234h)
LICZBA dw ?
push TABLICA[bx][si] ;wstaw na stos zawartośc odpowiednie komórki opamięci
push LICZBA ;wstaw na stos wartość zmiennej LICZBA
push 0 ;zapisz zero na stosie
push 20abh ;zapisz 20abh na stosie
Do umieszczenia "hurtem" wszystkich rejetrów (oprócz segmentowych) na stosie służy komenda bezparametrowa PUSHA . Rejestry "lądują" na stosie w kolejności: ax,cx,dx,bx,sp,bp,si,di .
Do umieszczenia na stosie rejstru znaczników służy instrukcja PUSHF .Można także zadeklarować w programie zmienną zawierającą gotowy "zestaw znaczników" i położyć na stosie, np.:
ZNACZNIKI dw 1111111111111110b ;16-bitowa liczba
push ZNACZNIKI
Zdejmowanie elementów ze stosu
POP - jest to instrukcja zdejmująca wartości ze stosu.
Jej parametrem jest miejsce wstawienia wartości, np.: rejestr lub komórka pamięci, np. :
pop ax ;zdejmij ze szczytu stosu wartość i wstaw do ax
pop ds ;zdejmij ze stosu wartośc i wstaw do ds
TABLICA dw 1000 dup(?)
LICZBA dw ?
pop TABLICA[bx] ;zdejmij ze stosu wartość i wstaw do tablicy w miejsce wskazane przez rejestr bx
pop LICZBA ;zdejmij ze stosu wartość i wstaw do zmiennej LICZBA
Jeżeli użyliśmy instrukcji PUSHA do umieszczenia zawrtości rejestrów na stosie,
to aby ozyskać oryginalne wartości tych rejestrów zdejmując je ze stosu należy użyć instrukcji bezparametrowej POPA .
Uwagi dotyczące stosu
1.Zawsze należy zostawić stos takim, jaki go się zastało. Dotyczy to szczególnie całości programu. Procesor składuje na stosie także swoje własne informacje bez naszej wiedzy i przy ich zdejmowaniu
nie zwraca uwagi, na to czy zdejmuje to co sam tam wstawił, czy też to co my tam połozyliśmy. Dlatego dbajmy o to, żeby nie zostawić na stosie własnych informacji po wykonaniu się programu.
2.Unikaj zmiany wartości rejestrów stosu SP i SS. Prowadzi to do częstych błędów.
3.Nie traktuj stosu wyłącznie jako magazynu. Można go wykorzystać np. do przepisywania wartości między rejestrami segmentowymi.
4.Nie "nadużywaj stosu". Stratą czasu jest składowanie rejestrów na stosie "tak na wszelki wypadek". Jeśli nie zmieniasz zawartości rejstru w procedurze, to nie musisz go zapamiętywać na stosie.
5.Stosuj instrukcję pusha tylko wtedy, gdy zmieniasz w procedurze wartości wszystkich 8 rejestrów.
6.Jeżeli program się "rozbiega" po pamięci, to sprawdz w procedurach, czy nie "zaśmieciłeś" stosu (pogubiłeś adresy).
Stos a funkcje API
Aby wywołąć jakąś funkcję API musisz najpierw zadbać o umieszczenie wszystkich jej parametrów na stosie i to w odpowiedniej kolejności.
Tasm32
Np. aby wywołać funkcję jakas_funkcja_API(parametr_1, parametr_2, parametr_3)należy postąpić tak:
push parametr_3
push parametr_2
push parametr_1
call jakas_funkcja_API
lub
call jakas_funkcja_API,parametr_1,parametr_2,parametr_3
Jak widać należy przed wywołaniem funkcji API odłożyć jej parametry na stosie w kolejności od prawej do lewej (PASCAL).
Wyjątkiem jest tutaj funkcja wsprintf(), gdzie parametry na stosie odkładamy z lewej do prawej (C).
O takim sposobie postępowania informuje słowo STDCALL (Szablon programu w Win32asm), które jast połączeniem wywołań C i PASCAL
i czyta parametry od prawej do lewej, ale to wywołujący jest odpowiedzialny za zbalansowanie stosu po wywołaniu.
Masm32
W Masm'ie do wywołania funkcji API najbezpieczniej jest użyć instrukcji invoke (składni wysokiego poziomu), np.:
invoke jakas_funkcja_API,parametr_1,parametr_2,parametr_3
Wtedy jeśli zapomnimy o odłożeniu na stosie jakiegoś parametru funkcji, to linker poinformuje nas o tym błędzie, bo
wywołanie zostanie skorygowane z prototypem funkcji (większość prototypów znajduje się w includach).
<<
|
|