Oprócz innych odpowiedzi chciałbym dodać, że podczas tworzenia pamięci RAM między przestrzenią stosu i sterty, należy również wziąć pod uwagę przestrzeń dla statycznych niestałych danych (np. Globale plików, statyka funkcji i cały program globals z perspektywy C i prawdopodobnie inne dla C ++).
Jak działa alokacja stosu / sterty
Warto zauważyć, że plik zestawu startowego jest jednym ze sposobów definiowania regionu; łańcuch narzędzi (zarówno środowisko kompilacji, jak i środowisko wykonawcze) w głównej mierze dbają o symbole, które definiują początek obszaru stosu (używany do przechowywania początkowego wskaźnika stosu w tabeli wektorów) oraz początek i koniec obszaru sterty (używany przez dynamikę alokator pamięci, zazwyczaj dostarczany przez bibliotekę libc)
W przykładzie OP zdefiniowano tylko 2 symbole, rozmiar stosu na 1 kB i rozmiar stosu na 0 kB. Wartości te są używane gdzie indziej, aby faktycznie utworzyć stos i przestrzenie sterty
W przykładzie @Gilles rozmiary są zdefiniowane i używane w pliku zestawu do ustawiania przestrzeni stosu, zaczynając od miejsca, w którym trwa i trwa rozmiar, identyfikowany przez symbol Stack_Mem i ustawiający na końcu etykietę __initial_sp. Podobnie dla sterty, gdzie spacja jest symbolem Heap_Mem (rozmiar 0,5kiB), ale z etykietami na początku i na końcu (__heap_base i __heap_limit).
Są one przetwarzane przez linker, który nie przydzieli niczego w przestrzeni stosu i przestrzeni stosu, ponieważ ta pamięć jest zajęta (przez symbole Stack_Mem i Heap_Mem), ale może umieścić te wspomnienia i wszystkie globale tam, gdzie jest to potrzebne. Etykiety kończą się symbolami bez długości pod podanymi adresami. __Initial_sp jest używany bezpośrednio do tabeli wektorów w czasie łączenia, a __heap_base i __heap_limit przez kod środowiska wykonawczego. Rzeczywiste adresy symboli są przypisywane przez linker na podstawie tego, gdzie je umieścił.
Jak już wspomniałem powyżej, te symbole nie muszą pochodzić z pliku startup.s. Mogą pochodzić z twojej konfiguracji linkera (plik ładowania rozproszonego w Keil, linkerscript w GNU), aw tych możesz mieć dokładniejszą kontrolę nad umieszczaniem. Na przykład możesz zmusić stos do umieszczenia na początku lub na końcu pamięci RAM lub trzymać globale z daleka od stosu lub cokolwiek chcesz. Możesz nawet określić, że HEAP lub STACK zajmują tylko tyle pamięci RAM, ile pozostało po umieszczeniu globali. Pamiętaj jednak, że musisz uważać, aby dodać więcej zmiennych statycznych, aby zmniejszyć inne pamięci.
Jednak każdy zestaw narzędzi jest inny, a sposób zapisania pliku konfiguracyjnego i symboli używanych przez dynamiczny alokator pamięci będzie musiał pochodzić z dokumentacji konkretnego środowiska.
Rozmiar stosu
Jeśli chodzi o sposób określania wielkości stosu, wiele łańcuchów narzędzi może zapewnić maksymalną głębokość stosu, analizując drzewa wywołań funkcji w twoim programie, JEŻELI nie używasz wskaźników rekurencyjnych lub funkcyjnych. Jeśli ich użyjesz, oszacuj rozmiar stosu i wstępnie wypełnij go wartościami kardynalnymi (być może za pomocą funkcji wprowadzania przed głównym), a następnie sprawdź po uruchomieniu programu przez chwilę, gdzie była maksymalna głębokość (czyli tam, gdzie wartości kardynalne koniec). Jeśli w pełni wykorzystałeś swój program do granic swoich możliwości, będziesz dość dokładnie wiedział, czy możesz zmniejszyć stos lub, jeśli program się zawiesi lub nie pozostaną żadne wartości kardynalne, że musisz zwiększyć stos i spróbować ponownie.
Rozmiary sterty
Określenie wielkości sterty jest nieco bardziej zależne od aplikacji. Jeśli dokonujesz alokacji dynamicznej tylko podczas uruchamiania, możesz po prostu dodać miejsce wymagane w kodzie startowym (plus trochę narzuty na zarządzanie pamięcią). Jeśli masz dostęp do źródła swojego menedżera pamięci, możesz dokładnie wiedzieć, co to jest narzut, a może nawet napisać kod, aby przejść pamięć i podać informacje o użytkowaniu. W przypadku aplikacji, które potrzebują dynamicznej pamięci środowiska wykonawczego (np. Przydzielanie buforów dla przychodzących ramek ethernetowych), najlepsze, co mogę zasugerować, to dokładnie wyostrzyć swój rozmiar stosu i dać stosowi wszystko, co pozostało po stosie i statyce.
Uwaga końcowa (RTOS)
Pytanie OP zostało oznaczone jako goły metal, ale chcę dodać notatkę dla RTOS. Często (zawsze?) Każdemu zadaniu / procesowi / wątkowi (po prostu napiszę tutaj zadanie dla uproszczenia) zostanie przypisany rozmiar stosu podczas tworzenia zadania, a oprócz stosów zadań prawdopodobnie będzie mały system operacyjny stos (używany do przerwań i tym podobnych)
Struktury rozliczania zadań i stosy muszą być skądś przydzielone, a często będzie to związane z ogólną przestrzenią sterty aplikacji. W takich przypadkach początkowy rozmiar stosu często nie ma znaczenia, ponieważ system operacyjny użyje go tylko podczas inicjalizacji. Widziałem na przykład, że WSZYSTKIE pozostałe miejsce podczas łączenia ma zostać przydzielone do HEAP i umieszczenie początkowego wskaźnika stosu na końcu stosu, aby wyrósł na stertę, wiedząc, że system operacyjny przydzieli od początku stosu i przydzieli stos systemu operacyjnego tuż przed opuszczeniem stosu initial_sp. Następnie cała przestrzeń jest wykorzystywana do przydzielania stosów zadań i innej dynamicznie alokowanej pamięci.