Prolog funkcji i epilog - Function prologue and epilogue
W asemblerze programowania The prolog funkcja jest kilka linii kodu na początku funkcji, które przygotowują się stos i rejestry do wykorzystania w ramach funkcji. Podobnie epilog funkcji pojawia się na końcu funkcji i przywraca stos i rejestry do stanu, w jakim znajdowały się przed wywołaniem funkcji.
Prolog i epilog nie są częścią samego języka asemblera; reprezentują konwencję używaną przez programistów języka asemblerowego i kompilatory wielu języków wyższego poziomu . Są dość sztywne i mają taką samą formę w każdej funkcji.
Prolog funkcji i epilog czasami zawierają również kod chroniący przed przepełnieniem bufora .
Prolog
Prolog funkcji zazwyczaj wykonuje następujące działania, jeśli architektura ma wskaźnik bazowy (znany również jako wskaźnik ramki) i wskaźnik stosu:
- Wstawia bieżący wskaźnik bazowy na stos, dzięki czemu można go później przywrócić.
- Przypisuje wartość wskaźnika bazowego do adresu wskaźnika stosu (który wskazuje wierzchołek stosu), tak aby wskaźnik bazowy wskazywał wierzchołek stosu.
- Przesuwa wskaźnik stosu dalej, zmniejszając lub zwiększając jego wartość, w zależności od tego, czy stos rośnie w dół, czy w górę. W x86 wskaźnik stosu jest zmniejszony, aby zrobić miejsce dla zmiennych lokalnych funkcji.
Można napisać kilka możliwych prologów, co skutkuje nieco inną konfiguracją stosu. Te różnice są dopuszczalne, o ile programista lub kompilator używa stosu we właściwy sposób wewnątrz funkcji.
Jako przykład, tutaj jest typowy prolog funkcji asemblera x86 wyprodukowany przez GCC
push ebp
mov ebp, esp
sub esp, N
Wartość bezpośrednia N to liczba bajtów zarezerwowanych na stosie do użytku lokalnego.
Ten sam efekt można osiągnąć za pomocą enterinstrukcji:
enter N, 0
Bardziej złożone prologi można uzyskać przy użyciu różnych wartości (innych niż 0) dla drugiego argumentu enterinstrukcji. Te prologi przesuwają kilka wskaźników podstawy/ramki, aby umożliwić zagnieżdżone funkcje , zgodnie z wymaganiami języków takich jak Pascal . Jednak współczesne wersje tych języków nie używają tych instrukcji, ponieważ w niektórych przypadkach ograniczają one głębokość zagnieżdżenia.
Epilog
Epilog funkcji odwraca działania prologu funkcji i zwraca kontrolę do funkcji wywołującej. Zwykle wykonuje następujące działania (ta procedura może się różnić w zależności od architektury):
- Upuść wskaźnik stosu do bieżącego wskaźnika bazowego, aby zwolnić miejsce zarezerwowane w prologu dla zmiennych lokalnych.
- Zdejmuje wskaźnik bazowy ze stosu, dzięki czemu jest przywracany do wartości sprzed prologu.
- Powraca do funkcji wywołującej, zdejmując licznik programu poprzedniej ramki ze stosu i przeskakując do niego.
Dany epilog odwróci efekty któregokolwiek z powyższych prologów (albo pełnego, albo tego, w którym użyto enter). Zgodnie z pewnymi konwencjami wywoływania obowiązkiem osoby wywoływanej jest wyczyszczenie argumentów ze stosu, więc epilog może również obejmować krok przesuwania wskaźnika stosu w dół lub w górę.
Na przykład, te trzy kroki mogą być wykonane w 32-bitowym języku asemblera x86 przez następujące instrukcje:
mov esp, ebp
pop ebp
ret
Podobnie jak prolog, procesor x86 zawiera wbudowaną instrukcję, która wykonuje część epilogu. Poniższy kod jest odpowiednikiem powyższego kodu:
leave
ret
leaveInstrukcji wykonuje movoraz popinstrukcje jak opisano powyżej.
Funkcja może zawierać wiele epilogów. Każdy punkt wyjścia funkcji musi albo przeskoczyć do wspólnego epilogu na końcu, albo zawierać własny epilog. Dlatego programiści lub kompilatorzy często używają kombinacji leavei retdo wyjścia z funkcji w dowolnym momencie. (Na przykład kompilator C zastąpiłby returninstrukcję sekwencją leave/ ret).
Dalsza lektura
- de Boyne Pollard, Jonathan (2010). „Gen na perylogi funkcji” . Często udzielane odpowiedzi .