Próbuję zrozumieć, w jaki sposób budowane są ramki stosu i które zmienne (parametry) są wypychane do stosu w jakiej kolejności? Niektóre wyniki wyszukiwania wykazały, że kompilator C / C ++ decyduje na podstawie operacji wykonywanych w ramach funkcji. Na przykład, jeśli funkcja miała po prostu zwiększyć przekazaną wartość int o 1 (podobnie jak operator ++) i zwrócić ją, umieściłby wszystkie parametry funkcji i zmiennych lokalnych w rejestrach.
Zastanawiam się, które rejestry są używane do zwracania lub przekazywania parametrów wartości. Jak zwracane są referencje? Jak kompilator wybiera między eax, ebx, ecx i edx?
Co muszę wiedzieć, aby zrozumieć, w jaki sposób rejestry, odwołania do stosu i stosu są używane, budowane i niszczone podczas wywoływania funkcji?
Odpowiedzi:
Oprócz tego, co powiedział Dirk, ważnym zastosowaniem ramek stosu jest zapisywanie poprzednich wartości rejestrów, aby można je było przywrócić po wywołaniu funkcji. Tak więc nawet na procesorach, w których rejestry są używane do przekazywania parametrów, zwracania wartości i zapisywania adresu zwrotnego, wartości tych rejestrów są zapisywane na stosie przed wywołaniem funkcji, aby można je było przywrócić po wywołaniu. Dzięki temu jedna funkcja może wywoływać inną bez nadpisywania własnych parametrów lub zapomnienia własnego adresu zwrotnego.
Wywołanie funkcji B z funkcji A w typowym „ogólnym” systemie może obejmować następujące kroki:
Nie jest to w żaden sposób jedyny sposób, w jaki mogą zadziałać wywołania funkcji (i mogę mieć krok lub dwa zepsute), ale powinien dać ci wyobrażenie o tym, jak stos jest używany, aby procesor obsługiwał zagnieżdżone wywołania funkcji.
źródło
push
ipop
są to dwie podstawowe operacje na stosie. Stos jest strukturą „kto pierwszy, ten pierwszy”, podobnie jak stos książek. Kiedy typush
kładziesz nowy obiekt na stosie; kiedypop
bierzesz przedmiot ze szczytu stosu. Nie możesz wstawiać ani usuwać obiektów na środku, możesz operować tylko na górze stosu. Możesz przeczytać więcej o stosach ogólnie, a stosie programów w szczególności na Wikipedii.Zależy to od zastosowanej konwencji wywoływania. Ktokolwiek zdefiniuje konwencję wywoływania, może podjąć taką decyzję, jak chce.
W najpopularniejszej konwencji wywoływania na x86 rejestry nie są używane do przekazywania parametrów; parametry są wypychane na stos, zaczynając od parametru znajdującego się najdalej po prawej stronie. Zwracana wartość jest umieszczana w eax i może używać edx, jeśli potrzebuje dodatkowej przestrzeni. Referencje i wskaźniki są zwracane w postaci adresu w eax.
źródło
Jeśli rozumiesz stos bardzo dobrze, zrozumiesz, jak działa pamięć 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 przechowywać funkcje w stosie:
Sterty przechowują wartości dynamicznego przydziału pamięci. Wartości automatycznej alokacji i usuwania magazynu stosu.
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 jakakolwiek funkcja zostanie „zwrócona” bez względu na to, że załadowała wszystkie lokalne zmienne lub cokolwiek, co natychmiast zwróci ze stosu, zmieni ramkę stosu. Oznacza to, że gdy jakakolwiek funkcja rekurencyjna uzyska warunek podstawowy, a my ustawimy return po warunku podstawowym, więc warunek podstawowy nie będzie czekał na załadowanie zmiennych lokalnych, które znajdują się w „innej” części programu, natychmiast zwróci bieżącą ramkę ze stosu, a teraz, jeśli jedna ramka powrót następnej klatki jest w rekordzie aktywacji. Zobacz to w praktyce:
Tak więc teraz, gdy funkcja znajdzie instrukcję return, usuwa bieżącą ramkę ze stosu.
podczas powrotu ze stosu wartość zostanie zwrócona w odwrotnej kolejności, w jakiej zostały przydzielone w stosie.
To bardzo krótki opis i jeśli chcesz dowiedzieć się więcej o stosie i podwójnej rekurencji, przeczytaj dwa posty na tym blogu:
Więcej informacji o stosie krok po kroku
Więcej informacji o Podwójnej rekurencji krok po kroku ze stosem
źródło
To, czego szukasz, nazywa się Application Binary Interface - ABI.
Dla każdego kompilatora istnieje specyfikacja określająca ABI.
Każda platforma zwykle określa i ABI w celu obsługi interoperacyjności między kompilatorami. Na przykład, Konwencje wywoływania x86 określają typowe konwencje wywoływania dla x86 i x86-64. Spodziewałbym się jednak bardziej oficjalnego dokumentu niż wikipedia.
źródło