Sdílet prostřednictvím


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:

  1. 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.

  2. 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

Wikipedie X86–64