x86-architectuur
De Intel x86-processor maakt gebruik van een complexe CISC-architectuur (instructiesetcomputer), wat betekent dat er een bescheiden aantal speciale registers is in plaats van grote hoeveelheden algemene registers. Het betekent ook dat complexe speciale instructies predomineren.
De x86-processor traceert zijn erfgoed ten minste zo ver terug als de 8-bits Intel 8080-processor. Veel eigenaardigheden in de x86-instructieset zijn te wijten aan de achterwaartse compatibiliteit met die processor (en met de Zilog Z-80-variant).
Microsoft Win32 maakt gebruik van de x86-processor in 32-bits flat mode. Deze documentatie richt zich alleen op de platte modus.
Registers
De x86-architectuur bestaat uit de volgende ongeprivilegieerde registers voor gehele getallen.
eax |
Accumulator |
ebx |
Basisregister |
ecx |
Tellerregister |
edx |
Gegevensregister : kan worden gebruikt voor I/O-poorttoegang en rekenkundige functies |
esi |
Indexregister van de bron |
edi- |
Bestemmingsindexregister |
ebp- |
Basispointerregister |
esp |
Stackpointer |
Alle gehele getallenregisters zijn 32 bits. Veel daarvan hebben echter 16-bit of 8-bit subregisters.
ax |
Lage 16 bits van eax |
bx |
Lage 16 bits van ebx- |
cx |
Lage 16 bits van ecx- |
dx |
Lage 16 bits van edx- |
si |
Lage 16 bits van esi- |
di |
Lage 16 bits van edi- |
|
Lage 16 bits van ebp- |
sp |
Lage 16 bits van esp |
al |
Lage 8 bits van eax- |
ah |
De hoogste 8 bits van ax |
bl |
Laag 8 bits van ebx |
bh |
Bovenste 8 bits van bx |
cl |
Lage 8 bits van ecx- |
ch |
Hoge 8 bits van cx- |
dl |
Lage 8 bits van edx- |
dh |
De hoogste 8 bits van register dx |
Het werken met een subregister is alleen van invloed op het subregister en niet op de onderdelen buiten het subregister. Als u bijvoorbeeld opslaat in het ax-register, blijven de hoge 16 bits van het eax-register ongewijzigd.
Wanneer u de (Evaluate Expression)-opdracht gebruikt, moeten registers worden voorafgegaan door een "at"-teken (@). U moet bijvoorbeeld gebruiken? @ax in plaats van ? ax. Dit zorgt ervoor dat het foutopsporingsprogramma ax herkent als een register in plaats van een symbool.
De opdracht (@) is echter niet vereist in de r (registers) opdracht. Zo wordt r ax=5 altijd correct geïnterpreteerd.
Twee andere registers zijn belangrijk voor de huidige status van de processor.
eip |
instructie aanwijzer |
vlaggen |
Vlaggen |
De instructiepointer is het adres van de instructie die wordt uitgevoerd.
Het vlagregister is een verzameling single-bit vlaggen. Veel instructies wijzigen de vlaggen om het resultaat van de instructie te beschrijven. Deze vlaggen kunnen vervolgens worden getest door springinstructies met een voorwaarde. Zie x86-vlaggen voor meer informatie.
Oproepconventies
De x86-architectuur heeft verschillende aanroepende conventies. Gelukkig volgen ze allemaal dezelfde register- en functieterugkeerregels.
Functies moeten alle registers behouden, met uitzondering van eax-, ecxen edx-, die kunnen worden gewijzigd in een functie-aanroep en esp, die moeten worden bijgewerkt volgens de aanroepconventie.
De eax- register ontvangt functiewaarden als het resultaat 32 bits of kleiner is. Als het resultaat 64 bits is, wordt het resultaat opgeslagen in de edx:eax paar.
Hier volgt een lijst met aanroepende conventies die worden gebruikt in de x86-architectuur:
Win32 (__stdcall)
Functieparameters worden op de stack geplaatst, van rechts naar links gepusht, en de aangeroepen functie schoont de stack.
Systeemeigen C++-methode-aanroep (ook wel bekend als thiscall)
Functieparameters worden doorgegeven aan de stack, van rechts naar links gepusht, de 'this' pointer wordt doorgegeven in het ecx- register en de opgeroepene schoont de stack op.
COM (__stdcall voor aanroepen van C++-methoden)
Functieparameters worden op de stack geplaatst, van rechts naar links, vervolgens wordt de 'this'-pointer op de stack geplaatst en vervolgens wordt de functie aangeroepen. De aangeroepene schoont de stapel.
__fastcall
De eerste twee DWORD-of-kleinere argumenten worden doorgegeven in de registers ecx en edx. De resterende parameters worden doorgegeven aan de stack en van rechts naar links gepusht. De aangeroepene leegt de stapel.
__cdecl
Functieparameters worden op de stack geplaatst, van rechts naar links gepusht, en de aanroeper maakt de stack schoon. De __cdecl oproepconventie wordt gebruikt voor alle functies met parameters voor variabele lengte.
Weergave van registers en vlaggen in Debugger
Hier volgt een voorbeeld van een registerweergave voor foutopsporing:
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
In debugging in de gebruikersmodus kunt u de iopl en de volledige laatste regel van de debugger negeren.
x86-vlaggen
In het voorgaande voorbeeld zijn de codes van twee letters aan het einde van de tweede regel vlaggen. Dit zijn enkelvoudige registers en hebben verschillende toepassingen.
De volgende tabel bevat de x86-vlaggen:
Vlagcode | Vlagnaam | Waarde | Vlagstatus | Beschrijving |
---|---|---|---|---|
van | Overloop-vlag | 0 1 | nvov- | Geen overloop - Overloop |
df | Richtingsvlag | 0 1 | updn | Richting omhoog - Richting omlaag |
als | Interrupt-vlag | 0 1 | diei | Onderbrekingen uitgeschakeld - Onderbrekingen ingeschakeld |
sf | Vlag ondertekenen | 0 1 | plng | Positief (of nul) - Negatief |
zf | Nulvlag | 0 1 | nzzr | Nonzero - Nul |
af | Hulpdraagvlag | 0 1 | naac- | Geen hulp dragen - Hulp dragen |
pf | Pariteitsvlag | 0 1 | pepo | Pariteit oneven - Pariteit even |
cf | Vlag dragen | 0 1 | nccy | Geen dragen - Dragen |
tf - | Trapvlag | Als tf- gelijk is aan 1, genereert de processor een STATUS_SINGLE_STEP uitzondering na de uitvoering van één instructie. Deze vlag wordt gebruikt door een foutopsporingsprogramma voor het implementeren van tracering met één stap. Het mag niet worden gebruikt door andere toepassingen. | ||
iopl | I/O-bevoegdheidsniveau | I/O-bevoegdheidsniveau Dit is een twee-bits geheel getal, met waarden tussen nul en 3. Het wordt gebruikt door het besturingssysteem om de toegang tot hardware te beheren. Het mag niet worden gebruikt door toepassingen. |
Wanneer registers worden weergegeven als gevolg van een opdracht in het venster met foutopsporingsopdrachten, wordt de status van de -vlag weergegeven. Als u echter een vlag wilt wijzigen met behulp van de opdracht r (Registers), moet u ernaar verwijzen door de vlagcode.
In het venster Registers van WinDbg wordt de vlagcode gebruikt om vlaggen weer te geven of te wijzigen. De vlagstatus wordt niet ondersteund.
Hier volgt een voorbeeld. In de voorgaande weergave van het register wordt de vlagstatus ng- weergegeven. Dit betekent dat de tekenvlag momenteel is ingesteld op 1. Gebruik de volgende opdracht om dit te wijzigen:
r sf=0
Hiermee stelt u de tekenvlag in op nul. Als u een andere registratieweergave uitvoert, wordt de ng-statuscode niet weergegeven. In plaats daarvan wordt de pl statuscode weergegeven.
De tekenvlag, Zero Flag en Carry Flag zijn de meestgebruikte vlaggen.
Voorwaarden
Een voorwaarde beschrijft de status van een of meer vlaggen. Alle voorwaardelijke bewerkingen op x86 worden uitgedrukt in voorwaarden.
De assemblyer gebruikt een afkorting van een of twee letters om een voorwaarde weer te geven. Een voorwaarde kan worden vertegenwoordigd door meerdere afkortingen. AE ('boven of gelijk aan') is bijvoorbeeld dezelfde voorwaarde als NB ('niet hieronder'). De volgende tabel bevat enkele algemene voorwaarden en hun betekenis.
Voorwaardenaam | Vlaggen | Betekenis |
---|---|---|
Z |
ZF=1 |
Resultaat van de laatste bewerking was nul. |
NZ |
ZF=0 |
Het resultaat van de laatste bewerking was niet nul. |
C |
CF=1 |
Laatste bewerking vereist een draag- of leenbewerking. (Voor niet-ondertekende gehele getallen geeft dit de overloop aan.) |
NC |
CF=0 |
Voor de laatste bewerking was geen dragen of lenen vereist. (Voor niet-ondertekende gehele getallen geeft dit de overloop aan.) |
S |
SF=1 |
Het resultaat van de laatste bewerking heeft de hoge bitset. |
NS |
SF=0 |
Het resultaat van de laatste bewerking heeft zijn hoogste bit gewist. |
O |
VAN=1 |
Wanneer de bewerking wordt behandeld als een ondertekend geheel getal, heeft de laatste bewerking een overloop of onderloop veroorzaakt. |
NEE |
OF=0 |
Bij behandeling als gepoolde integerbewerking heeft de laatste bewerking geen overflow of underflow veroorzaakt. |
Voorwaarden kunnen ook worden gebruikt om twee waarden te vergelijken. De cmp instructie vergelijkt de twee operanden en stelt vervolgens vlaggen in alsof de ene operand van de andere wordt afgetrokken. De volgende voorwaarden kunnen worden gebruikt om het resultaat van cmpwaarde1, waarde2te controleren.
Voorwaardenaam | Vlaggen | De betekenis na een CMP-bewerking. |
---|---|---|
E |
ZF=1 |
waarde1 == waarde2. |
NE |
ZF=0 |
waarde1 != waarde2. |
GE NL | SF=OF |
waarde1>= waarde2. Waarden worden behandeld als ondertekende gehele getallen. |
LE NG | ZF=1 of SF!=OF |
waarde1<= waarde2. Waarden worden behandeld als ondertekende gehele getallen. |
G NLE | ZF=0 en SF=OF |
waarde1>waarde2. Waarden worden behandeld als ondertekende gehele getallen. |
L NGE | SF!=OF |
waarde1<waarde2. Waarden worden behandeld als ondertekende gehele getallen. |
AE NB | CF=0 |
waarde1>= waarde2. Waarden worden behandeld als niet-ondertekende gehele getallen. |
BE NA | CF=1 of ZF=1 |
waarde1<= waarde2. Waarden worden behandeld als niet-ondertekende gehele getallen. |
Een NBE | CF=0 en ZF=0 |
waarde1>waarde2. Waarden worden behandeld als niet-ondertekende gehele getallen. |
B NAE | CF=1 |
waarde1<waarde2. Waarden worden behandeld als niet-ondertekende gehele getallen. |
Condities worden meestal gebruikt om te reageren op het resultaat van een cmp- of test-instructie. Bijvoorbeeld
cmp eax, 5
jz equal
vergelijkt de eax- register met het getal 5 door de expressie (eax - 5) te berekenen en vlaggen in te stellen op basis van het resultaat. Als het resultaat van de aftrekking nul is, wordt de vlag zr ingesteld en wordt de jz voorwaarde waar, zodat de sprong wordt genomen.
Gegevenstypen
byte: 8 bits
woord: 16 bits
dword: 32 bits
qword: 64 bits (inclusief dubbele drijvende komma)
tweede: 80 bits (inclusief dubbele drijvende komma)
oword: 128 bits
Notatie
De volgende tabel geeft de notatie aan die wordt gebruikt om de taalinstructies voor assembly's te beschrijven.
Notatie | Betekenis |
---|---|
r, r1, r2... |
Registers |
m |
Geheugenadres (zie het gedeelte Adresseringsmodi voor meer informatie.) |
#n |
Onmiddellijke constante |
r/m |
Registreren of geheugen |
r/#n |
Registreren of onmiddellijke constante |
r/m/#n |
Register, geheugen of onmiddellijke constante |
CC- |
Een voorwaardecode die wordt vermeld in de voorgaande sectie Voorwaarden. |
T- |
"B", "W" of "D" (byte, woord of dword) |
accT- |
Grootte T van de accumulator: al indien T = "B", ax indien T = "W", of eax indien T = "D" |
Adresseringsmodi
Er zijn verschillende adresseringsmodi, maar ze hebben allemaal de vorm T ptr [expr], waarbij T- een bepaald gegevenstype is (zie de voorgaande sectie Gegevenstypen) en expr- een expressie is met constanten en registers.
De notatie voor de meeste modi kan zonder veel moeite worden afgeleid. Bijvoorbeeld: BYTE PTR [esi+edx*8+3] betekent 'neem de waarde van het esi--register, voeg er acht keer de waarde van het edx--register aan toe, voeg drie toe en open vervolgens de byte op het resulterende adres.'
Pipelining
De Pentium is dual-issue, wat betekent dat het tot twee acties in één kloktik kan uitvoeren. De regels voor wanneer twee acties tegelijkertijd kunnen worden uitgevoerd (bekend als koppelen) zijn echter erg ingewikkeld.
Omdat x86 een CISC-processor is, hoeft u zich geen zorgen te maken over jump delay slots.
Gesynchroniseerde geheugentoegang
Instructies voor laden, wijzigen en opslaan kunnen een lock voorvoegsel hebben, waarmee de instructie als volgt wordt aangepast:
Voordat de instructie wordt uitgegeven, worden alle in behandeling zijnde geheugenbewerkingen door de CPU leeggemaakt om de coherentie te garanderen. Alle gegevens-prefetches worden geannuleerd.
Tijdens het uitgeven van de instructie heeft de CPU exclusieve toegang tot de bus. Dit zorgt voor de atomiciteit van de bewerking laden/wijzigen/opslaan.
De xchg-instructie voldoet automatisch aan de vorige regels wanneer deze een waarde met geheugen uitwisselt.
Alle andere instructies worden standaard niet vergrendeld.
Sprongvoorspelling
Onvoorwaardelijke sprongen worden voorspeld te worden genomen.
Er wordt voorspeld of voorwaardelijke sprongen wel of niet zullen worden genomen, afhankelijk van of ze de laatste keer wel of niet werden genomen toen ze werden uitgevoerd. De cache voor opnamespronggeschiedenis is beperkt in grootte.
Als de CPU geen record heeft of de voorwaardelijke sprong is genomen of niet de laatste keer dat deze werd uitgevoerd, voorspelt het voorwaardelijke sprongen naar achteren zoals genomen en vooruit voorwaardelijke sprongen zoals niet genomen.
Uitlijning
De x86-processor corrigeert automatisch niet-uitgelijnde geheugentoegang, met een prestatiestraf. Er wordt geen uitzondering gegenereerd.
Een geheugentoegang wordt beschouwd als uitgelijnd als het adres een geheel veelvoud van de objectgrootte is. Alle BYTE-toegangen worden bijvoorbeeld uitgelijnd (alles is een geheel getal van 1), WORD-toegang tot even adressen wordt uitgelijnd en DWORD-adressen moeten een veelvoud van 4 zijn om te worden uitgelijnd.
Het lock-voorvoegsel mag niet worden gebruikt voor niet-uitgelijnde geheugentoegangen.