Segmentace programu paměti

Paměť programu je rozdělena na pět segmentů: text, data, bss (block started,by symbol, segment neinicializovaných dat), heap ( halda) a stack ( zásobník).,Každý segment reprezentuje speciální část paměti, která je vymezena,pro určité účely.,Segment text se někdy značí i jako code. To je místo, kde se nacházejí,instrukce strojového jazyka. Vykonávání instrukcí v tomto segmentu,není lineární, diky výše zmíněným vysokoúrovňovým řídicím strukturám,a funkcím, které se zkompilují do instrukcí větvení ( branch), skoků ( jump),a volání ( call). V okamžiku spuštění programu se EIP nastaví na první instrukci,segmentu text. Procesor potom následuje vykonávací smyčku, která
dělá následující:
1. Přečti instrukci, na kterou ukazuje EIP.
2. Přičti k EIP délku instrukce.
3. Vykonej instrukci přečtenou v kroku 1.
4. Jdi na krok 1.
Někdy je přečtená instrukce instrukcí skoku nebo volání, která mění EIP na,jinou adresu. Procesor se nestará o změny, neboť stejně předpokládá nelineární,vykonávání. Takže pokud se v kroku 3 EIP nějak změní, procesor bude dále pokračovat v kroku 1, přečte a vykoná další instrukci, na kterou EIP ukazuje, ať už bude jakákoliv. Právo zápisu je v segmentu text vypnuto, neboť neslouží k uchovávání proměnných, ale jen kódu. To zabrání lidem modifikovat programový kód a jakýkoliv pokus o zápis do tohoto segmentu paměti způsobí zobrazení varování uživateli, že se stalo něco špatného, a okamžité ukončení programu. Další výhodou toho, že je tento segment pouze pro čtení, je umožnění jeho bezproblémového sdílení při spuštění více kopií téhož programu. Také je vhodné poznamenat, že tento segment má fixní velikost.  Segmenty data a bss se používají pro uchování globálních a statických programových proměnných. V segmentu data se ukrývají inicializované globální proměnné, řetězce a další konstanty, které jsou v programu užívány. V segmentu bss jsou neinicializované proměnné. Ačkoliv jsou tyto segmenty zapisovatelé, také mají fixní velikost. Segment heap (halda) se používá pro ostatní programové proměnné. Segment haldy nemá konstantní velikost a podle potřeby může jeho velikost růst i klesat. Celá tato paměť je řízena alokačními a dealokačními algoritmy, které rezervují část paměti pro pozdější použití a zpětně odstraňují rezervace, aby se oblast mohla později opět využít. Halda bude růst a klesat v závislosti na tom, kolik paměti má pro tyto účely rezervováno. Růst haldy začíná na nižších a postupuje do vyšších adres paměti. Segment stack (zásobník) má také proměnou velikost a používá se jako dočasné úložiště pro kontext během volání funkcí. Když program zavolá funkci, bude mít vlastní sadu proměnných a kód funkce bude v jiné části segmentu text (nebo code). Protože se kontext a EIP musí při volání funkce změnit, zásobník slouží k zapamatování všech proměnných a EIP, na který se po skončení funkce program opět vrátí. V obecných počítačových termínech je zásobník abstraktní datová struktura, která se velmi často používá. Má řazení typu FILO (First-In, Last-Out – první dovnitř, poslední ven), což znamená, že první položka, která se do stacku dostane je tou poslední, která ze stacku může ven. Je to jako skládání korálků na šňůru, která má zavázaný druhý konec – nemůžete dostat ven první korálek bez toho, aniž byste nejdříve nevytáhli ostatní korálky. Přidání položky na zásobník se říká pushing a odebírání popping. Jak napovídá jméno, paměťový segment zásobníku je ve skutečnosti datová struktura. Registr ESP se používá k udržování adresy na konci zásobníku, který se neustále mění, tak jak jsou neustále přidávány a odebírány položky. Vzhledem k dynamickému chování této struktury je zřejmé, že stack nemá fixní velikost. Opačně než halda velikost zásobníku roste z vyšších adres k nižším. Použití koncepce FILO pro implementaci zásobníku se může zdát zbytečné, ale protože se stack používá pro uchovávání kontextu, je to velmi užitečné. Když se zavolá funkce, potřebné údaje se vloží na zásobník ve formě tzv. rámce zásobníku ( stack frame). Registr EBP, občas nazývaný jako frame pointer ( FP, ukazatel na rámec) nebo local base pointer ( LB, ukazatel na lokální bázi), se použije k odkazování na proměnné v aktuálním zásobníkovém rámci. Každý takový rámec obsahuje parametry funkcí, její lokální proměnné a dva pointery důležité pro navrácení věcí do stavu, v jakém byly před samotným voláním: saved frame pointer ( SFP, uložený ukazatel na rámec) a návratová adresa ( return value). Pointer na rámec zásobníku se používá k obnovení EBP na jeho předchozí hodnotu a návratová adresa k obnovení EIP na další instrukcí hned za voláním funkce. Zde je příklad testovací funkce a hlavní funkce: void test_function(int a, int b, int c, int d)
{
char flag;
char buffer[10];
}
void main()
{
test_function(1, 2, 3, 4);
}
V tomto krátkém kousku kódu se deklaruje testovací funkce se čtyřmi argumenty, které jsou deklarovány jako celá čísla: a, b, c a d. Lokální proměnné pro funkci zahrnuje jeden znak nazvaný flag a desetiznakový buffer nazvaný buffer. Funkce main() se po spuštění programu spustí jako první a jednoduše zavolá testovací funkci. Když se funkce test_function zavolá z funkce main, uloží se na zásobník rozličné hodnoty a vytvoří se rámec zásobníku. Argumenty funkce se uloží v opačném pořadí (protože je stack FILO), tedy d, c, b a nakonec a. V okamžiku, kdy je spuštěna instrukce call pro volání funkce test_ function(), se na zásobník uloží návratová adresa, jejíž hodnota bude EIP ukazující na instrukci za instrukcí volání (tedy adresa instrukce call + velikost samotné instrukce). Za návratovou adresou se nachází tzv. prolog procedury. V tomto kroku se do zásobníku uloží hodnota registru EBP, což je uložený ukazatel na rámec a později se použije pro obnovení do původního stavu. Aktuální hodnota registru ESP se potom zkopíruje do registru EBP a tím se nastaví ukazatel na nový rámec. Nakonec se alokuje paměť pro lokální proměnné funkce (flag a buffer) na zásobníku zmenšením ESP.  Toto tedy je rámec zásobníku. Na lokální proměnné se odkazuje odečítáním z ukazatele na rámec (registr EBP) a na argumenty funkce přičítáním. Když se zavolá funkce, EIP se změní na adresu začátku funkce v segmentu text (nebo code). Paměť na zásobníku se použije pro lokální proměnné funkce a její argumenty. Když se funkce ukončí, celý rámec zásobníku se ze zásobníku odstraní a EIP se nastaví na uloženou návratovou adresu, takže program může dále pokračovat ve vykonávání. Jestliže by se z dané funkce zavolala jiná funkce, vytvořil by se pro ni v zásobníku další rámec a tak dále. Při každém ukončení funkce se rámec zásobníku odstraní a tak se může vykonávání kódu vrátit na předešlou funkci. Kvůli tomuto chování je tento segment paměti organizován jako FILO. Rozličné segmenty paměti jsou za sebou poskládány v pořadí, v jakém byly uvedeny, od nižších adres do vyšších. Protože většinou jsme zvyklí prohlížet si seznamy ze shora dolů, jsou nižší adresy uvedeny nahoře. Protože jsou segmenty heap a stack dynamické, rostou oba proti sobě. To minimalizuje plýtvání místem a možnost, že by se tyto segmenty střetly.