Notatka
Dostęp do tej strony wymaga autoryzacji. Może spróbować zalogować się lub zmienić katalogi.
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować zmienić katalogi.
Cała pamięć poza bieżącym adresem RSP jest uważana za ulotną: system operacyjny lub debuger może nadpisać tę pamięć podczas sesji debugowania użytkownika lub obsługi przerwań. W związku z tym przed próbą odczytu lub zapisu wartości w ramce stosu należy zawsze ustawiać RSP.
W tej sekcji omówiono alokację przestrzeni stosu dla zmiennych lokalnych i funkcji wewnętrznej alloca.
Alokacja stosu
Prolog funkcji jest odpowiedzialny za przydzielanie miejsca stosu na zmienne lokalne, zapisane rejestry, parametry stosu i parametry rejestru.
Obszar parametru jest zawsze w dolnej części stosu (nawet jeśli alloca jest używany), dzięki czemu zawsze będzie sąsiadować z adresem zwrotnym podczas dowolnego wywołania funkcji. Zawiera co najmniej cztery wpisy, ale zawsze wystarczająco dużo miejsca, aby przechowywać wszystkie parametry wymagane przez dowolną funkcję, która może być wywoływana. Należy pamiętać, że miejsce jest zawsze przydzielane dla parametrów rejestru, nawet jeśli same parametry nigdy nie są zapisywane na stosie; funkcja wywoływana gwarantuje, że dla wszystkich jej parametrów zarezerwowano miejsce. Adresy bazowe są wymagane dla argumentów rejestru, aby zapewnić ciągły obszar pamięci na wypadek, gdyby wywołana funkcja musiała uzyskać adres listy argumentów (va_list) lub pojedynczego argumentu. Ten obszar zapewnia również wygodne miejsce do zapisywania argumentów rejestrowych podczas wykonywania thunk oraz jako opcję debugowania (na przykład, ułatwia znalezienie argumentów podczas debugowania, jeśli są przechowywane na ich adresach domowych w kodzie prologu). Nawet jeśli wywoływana funkcja ma mniej niż 4 parametry, te 4 lokalizacje stosu są praktycznie przypisane do wywoływanej funkcji i mogą być wykorzystywane do innych celów oprócz zapisywania wartości rejestrów parametrów. W związku z tym wywołujący może nie zapisywać informacji w tym regionie stosu podczas wywołania funkcji.
Jeśli pamięć jest dynamicznie przydzielana (alloca) w funkcji, to rejestr nieulotny musi być używany jako wskaźnik ramki do oznaczenia podstawy stałej części stosu i musi być zapisany oraz zainicjowany w prologu. Należy pamiętać, że kiedy używa się alloca, wywołania do tego samego adresata z tego samego wywołującego mogą mieć różne adresy bazowe dla ich parametrów rejestru.
Stos zawsze będzie utrzymywany w 16-bajtowym wyrównaniu, z wyjątkiem w prologu (na przykład po zapisaniu adresu powrotu na stos) i z wyjątkiem przypadków określonych w Rodzajach Funkcji dla określonej klasy funkcji ramek.
Poniżej przedstawiono przykład układu stosu, w którym funkcja A wywołuje funkcję nie-liściową B. Prolog funkcji A już przydzielił miejsce dla wszystkich parametrów rejestru i stosu wymaganych przez B na dole stosu. Wywołanie wypycha adres zwrotny, a prolog B przydziela miejsce na zmienne lokalne, rejestry nieulotne oraz miejsce potrzebne do wywołania funkcji. Jeśli B używa alloca, miejsce jest przydzielane między obszarem zapisu rejestru zmiennej lokalnej/nieulotnej a obszarem stosu parametrów.
Gdy funkcja B wywołuje inną funkcję, adres zwrotny jest umieszczany tuż poniżej domyślnego adresu dla RCX.
Dynamiczna konstrukcja obszaru stosu parametrów
Jeśli jest używany wskaźnik ramki, opcja istnieje, aby dynamicznie utworzyć obszar stosu parametrów. Nie jest to obecnie wykonywane w kompilatorze x64.
Typy funkcji
Istnieją w zasadzie dwa typy funkcji. Funkcja, która wymaga ramki stosu, nazywana jest funkcją ramki stosu. Funkcja, która nie wymaga ramki stosu, jest nazywana funkcją liściową.
Funkcja ramki to funkcja, która przydziela przestrzeń stosu, wywołuje inne funkcje, zapisuje niewolne rejestry lub używa obsługi wyjątków. Wymaga również wpisu tabeli funkcji. Funkcja ramki wymaga prologu i epilogu. Funkcja ramki może dynamicznie przydzielać miejsce na stosie i stosować wskaźnik ramki. Funkcja ramowa ma pełne możliwości tego standardu wywołań.
Jeśli funkcja ramki stosu nie wywołuje innej funkcji, nie wymaga wyrównania stosu (przywoływane w sekcji Alokacja Stosu).
Funkcja liścia jest funkcją, która nie wymaga wpisu tabeli funkcji. Nie może wprowadzać zmian w żadnych rejestrach niezauwolnych, w tym RSP, co oznacza, że nie może wywoływać żadnych funkcji ani przydzielać miejsca na stosie. Można pozostawić stos nieuporządkowany podczas jego wykonywania.
wyrównanie malloc
Malloc ma gwarancję zwracania pamięci, która jest odpowiednio wyrównana do przechowywania dowolnego obiektu, który ma podstawowe wyrównanie i może zmieścić się w ilości przydzielonej pamięci. Podstawowe wyrównanie to wyrównanie mniejsze lub równe największemu wyrównaniu obsługiwanemu przez implementację bez specyfikacji wyrównania. (W języku Microsoft C++ jest to wyrównanie wymagane dla double, czyli 8 bajtów. W kodzie przeznaczonym dla platform 64-bitowych jest to 16 bajtów). Na przykład alokacja czterech bajtów zostanie wyrównana do granicy, która obsługuje każdy obiekt o rozmiarze czterech bajtów lub mniejszym.
Visual C++ zezwala na typy, które mają zwiększone wyrównanie, znane również jako typy z nadmiernym wyrównaniem. Na przykład typy SSE __m128 oraz typy zadeklarowane przy użyciu __declspec(align( n )), gdzie n jest większe niż 8, mają rozszerzone wyrównanie. Wyrównanie pamięci na odpowiedniej granicy dla obiektu z wymaganiem rozszerzonego wyrównania nie jest gwarantowane przez element malloc. Aby przydzielić pamięć dla nadmiernie wyrównanych typów, użyj _aligned_malloc i powiązanych funkcji.
alloca
_alloca musi być wyrównana do 16 bajtów i dodatkowo wymagana do użycia wskaźnika ramki.
Przydzielony stos musi zawierać miejsce po nim dla parametrów kolejnych nazywanych funkcjami, zgodnie z opisem w temacie Alokacja stosu.