Segmentace paměti x86 - x86 memory segmentation

Segmentace paměti x86 se týká implementace segmentace paměti v architektuře sady počítačových instrukcí Intel x86 . Segmentace byla na Intel 8086 zavedena v roce 1978 jako způsob, který umožňuje programům adresovat více než 64 kB (65 536  bajtů ) paměti. Intel 80286 představil druhou verzi segmentace v roce 1982, která přidává podporu pro virtuální paměť a ochrany paměti . V tomto okamžiku byl původní model přejmenován na skutečný režim a nová verze byla pojmenována jako chráněný režim . Architektura x86-64 , představená v roce 2003, do značné míry zrušila podporu segmentace v 64bitovém režimu.

V reálném i chráněném režimu používá systém k odvození skutečné adresy paměti 16bitové segmentové registry . V reálném režimu registry CS, DS, SS a ES ukazují na aktuálně používaný segment programového kódu (CS), aktuální datový segment (DS), aktuální segment zásobníku (SS) a jeden další segment určený programátorem (ES). Intel 80386 , který byl zaveden v roce 1985, přidává další dvě segmentové registry, FS a GS, bez zvláštní použití definovaných hardware. Způsob použití segmentových registrů se mezi těmito dvěma režimy liší.

Volba segmentu je standardně předvolena procesorem podle prováděné funkce. Pokyny jsou vždy načítány ze segmentu kódu. Jakýkoli push nebo pop zásobníku nebo jakýkoli odkaz na data odkazující na zásobník používá segment zásobníku. Všechny ostatní odkazy na data používají datový segment. Extra segment je výchozí cíl pro řetězcové operace (například MOVS nebo CMPS). FS a GS nemají použití přiřazené hardwarem. Formát instrukce umožňuje volitelný byte prefixu segmentu, který lze v případě potřeby použít k přepsání výchozího segmentu pro vybrané instrukce.

Skutečný režim

Tři segmenty v paměti reálného režimu (pro zvětšení klikněte na obrázek). Mezi segmentem 2 a segmentem 3 se překrývá; bajty v tyrkysové oblasti lze použít z obou segmentových voličů.

V reálném režimu nebo režimu V86 se velikost segmentu může pohybovat od 1 bajtu do 65 536 bajtů (pomocí 16bitových offsetů).

16bitový volič segmentů v registru segmentů je interpretován jako nejvýznamnějších 16 bitů lineární 20bitové adresy, nazývaných adresa segmentu, přičemž zbývající čtyři nejméně významné bity jsou všechny nuly. Adresa segmentu je v instrukci vždy přidána k 16bitovému offsetu, aby byla získána lineární adresa, která je v tomto režimu stejná jako fyzická adresa . Například segmentovaná adresa 06EFh: 1234h (zde přípona „h“ znamená hexadecimální ) má volič segmentu 06EFh, což představuje adresu segmentu 06EF0h, ke které se přidá ofset, čímž se získá lineární adresa 06EF0h + 1234h = 08124h.

  0000 0110 1110 1111  0000 Segment , 16 bitů, posunuto o 4 bity vlevo (nebo vynásobeno 0x10)
+      0001 0010 0011 0100 Ofset , 16 bitů
                          
  0000 1000 0001 0010 0100 Adresa , 20 bitů

Kvůli způsobu přidání adresy segmentu a ofsetu lze jednu lineární adresu namapovat až na 2 12 = 4096 odlišných párů segment: offset. Například lineární adresa 08124h může mít segmentované adresy 06EFh: 1234h, 0812h: 0004h, 0000h: 8124h atd.

