Architektura x86
Procesor Intel x86 používá komplexní architekturu počítačů s instrukční sadou (CISC), což znamená, že existuje skromný počet speciálních registrů místo velkého množství registrů pro obecné účely. To také znamená, že komplexní specializované instrukce budou převládat.
Procesor x86 sleduje jeho dědictví alespoň až do 8bitového procesoru Intel 8080. Mnoho specifik v instrukční sadě x86 je způsobeno zpětnou kompatibilitou s tímto procesorem (a s jeho variantou Zilog Z-80).
Microsoft Win32 používá procesor x86 v 32bitovém plochém režimu. Tato dokumentace se zaměří jenom na plochý režim.
Registruje
Architektura x86 se skládá z následujících neprivilegovaných celých registrů.
eax |
Akumulátor |
ebx |
Základní registr |
ecx |
Registr čítačů |
edx |
Registr dat – lze použít pro přístup k vstupně-výstupním portům a aritmetické funkce. |
esi |
Registr zdrojového indexu |
edi |
Registr cílového indexu |
ebp |
Registr základního ukazatele |
esp |
Ukazatel zásobníku |
Všechny celočíselné registry jsou 32bitové. Mnoho z nich ale obsahuje 16bitové nebo 8bitové subregistery.
ax |
Nízkých 16 bitů eax |
bx |
Nízkých 16 bitů ebx |
cx |
Dolních 16 bitů ecx |
dx |
Nízkých 16 bitů edx |
si |
16 nízkých bitů esi |
di |
Nízkých 16 bitů edi |
bp |
Dolních 16 bitů ebp |
sp |
Nízkých 16 bitů esp |
al |
Nízkých 8 bitů eax |
ah |
Hodnota horních 8 bitů registru AX |
|
8 nízkých bitů ebx |
bh |
Horních 8 bitů bx |
cl |
Nízkých 8 bitů ecx |
|
Vyšších 8 bitů registru CX pro a |
dl |
Nízkých 8 bitů edx |
dh |
Horních 8 bitů dx |
Operace na podregistru ovlivňuje pouze podregistr a žádné části mimo podregistr. Například uložení do registru ax ponechá vysokých 16 bitů registru eax beze změny.
Při použití příkazu ? (Evaluate Expression) by měly být registry opatřeny znakem zavináč ( @ ). Měli byste například použít ? @ax místo ? ax. Tím zajistíte, že ladicí program rozpozná ax jako registr místo symbolu.
Ve velení r (Registers) se však (@) nevyžaduje. Například r ax=5 bude vždy interpretováno správně.
Pro aktuální stav procesoru jsou důležité dva další registry.
eip |
ukazatel instrukce |
příznaky |
vlajky |
Ukazatel instrukce je adresa spuštěné instrukce.
Registr příznaků je kolekce jednobitových příznaků. Mnoho instrukcí mění příznaky, aby popsaly výsledek instrukce. Tyto příznaky je pak možné testovat pomocí pokynů podmíněného přeskakování. Podrobnosti naleznete v příznacích x86 .
Konvence volání
Architektura x86 má několik různých konvencí volání. Naštěstí se všechny řídí stejnými pravidly uchovávání registru a pravidly pro návrat z funkcí.
Funkce musí zachovat všechny registry s výjimkou eax, ecxa edx, které je možné změnit v rámci volání funkce, a esp, které musí být aktualizovány podle konvence volání.
eax registr přijímá návratové hodnoty funkce, pokud je výsledek 32 bitů nebo menší. Pokud je výsledek 64 bitů, výsledek se uloží do dvojice edx:eax.
Následuje seznam konvencí volání používaných v architektuře x86:
Win32 (__stdcall)
Parametry funkce se předávají na zásobníku, jsou vkládány zprava doleva a volaná funkce zásobník vyčistí.
Nativní volání metody C++ (označované také jako thiscall)
Parametry funkce se předávají na zásobník, vkládají se zprava doleva, ukazatel 'this' se předává v registru ecx a volající vyčistí zásobník.
COM (__stdcall pro volání metody C++)
Parametry funkce jsou předány na zásobník, nasunuty zprava doleva, pak je ukazatel "this" nasunut na zásobník, a poté je volána funkce. Volaný vyčistí zásobník.
__fastcall
První dva argumenty menší než nebo rovny DWORD jsou předány v registrech ecx a edx. Zbývající parametry se předávají na zásobník a jsou zasouvány zprava doleva. Volaný vyčistí zásobník.
__cdecl
Parametry funkce se předávají v zásobníku, odsunou zprava doleva a volající zásobník vyčistí. Konvence volání __cdecl se používá pro všechny funkce s parametry proměnné délky.
Zobrazení registrů a příznaků v ladicím programu
Tady je ukázkový výpis registru debuggeru:
eax=00000000 ebx=008b6f00 ecx=01010101 edx=ffffffff esi=00000000 edi=00465000
eip=77f9d022 esp=05cffc48 ebp=05cffc54 iopl=0 nv up ei ng nz na po nc
cs=001b ss=0023 ds=0023 es=0023 fs=0038 gs=0000 efl=00000286
Při ladění v uživatelském režimu můžete ignorovat iopl a celý řádek zobrazení ladicího nástroje.
x86 Příznaky
V předchozím příkladu jsou dvoupísmenné kódy na konci druhého řádku značky. Jedná se o jednobitové registry a různé způsoby použití.
Následující tabulka uvádí příznaky x86:
Kód příznaku | Název příznaku | Hodnota | Stav příznaku | Popis |
---|---|---|---|---|
z | Příznak přetečení | 0 1 | nvov | Bez přetečení – přetečení |
df | Příznak směru | 0 1 | updn | Směr nahoru – směr dolů |
pokud | Příznak přerušení | 0 1 | diei | Přerušení deaktivováno – Přerušení aktivováno |
sf | Znaková vlajka | 0 1 | #plng | Kladné (nebo nula) – záporné |
zf | Příznak Nula | 0 1 | nzzr | Nenula – nula |
af | Pomocný příznak pro přenos | 0 1 | naac | Žádný pomocný přenos – pomocný přenos |
pf | Příznak parity | 0 1 | pepo | Parita lichá – parita sudá |
cf | Příznak přenosu | 0 1 | nccy | Bez přenesení - Přenesení |
tf | Příznak soutisku | Pokud se tf rovná 1, procesor po provedení jedné instrukce vyvolá STATUS_SINGLE_STEP výjimku. Tento příznak používá ladicí program k implementaci trasování s jedním krokem. Neměly by ho používat jiné aplikace. | ||
iopl | Úroveň priority I/O | Úroveň oprávnění vstupně-výstupních operací Je to dvoubitové celé číslo s hodnotami mezi nulou a 3. Používá ho operační systém k řízení přístupu k hardwaru. Aplikace by ji neměly používat. |
Když se registry zobrazí jako výsledek nějakého příkazu v okně ladicího příkazu, zobrazí se stav příznaku . Pokud ale chcete změnit příznak pomocí příkazu r (Registers), měli byste použít kód příznaku.
V okně Registry winDbg se kód příznaku používá k zobrazení nebo změně příznaků. Stav příznaku není podporován.
Tady je příklad. V předchozím zobrazení registru se zobrazí stav příznaku ng. To znamená, že příznak znaménka je aktuálně nastavený na hodnotu 1. Pokud to chcete změnit, použijte následující příkaz:
r sf=0
Tím se příznak znaménka nastaví na nulu. Pokud provedete další zobrazení registru, stavový kód se nezobrazí. Místo toho se zobrazí stavový kód pl.
Příznak sign, příznak zero a příznak carry jsou nejčastěji používané příznaky.
Podmínky
Podmínka popisuje stav jednoho nebo více příznaků. Všechny podmíněné operace na platformě x86 jsou vyjádřeny za podmínek.
Assembler používá k reprezentaci podmínky jednopísmennou nebo dvoupísmennou zkratku. Podmínku může reprezentovat více zkratek. Například AE ("nad nebo rovno") je stejná podmínka jako NB ("není níže"). Následující tabulka uvádí některé běžné podmínky a jejich význam.
Název podmínky | Vlajky | Význam |
---|---|---|
Z |
ZF=1 |
Výsledek poslední operace byl nula. |
NZ |
ZF=0 |
Výsledek poslední operace nebyl nulový. |
C |
CF=1 |
Poslední operace vyžadovala přenos nebo zapůjčení. (Pro celá čísla bez znaménka to znamená přetečení.) |
NC |
CF=0 |
Poslední operace nepožadovala přenos nebo půjčování. (Pro celá čísla bez znaménka to indikuje přetečení.) |
S |
SF=1 |
Výsledek poslední operace má nastavený nejvyšší bit. |
NS |
SF=0 |
Výsledek poslední operace má svůj nejvyšší bit vynulovaný. |
O |
OF=1 |
Když je operace zpracována jako operace se znaménkovým celočíselným typem, poslední operace způsobila přetečení nebo podtečení. |
NE |
OF=0 |
Při zacházení jako s celočíselnou operací, poslední operace nezpůsobila přetečení ani podtečení. |
Podmínky lze použít také k porovnání dvou hodnot. Instrukce cmp porovnává dva operandy a potom nastaví příznaky tak, jako by odečítá jeden operand od druhého. Následující podmínky lze použít ke kontrole výsledku cmphodnota1, hodnota2.
Název podmínky | Vlajky | Význam po operaci CMP. |
---|---|---|
E |
ZF=1 |
hodnota1 == hodnota2. |
SEVEROVÝCHOD |
ZF=0 |
hodnota1 != hodnota2. |
GE NL | SF=OF |
hodnota1>= hodnota2. Hodnoty se považují za podepsaná celá čísla. |
LE NG | ZF=1 nebo SF!=OF |
hodnota1<= hodnota2. Hodnoty jsou považovány za celá čísla se znaménkem. |
G NLE | ZF=0 a SF=OF |
hodnota1>hodnota2. Hodnoty se považují za podepsaná celá čísla. |
L NGE | SF!=OF |
hodnota1<hodnota2. Hodnoty se považují za celá čísla se znaménkem. |
AE NB | CF=0 |
hodnota1>= hodnota2. Hodnoty se považují za celá čísla bez znaménka. |
BE NA | CF=1 nebo ZF=1 |
hodnota1<= hodnota2. Hodnoty se považují za celá čísla bez znaménka. |
A NBE | CF=0 a ZF=0 |
hodnota1>hodnota2. Hodnoty se považují za celá čísla bez znaménka. |
B NAE | CF=1 |
hodnota1<hodnota2. Hodnoty se považují za celá čísla bez znaménka. |
Podmínky se obvykle používají k jednání podle výsledku instrukcí cmp nebo test. Například
cmp eax, 5
jz equal
porovná registr eax s číslem 5 výpočtem výrazu (eax - 5) a nastaví příznaky podle výsledku. Pokud je výsledek odčítání nula, nastaví se příznak zr a podmínka jz bude pravdivá, takže dojde k provedení skoku.
Datové typy
bajt: 8 bitů
slovo: 16 bitů
dword: 32 bitů
qword: 64 bitů (zahrnuje dvojité plovoucí čárky)
tword: 80 bitů (zahrnuje rozšířené double s plovoucí desetinou čárkou)
oword: 128 bitů
Zápis
Následující tabulka uvádí zápis použitý k popisu instrukcí jazyka sestavení.
Zápis | Význam |
---|---|
r, r1, r2... |
Registruje |
m |
Adresa paměti (další informace najdete v následující části Adresovací režimy.) |
#n |
Okamžitá konstanta |
r/m |
Registr nebo paměť |
r/#n |
Registr nebo okamžitá konstanta |
r/m/#n |
Registrace, paměť nebo okamžitá konstanta |
cc |
Kód podmínky uvedený v předchozí části Podmínky. |
T |
"B", "W" nebo "D" (bajt, slovo nebo dvojité slovo) |
accT |
Velikost T akumulátoru: al, pokud T = "B", ax, pokud T = "W" nebo eax, pokud T = "D" |
Režimy adresování
Existují různé režimy adresování, ale všechny mají tvar T ptr [výraz], kde T je datový typ (viz předchozí část Datové typy) a výraz je výraz zahrnující konstanty a registry.
Zápis pro většinu režimů lze odvodit bez velkého problému. Například BYTE PTR [esi+edx*8+3] znamená "vezměte hodnotu registru esi, přičtěte k ní osmkrát hodnotu registru edx, přidejte tři, a potom přistupte k bajtu na výsledné adrese."
Proudové zpracování
Pentium je dvouvláknové, což znamená, že může provádět až dvě akce během jednoho taktu. Pravidla, kdy je však schopná provádět dvě akce najednou (označované jako párování), jsou ale velmi složitá.
Vzhledem k tomu, že x86 je procesor CISC, nemusíte se starat o sloty zpoždění skoku.
Synchronizovaný přístup k paměti
Načítací, upravovací a ukládací instrukce mohou získat předponu zámkové , která modifikuje instrukci následujícím způsobem:
Před vydáním instrukce procesor vyprázdní všechny čekající operace paměti, aby se zajistila soulad. Všechny předsběry dat jsou zrušeny.
Při vydávání instrukcí bude mít procesor výhradní přístup ke sběrnici. Tím se zajistí atomicita operace načtení, modifikace a uložení.
Instrukce xchg automaticky dodržuje předchozí pravidla vždy, když vymění hodnotu s pamětí.
Všechny ostatní pokyny jsou výchozí pro neblokování.
Predikce skoku
Bezpodmínečné skoky se očekává, že budou provedeny.
Podmíněné skoky se předpovídají, zda budou provedeny nebo ne, závisí na tom, zda byly provedeny při poslední exekuci. Mezipaměť pro záznam historie skoků je omezená velikostí.
Pokud procesor nemá záznam o tom, jestli byl podmíněný skok proveden nebo nebyl proveden při posledním spuštění, předpovídá, že zpětné podmíněné skoky jsou provedené a dopředné podmíněné skoky nejsou provedené.
Zarovnání
Procesor x86 automaticky opraví nezarovnaný přístup k paměti za cenu zhoršení výkonu. Není vyvolána žádná výjimka.
Přístup k paměti se považuje za zarovnaný, pokud je adresa celočíselnou násobkem velikosti objektu. Například všechny přístupy BYTE jsou zarovnané (vše je celé číslo násobku 1), wordové přístupy k sudým adresám jsou zarovnané a adresy DWORD musí být násobkem 4, aby bylo možné zarovnat.
zámek předpona by se neměla používat pro nezarovnané přístupy do paměti.
Viz také
architektura x64