Ramka stosu to ramka danych, która jest wypychana na stos. W przypadku stosu wywołań ramka stosu reprezentowałaby wywołanie funkcji i dane argumentu.
Jeśli dobrze pamiętam, adres zwrotny funkcji jest najpierw wypychany na stos, a następnie argumenty i miejsce na zmienne lokalne. Razem tworzą „ramkę”, chociaż prawdopodobnie zależy to od architektury. Procesor wie, ile bajtów jest w każdej ramce i odpowiednio przesuwa wskaźnik stosu, gdy ramki są wypychane i wyskakiwane ze stosu.
EDYTOWAĆ:
Istnieje duża różnica między stosami wywołań wyższego poziomu a stosami wywołań procesora.
Kiedy mówimy o stosie wywołań procesora, mówimy o pracy z adresami i wartościami na poziomie bajtów / słów w asemblerze lub kodzie maszynowym. Podczas mówienia o językach wyższego poziomu występują „stosy połączeń”, ale są one narzędziem do debugowania / środowiska wykonawczego zarządzanym przez środowisko wykonawcze, dzięki czemu można rejestrować, co poszło nie tak z twoim programem (na wysokim poziomie). Na tym poziomie często znane są numery linii, nazwy metod i klas. Zanim procesor otrzyma kod, nie ma absolutnie żadnego pojęcia o tych rzeczach.
Jeśli rozumiesz stos bardzo dobrze, zrozumiesz, jak pamięć działa w programie, a jeśli zrozumiesz, jak pamięć działa w programie, zrozumiesz, jak przechowuje funkcje w programie, a jeśli zrozumiesz, jak przechowuje funkcje w programie, zrozumiesz, jak działa funkcja rekurencyjna, a jeśli zrozumiesz, jak działa funkcja rekurencyjna, zrozumiesz, jak działa kompilator, a jeśli zrozumiesz, jak działa kompilator, twój umysł będzie działał jako kompilator i bardzo łatwo debugujesz dowolny program
Pozwól mi wyjaśnić, jak działa stos:
Najpierw musisz wiedzieć, jak funkcje są reprezentowane na stosie:
Sterta przechowuje dynamicznie przydzielane wartości.
Stos przechowuje wartości automatycznego przydzielania i usuwania.
Rozumiemy na przykładzie:
Teraz zrozum części tego programu:
Zobaczmy teraz, co to jest stos, a jakie części stosu:
Pamiętaj o jednej rzeczy: jeśli warunek powrotu dowolnej funkcji zostanie spełniony, bez względu na to, czy załadował zmienne lokalne, czy nie, natychmiast powróci ze stosu z ramką stosu. Oznacza to, że za każdym razem, gdy jakakolwiek funkcja rekurencyjna zostanie spełniona warunek podstawowy, a my wstawimy znak powrotu po warunku podstawowym, warunek podstawowy nie będzie czekał na załadowanie zmiennych lokalnych, które znajdują się w części „else” programu. Natychmiast zwróci bieżącą ramkę ze stosu, po której następna ramka znajduje się teraz w rekordzie aktywacji.
Zobacz to w praktyce:
Tak więc teraz, gdy funkcja napotka instrukcję return, usuwa bieżącą ramkę ze stosu.
Podczas powrotu ze stosu wartości będą zwracane w odwrotnej kolejności niż pierwotna kolejność, w jakiej zostały przydzielone w stosie.
źródło
hello()
wywołały rekurencyjnie,hello()
które następnie (ponownie) wywołały rekurencyjniehello()
, a ramka globalna jest oryginalną funkcją, która wywołała pierwsząhello()
?Szybkie zakończenie. Może ktoś ma lepsze wytłumaczenie.
Stos wywołań składa się z 1 lub wielu kilku ramek stosu. Każda ramka stosu odpowiada wywołaniu funkcji lub procedury, które jeszcze nie zakończyło się zwrotem.
Aby użyć ramki stosu, wątek zachowuje dwa wskaźniki, jeden nazywany jest wskaźnikiem stosu (SP), a drugi wskaźnikiem ramki (FP). SP zawsze wskazuje na „górę” stosu, a FP zawsze wskazuje na „górę” ramki. Ponadto wątek utrzymuje również licznik programów (PC), który wskazuje następną instrukcję do wykonania.
Na stosie są przechowywane: zmienne lokalne i wartości tymczasowe, rzeczywiste parametry bieżącej instrukcji (procedura, funkcja itp.)
Istnieją różne konwencje wywoływania dotyczące czyszczenia stosu.
źródło
„Stos wywołań składa się z ramek stosów ...” - Wikipedia
Rama stosu to rzecz, którą umieszczasz na stosie. Są to struktury danych, które zawierają informacje o podprogramach do wywołania.
źródło
Programiści mogą mieć pytania dotyczące ramek stosu nie w szerokim znaczeniu (że jest to pojedyncza jednostka w stosie, która obsługuje tylko jedno wywołanie funkcji i zachowuje adres zwrotny, argumenty i zmienne lokalne), ale w wąskim znaczeniu - gdy termin
stack frames
jest wymieniony w kontekst opcji kompilatora.Czy autor pytania miał na myśli, czy nie, ale koncepcja ramki stosu w aspekcie opcji kompilatora jest bardzo ważnym zagadnieniem, nieuwzględnionym w innych odpowiedziach tutaj.
Na przykład kompilator Microsoft Visual Studio 2015 C / C ++ ma następującą opcję związaną z
stack frames
:GCC mają następujące elementy:
Kompilator Intel C ++ ma następujące funkcje:
który ma następujący alias:
Delphi ma następującą opcję wiersza polecenia:
W tym konkretnym sensie, z perspektywy kompilatora, ramka stosu to tylko kod wejścia i wyjścia dla procedury , która przesuwa kotwicę do stosu - która może być również używana do debugowania i obsługi wyjątków. Narzędzia do debugowania mogą skanować dane stosu i używać tych kotwic do śledzenia wstecznego, podczas lokalizowania
call sites
w stosie, tj. Do wyświetlania nazw funkcji w kolejności, w jakiej zostały one nazwane hierarchicznie. W przypadku architektury Intel jest topush ebp; mov ebp, esp
lubenter
do wejścia imov esp, ebp; pop ebp
lubleave
do wyjścia.Dlatego bardzo ważne jest, aby zrozumieć dla programisty, w jakiej ramce jest stos, jeśli chodzi o opcje kompilatora - ponieważ kompilator może kontrolować, czy wygenerować ten kod, czy nie.
W niektórych przypadkach kompilator może pominąć ramkę stosu (kod wejścia i wyjścia dla procedury), a do zmiennych można uzyskać bezpośredni dostęp za pomocą wskaźnika stosu (SP / ESP / RSP) zamiast wygodnego wskaźnika bazowego (BP / ESP / RSP). Warunki pominięcia ramy stosu, na przykład:
Pominięcie ramek stosu (kod wejścia i wyjścia dla procedury) może sprawić, że kod będzie mniejszy i szybszy, ale może również negatywnie wpłynąć na zdolność debuggerów do śledzenia danych w stosie i wyświetlania ich programistom. Są to opcje kompilatora, które określają, w jakich warunkach funkcja powinna mieć kod wejścia i wyjścia, na przykład: (a) zawsze, (b) nigdy, (c) w razie potrzeby (określając warunki).
źródło
Ramka stosu to spakowana informacja związana z wywołaniem funkcji. Informacje te ogólnie obejmują argumenty przekazane do funkcji th, zmienne lokalne i miejsce, do którego należy wrócić po zakończeniu. Rekord aktywacji to inna nazwa ramki stosu. Układ ramki stosu jest określany w ABI przez producenta i każdy kompilator obsługujący ISA musi być zgodny z tym standardem, jednak schemat układu może być zależny od kompilatora. Ogólnie rozmiar ramki stosu nie jest ograniczony, ale istnieje koncepcja zwana „czerwoną / chronioną strefą”, która umożliwia wykonywanie wywołań systemowych ... itd. Bez ingerencji w ramkę stosu.
Zawsze występuje SP, ale na niektórych ABI (na przykład ARM i PowerPC) FP jest opcjonalny. Argumenty, które musiały zostać umieszczone na stosie, można skompensować tylko za pomocą SP. To, czy ramka stosu jest generowana dla wywołania funkcji, zależy od typu i liczby argumentów, zmiennych lokalnych oraz ogólnego sposobu dostępu do zmiennych lokalnych. W większości ISA, po pierwsze, używane są rejestry i jeśli jest więcej argumentów niż rejestry dedykowane do przekazywania argumentów, są one umieszczane na stosie (na przykład x86 ABI ma 6 rejestrów do przekazywania argumentów liczb całkowitych). Dlatego czasami niektóre funkcje nie wymagają umieszczenia ramki stosu na stosie, tylko adres zwrotny jest wypychany na stos.
źródło