To by mohlo být matoucí pro programátory zvyklé na jedinečná schémata adresování, ale může to být také výhoda, například při adresování více vnořených datových struktur. Zatímco segmenty reálného režimu jsou vždy 64  kB dlouhé, praktickým efektem je pouze to, že žádný segment nemůže být delší než 64 KB, nikoli každý segment musí mít 64 kB. Protože v reálném režimu neexistuje žádná ochrana ani omezení oprávnění, i když by segment mohl být definován jako menší než 64 kB, bylo by stále zcela na programech, aby je koordinovaly a udržovaly v mezích svých segmentů, jak to dokáže jakýkoli program. vždy přistupujte k jakékoli paměti (protože může libovolně nastavit výběr segmentů na změnu adres segmentů bez absolutního dohledu). Proto si lze stejně dobře představit skutečný režim, který má proměnnou délku pro každý segment, v rozsahu 1 až 65 536 bajtů, což CPU prostě nevynucuje.

(Úvodní nuly lineární adresy, segmentované adresy a pole segmentu a odsazení jsou zde pro přehlednost zobrazeny. Obvykle jsou vynechány.)

Efektivní 20bitový adresní prostor reálného režimu omezuje adresovatelnou paměť na 2 20  bajtů nebo 1 048 576 bajtů (1  MB ). To bylo odvozeno přímo z hardwarového designu Intel 8086 (a následně blízce příbuzného 8088), který měl přesně 20 adresních pinů . (Oba byly zabaleny do 40kolíkových DIP balíčků; dokonce s pouhými 20 adresními řádky byly adresové a datové sběrnice multiplexovány, aby se vešly všechny adresy a datové linky do omezeného počtu pinů.)

Každý segment začíná na násobku 16 bajtů, nazývaných odstavec , od začátku lineárního (plochého) adresního prostoru. To znamená v intervalech 16 bajtů. Protože jsou všechny segmenty 64 kB dlouhé, vysvětluje to, jak může docházet k překrývání mezi segmenty a proč lze k libovolnému umístění v adresním prostoru lineární paměti přistupovat pomocí mnoha párů segment: offset. Skutečnou polohu začátku segmentu v prostoru lineárních adres lze vypočítat pomocí segmentu × 16. Hodnota segmentu 0Ch (12) by poskytla lineární adresu na C0h (192) v prostoru lineárních adres. K tomuto číslu pak lze přidat offset adresy. 0Ch: 0Fh (12:15) bude C0h+0Fh = CFh (192+15 = 207), CFh (207) je lineární adresa. Takové překlady adres jsou prováděny segmentační jednotkou CPU. Poslední segment, FFFFh (65535), začíná na lineární adrese FFFF0h (1048560), 16 bytů před koncem 20bitového adresního prostoru, a tak má přístup s posunem až 65 536 bytů, až 65 520 (65 536 −16) bajtů za koncem 20bitového adresního prostoru 8088. Na 8088 byly tyto přístupy k adrese zabaleny kolem začátku adresního prostoru tak, že 65535: 16 by přistupovalo k adrese 0 a 65533: 1000 k adrese 952 lineárního adresního prostoru. Použití této funkce programátory vedlo k problémům s kompatibilitou brány A20 v pozdějších generacích CPU, kde byl lineární adresový prostor rozšířen za posledních 20 bitů.

V 16bitovém reálném režimu je umožnění aplikacím využívat více paměťových segmentů (za účelem přístupu k více paměti, než je k dispozici v jakémkoli 64K segmentu) poměrně složité, ale bylo považováno za nutné zlo pro všechny nástroje, kromě těch nejmenších ( což by mohlo dělat s menší pamětí). Jádrem problému je, že nejsou k dispozici žádné vhodné adresně aritmetické instrukce vhodné pro plošné adresování celého rozsahu paměti. Ploché adresování je možné použitím více instrukcí, což však vede k pomalejším programům.

Koncept paměťového modelu je odvozen od nastavení registrů segmentů. Například v malém modelu CS = DS = SS, to je kód programu, data a zásobník jsou obsaženy v jednom segmentu 64 kB. V modelu malé paměti DS = SS, takže data i zásobník se nacházejí ve stejném segmentu; CS ukazuje na jiný segment kódu až 64 kB.

