Poprzedni :: Spis treści :: Następny


2. Podstawowe informacje
2.1 Organizacja pamięci programu
2.2 Stos
2.3 Mechanizm wywoływania funkcji
2.3.1 Instrukcja CALL
2.3.2 Instrukcja RET


2. Podstawowe informacje

2.1 Organizacja pamięci programu

Pamięć procesu przedstawia następujący rysunek:

pamięć w linuksie

Poszczególne fragmenty pamięci zawierają:

2.2 Stos

Stos jest to ciągły obszar pamięci implementujący kolejkę FILO (pierwszy wchodzi ostatni wychodzi). Operacje na stosie (push, pop) dostarczane są przez odpowiednie instrukcje procesora (odpowiednio PUSH i POP). Stos jest ściśle związany z mechanizmem wywoływania funkcji i przechowuje tzw. ramki umieszczanych tam w momencie wywołania funkcji i zdejmowanych w chwili powrotu z funkcji. Każda ramka zawiera następujące elementy:

Dodatkowo należy zwrócić uwagę, że na maszynach typu x86 stos rośnie od adresów wysokich ku niższym (najwyższy element na stosie ma najniższy adres).

Przykładowy wierzchołek stosu przedstawia poniższy rysunek:

schemat stosu

Rysunek, oprócz przykładowej ramki, przedstawia także zawartość dwóch rejestrów procesora:

Dostępność rejestru EBP oraz pozycja na stosie jaką wskazuje pozwala na odwoływanie się do argumentów funkcji oraz do jej zmiennych lokalnych poprzez dodanie odpowiedniej wartości do EBP. Przykładowo:

EBP + 4 = adres powrotu
EBP + 8 = pierwszy argument
EBP - 4 = pierwsza zmienna lokalna funkcji

(wartościami dodawanymi są wielokrotności 4 ponieważ każdy element stosu ma długość jednego słowa a te ma 4 bajty (na maszynie x86).

2.3 Mechanizm wywoływania funkcji

Mechanizm umożliwiający wywoływanie funkcji musi zapewnić , że, po zakończeniu wykonywania wywoływanej funkcji, sterowanie wróci do miejsca wywołania. Aby to zapewnić procesory x86 udostępniają instrukcje CALL oraz RET (omówione poniżej). Dodatkowo na stos należy włożyć argumenty funkcji oraz zadbać o zapamiętanie adresu ramki funkcji wywołującej i odpowiednie uaktualnienie wskaźnika aktualnej ramki (rejestr EBP). O te czynności zadbać trzeba samodzielnie (oczywiście jeżeli programujemy w assemblerze, w przypadku języków wyższego poziomu odpowiednie operacje przeprowadza kompilator).

W przypadku języka C wywołanie funkcji odbywa się następująco:

Współczesne kompilatory starają się zoptymalizować (przyspieszyć) kod. Jedną z metod osiągnięcia tego jest powiększenie stosu (w momencie wykonywania kodu funkcji) o znacznie większą ilość komórek niż jest to potrzebne do przechowywania zmiennych lokalnych. Dodatkowa pamięć jest wykorzystywana np. do przyspieszenia funkcji. Na przykład zamiast używać instrukcji PUSH i POP, które wkładają odpowiedni element na stos i uaktualniają rejestr ESP, można "wkładać" elementy w odpowiednie miejsca poniżej wierzchołka stosu (oczywiście dbając o to aby nie uszkodzić znajdujących się tam danych) co można zrealizować przy pomocy jednej instrukcji.

2.3.1 Instrukcja CALL

Instrukcja CALL działa następująco:

mechanizm call

2.3.2 Instrukcja RET

Instrukcja RET działa następująco:

mechanizm ret

Poprzedni :: Spis treści :: Następny


Valid XHTML 1.0 Strict