Chráněný režim

Tři segmenty v paměti chráněného režimu (pro zvětšení klikněte na obrázek) s tabulkou lokálního deskriptoru .

80286 chráněný režim

80286 je chráněná režim rozšiřuje adresový prostor procesoru do 2 24 bajtů (16 megabajtů), ale ne nastavením hodnoty posunu. Místo toho nyní 16bitové segmentové registry nyní obsahují index do tabulky deskriptorů segmentů obsahujících 24bitové základní adresy, ke kterým je přidán offset. Pro podporu starého softwaru se procesor spouští v "reálném režimu", což je režim, ve kterém používá model segmentovaného adresování 8086. Existuje však malý rozdíl: výsledná fyzická adresa již není zkrácena na 20 bitů, takže skutečná ukazatele režimu (nikoli však ukazatele 8086) mohou nyní odkazovat na adresy mezi 100000 16 a 10FFEF 16 . Tato zhruba 64kilobajtová oblast paměti byla známá jako High Memory Area (HMA) a pozdější verze DOS ji mohly využít ke zvětšení dostupné „konvenční“ paměti (tj. V rámci prvního MB ). Po přidání HMA je celkový adresní prostor přibližně 1,06 MB. Ačkoli 80286 neskrátí adresy v reálném režimu na 20 bitů, systém obsahující 80286 to může udělat s hardwarem vně procesoru, a to tak, že odepne 21. adresní řádek, řádek A20 . Hardware IBM PC AT poskytl k tomu hardware (pro plnou zpětnou kompatibilitu se softwarem pro původní modely IBM PC a PC/XT ), a tak to udělaly i všechny následující PC klony „ AT -class“.

Chráněný režim 286 se používal jen zřídka, protože by vylučoval velkou skupinu uživatelů s počítači 8086/88. Kromě toho stále vyžadovalo rozdělení paměti na 64k segmenty, jako se to dělo v reálném režimu. Toto omezení lze obejít na 32bitových procesorech, které umožňují použití ukazatelů paměti větších než 64 kB, ale protože pole Limit segmentu je pouze 24bitové, maximální velikost segmentu, kterou lze vytvořit, je 16 MB (ačkoli stránkovací lze použít k přidělení více paměti, žádný jednotlivý segment nesmí překročit 16 MB). Tato metoda se běžně používala v aplikacích Windows 3.x k vytvoření plochého paměťového prostoru, ačkoli vzhledem k tomu, že samotný operační systém byl stále 16bitový, volání API nebylo možné provádět s 32bitovými pokyny. Bylo tedy stále nutné umístit veškerý kód, který provádí volání API, do 64k segmentů.

Jakmile je vyvolán chráněný režim 286, nelze jej opustit, kromě provedení hardwarového resetu. Stroje navazující na rostoucí standard IBM PC/AT mohly předstírat reset CPU prostřednictvím standardizovaného ovladače klávesnice, ale to bylo výrazně pomalé. Windows 3.x oba tyto problémy vyřešil záměrným spuštěním trojité chyby v mechanismech zpracování přerušení procesoru, což by způsobilo, že se CPU téměř okamžitě vrátí zpět do reálného režimu.

Podrobný pracovní postup segmentační jednotky

Logická adresa se skládá ze 16bitového segmentového voliče (dodávajícího 13+1 adresních bitů) a 16bitového offsetu. Volič segmentů musí být umístěn v jednom ze segmentových registrů. Tento selektor se skládá z 2bitové požadované úrovně oprávnění (RPL), 1bitového indikátoru tabulky (TI) a 13bitového indexu.

Při pokusu o překlad adresy dané logické adresy procesor načte strukturu 64bitového segmentového deskriptoru buď z tabulky globálního deskriptoru, když TI = 0, nebo z tabulky lokálního deskriptoru, když TI = 1. Poté provede kontrolu oprávnění:

max (CPL, RPL) ≤ DPL

kde CPL je aktuální úroveň oprávnění (nachází se v dolních 2 bitech registru CS), RPL je požadovaná úroveň privilegií z voliče segmentů a DPL je úroveň oprávnění segmentu popisovače (nachází se v deskriptoru). Všechny úrovně oprávnění jsou celá čísla v rozsahu 0–3, kde nejnižší číslo odpovídá nejvyššímu oprávnění.

Pokud je nerovnost nepravdivá, generuje procesor chybu obecné ochrany (GP) . Jinak překlad adres pokračuje. Procesor poté převezme 32bitový nebo 16bitový offset a porovná je s limitem segmentu uvedeným v deskriptoru segmentu. Pokud je větší, generuje se porucha GP. Jinak procesor přidá 24-bitovou segmentovou základnu, specifikovanou v deskriptoru, na offset, čímž vytvoří lineární fyzickou adresu.

Kontrola oprávnění se provádí pouze při načtení registru segmentů, protože deskriptory segmentů jsou ukládány do mezipaměti ve skrytých částech registrů segmentů.

80386 chráněný režim

V procesorech Intel 80386 a novějších si chráněný režim zachovává mechanismus segmentace chráněného režimu 80286, ale jako druhá vrstva překladu adres byla přidána stránkovací jednotka mezi segmentační jednotkou a fyzickou sběrnicí. Rovněž je důležité, že offsety adres jsou 32bitové (namísto 16bitových) a základna segmentu v každém deskriptoru segmentu je také 32bitová (namísto 24bitová). Obecný provoz segmentační jednotky je jinak beze změny. Stránkovací jednotku lze povolit nebo zakázat; pokud je zakázáno, operace je stejná jako na 80286. Pokud je povolena stránkovací jednotka, adresy v segmentu jsou nyní virtuální adresy, nikoli fyzické adresy jako na 80286. To znamená, že počáteční adresa segmentu, offset, a konečná 32bitová adresa segmentační jednotky odvozené přidáním dvou jsou všechny virtuální (nebo logické) adresy, když je aktivována stránkovací jednotka. Když segmentační jednotka generuje a ověřuje tyto 32bitové virtuální adresy, povolená stránkovací jednotka tyto virtuální adresy nakonec převede na fyzické adresy. Fyzické adresy jsou na 386 32bitové , ale mohou být větší u novějších procesorů, které podporují rozšíření fyzické adresy .

80386 také představil dva nové univerzální datové segmentové registry, FS a GS, do původní sady čtyř segmentových registrů (CS, DS, ES a SS).

CPU 386 lze vrátit zpět do reálného režimu tak, že trochu vymažete v řídicím registru CR0, ale toto je privilegovaná operace, která má zajistit bezpečnost a robustnost. Pro srovnání, 286 mohl být vrácen do skutečného režimu pouze vynucením resetu procesoru, např. Trojitou poruchou nebo použitím externího hardwaru.

Pozdější vývoj

Architektura x86-64 nepoužívá segmentaci v dlouhém režimu (64bitový režim). Čtyři ze segmentových registrů, CS, SS, DS a ES, jsou nuceny na 0 a limit na 2 64 . Segmentové registry FS a GS mohou mít stále nenulovou základní adresu. To umožňuje operačním systémům používat tyto segmenty pro speciální účely. Na rozdíl od mechanismu tabulky globálního deskriptoru používaného staršími režimy je základní adresa těchto segmentů uložena v registru specifickém pro model . Architektura x86-64 dále poskytuje speciální instrukci SWAPGS , která umožňuje prohození základních adres režimu jádra a uživatelského režimu .

Například Microsoft Windows na x86-64 používá segment GS k označení bloku Thread Environment Block , malé datové struktury pro každé vlákno , která obsahuje informace o zpracování výjimek, lokálních proměnných podprocesů a dalších stavech podle vlákna. Podobně linuxové jádro používá segment GS k ukládání dat na CPU.

GS / FS jsou také použity v gcc ‚s zásobníkového místní a kanárkově bázi zásobníku chránič.

Cvičení

Logické adresy lze explicitně zadat v jazyce sestavení x86 , např. (Syntaxe AT&T):

movl $42, %fs:(%eax)  ; Equivalent to M[fs:eax]<-42) in RTL

nebo v syntaxi Intel :

mov dword [fs:eax], 42

Registry segmentů se však obvykle používají implicitně.

  • Všechny instrukce CPU jsou implicitně načteny ze segmentu kódu určeného selektorem segmentů uloženým v registru CS.
  • Většina referencí paměti pochází z datového segmentu určeného voličem segmentů uloženým v registru DS. Ty mohou také pocházet z extra segmentu určeného selektorem segmentu uloženým v registru ES, pokud předpona přepisu segmentu předchází instrukci, která dělá referenci paměti. Většina, ale ne všechny pokyny, které ve výchozím nastavení používají DS, budou přijímat předponu přepsání ES.
  • Odkazy zásobníku procesoru , buď implicitně (např. Instrukce push a pop ), nebo explicitně ( přístupy do paměti pomocí registrů (E) SP nebo (E) BP ) používají segment zásobníku specifikovaný voličem segmentu uloženým v registru SS.
  • Návod string (např Štos , MOV ), spolu s datového segmentu, také použít další úsek určený selektoru segmentu se konala v EŠ registrovat.

Segmentaci nelze vypnout na procesorech x86-32 (to platí i pro 64bitový režim, ale mimo rámec diskuse), tolik 32bitových operačních systémů simuluje model ploché paměti nastavením základen všech segmentů na 0 aby byla segmentace vůči programům neutrální. Například jádro Linuxu nastavuje pouze 4 obecné segmenty:

název Popis Základna Omezit DPL
__KERNEL_CS Segment kódu jádra 0 4 GiB 0
__KERNEL_DS Datový segment jádra 0 4 GiB 0
__USER_CS Segment uživatelského kódu 0 4 GiB 3
__USER_DS Segment uživatelských dat 0 4 GiB 3

Vzhledem k tomu, že základna je ve všech případech nastavena na 0 a limit 4 GiB, segmentační jednotka neovlivní adresy, které programové problémy před tím, než dorazí na stránkovací jednotku. (To se samozřejmě týká procesorů 80386 a novějších, protože dřívější procesory x86 nemají stránkovací jednotku.)

Aktuální Linux také používá GS k odkazování na lokální úložiště vláken .

Segmenty lze definovat jako kódové, datové nebo systémové segmenty. K dispozici jsou další bity oprávnění, aby segmenty byly pouze pro čtení, čtení/zápis, spouštění atd.

V chráněném režimu může kód vždy upravovat všechny registry segmentů kromě CS ( volič segmentu kódu ). Důvodem je, že aktuální úroveň oprávnění (CPL) procesoru je uložena ve spodních 2 bitech registru CS. Jediné způsoby, jak zvýšit úroveň oprávnění procesoru (a znovu načíst CS), jsou příkazy lcall (vzdálené volání) a int (přerušení) . Podobně jediné způsoby, jak snížit úroveň oprávnění (a znovu načíst CS), jsou instrukce lret (vzdálený návrat) a iret (přerušený návrat). V reálném režimu může kód také upravit registr CS provedením skoku do dálky (nebo pomocí nezdokumentované POP CSinstrukce na 8086 nebo 8088)). V reálném režimu samozřejmě neexistují žádné úrovně oprávnění; všechny programy mají absolutně nekontrolovaný přístup do celé paměti a ke všem instrukcím CPU.

Další informace o segmentaci najdete v příručkách IA-32 volně dostupných na webech AMD nebo Intel .

Poznámky a reference

Viz také

externí odkazy