Intel x86 Assembly Language & Microarchitecture
Registrieren Sie die Grundlagen
Suche…
16-Bit-Register
Bei der Definition des ursprünglichen 8086 durch Intel handelte es sich um einen 16-Bit-Prozessor mit einem 20-Bit-Adressbus (siehe unten). Sie definierten 8 allgemeine 16-Bit-Register - gaben ihnen jedoch bestimmte Rollen für bestimmte Anweisungen:
-
AXDas Akkumulatorregister.
Viele Opcodes nahmen dieses Register entweder an oder waren schneller, wenn es angegeben wurde. -
DXDas Datenregister.
Dies wurde manchmal als die hohen 16 Bits eines 32-Bit-Werts mitAXkombiniert, beispielsweise als Ergebnis einer Multiplikation. -
CXDas Count-Register.
Dies wurde in einer Reihe schleifenorientierter Anweisungen als impliziter Zähler für diese Schleifen verwendet - zum BeispielLOOPNE(Schleife, falls nicht gleich) undREP(wiederholtes Verschieben / Vergleichen). -
BXDas Basisregister.
Dies kann verwendet werden, um die Basis einer Struktur im Speicher zu indizieren - keines der oben genannten Register könnte zum direkten Indexieren in den Speicher verwendet werden. -
SIDas Quellindexregister.
Dies war der implizite Quellenindex für bestimmte Verschiebungs- und Vergleichsoperationen im Speicher. -
DIDas Zielindexregister.
Dies war der implizite Zielindex im Speicher für bestimmte Verschiebungs- und Vergleichsoperationen. -
SPDas Stack-Pointer-Register.
Dies ist das am wenigsten generelle Register im Set! Es zeigte auf die aktuelle Position im Stack, die explizit fürPUSHundPOPOperationen verwendet wurde, implizit fürCALLundRETmit Unterprogrammen und VERY implizit während Interrupts. Daher war die Verwendung für alles andere gefährlich für Ihr Programm! -
BPDas Basiszeigerregister.
Wenn Unterprogramme andere Unterprogramme aufrufen, enthält der Stapel mehrere "Stapelrahmen".BPkönnte zum Speichern des aktuellen Stack-Frames verwendet werden. Wenn eine neue Subroutine aufgerufen wurde, konnte sie auf dem Stack gespeichert, der neue Stack-Frame erstellt und verwendet werden. Bei Rückkehr aus der inneren Subroutine konnte der alte Stack-Frame-Wert wiederhergestellt werden .
Anmerkungen:
Die ersten drei Register können nicht zum Indizieren in den Speicher verwendet werden.
BX,SIundDIindexieren standardmäßig in das aktuelle Datensegment (siehe unten).MOV AX, [BX+5] ; Point into Data Segment MOV AX, ES:[DI+5] ; Override into Extra SegmentWenn
DIin Speicher-zu-Speicher-Operationen wieMOVSundCMPS, wird ausschließlich das Extra-Segment verwendet (siehe unten). Dies kann nicht überschrieben werden.SPundBPverwenden standardmäßig das Stapelsegment (siehe unten).
32-Bit-Register
Als Intel den 80386 produzierte, wurde ein Upgrade von einem 16-Bit-Prozessor auf einen 32-Bit-Prozessor durchgeführt. 32-Bit-Verarbeitung bedeutet zwei Dinge: Sowohl die zu manipulierenden Daten waren 32-Bit als auch die Speicheradressen, auf die zugegriffen wurde, waren 32-Bit. Um dies zu erreichen, aber immer noch kompatibel zu ihren früheren Prozessoren, haben sie völlig neue Modi für den Prozessor eingeführt. Es war entweder im 16-Bit-Modus oder im 32-Bit-Modus - aber Sie können diesen Modus Anweisungsweise für entweder Daten, Adressierung oder beides außer Kraft setzen!
Zunächst mussten 32-Bit-Register definiert werden. Sie haben dies getan, indem sie einfach die vorhandenen acht von 16 Bit auf 32 Bit erweitert und ihnen "erweiterte" Namen mit einem E Präfix gegeben haben: EAX , EBX , ECX , EDX , ESI , EDI , EBP und ESP . Die unteren 16 Bits dieser Register waren die gleichen wie zuvor, aber die oberen Hälften der Register standen für 32-Bit-Operationen wie ADD und CMP . Die oberen Hälften waren nicht wie bei den 8-Bit-Registern separat zugänglich.
Der Prozessor musste über einen separaten 16-Bit- und 32-Bit-Modus verfügen, da Intel für viele Operationen die gleichen Opcodes verwendete: CMP AX,DX im 16-Bit-Modus und CMP EAX,EDX im 32-Bit-Modus hatten genau dieselben Opcodes ! Dies bedeutet, dass derselbe Code NICHT in beiden Modi ausgeführt werden kann:
Der Opcode für "Sofort in
AX" lautet0xB8, gefolgt von zwei Bytes des unmittelbaren Werts:0xB8 0x12 0x34
Der Opcode für "Sofort in
EAX" lautet0xB8, gefolgt von vier Bytes des unmittelbaren Werts:0xB8 0x12 0x34 0x56 0x78
Der Assember muss also wissen, in welchem Modus sich der Prozessor befindet, wenn er den Code ausführt, damit er weiß, dass er die richtige Anzahl von Bytes ausgibt.
8-Bit-Register
Bei den ersten vier 16-Bit-Registern kann auf die Bytes der oberen und unteren Hälfte direkt als eigene Register zugegriffen werden:
-
AHundALsind die oberen und unteren Hälften desAXRegisters. -
BHundBLsind die High- und Low-Hälfte desBXRegisters. -
CHundCLsind die High- und Low-Hälfte desCXRegisters. -
DHundDLsind die High- und Low-Hälfte desDXRegisters.
Beachten Sie, dass dies bedeutet, dass durch das Ändern von AH oder AL auch AX sofort geändert wird! Beachten Sie auch, dass jede Operation in einem 8-Bit-Register keinen Einfluss auf den "Partner" haben kann. 0xFF AL so hochgezählt wird, dass es von 0xFF zu 0x00 0xFF , würde sich AH nicht ändern.
64-Bit-Register haben auch 8-Bit-Versionen, die ihre niedrigeren Bytes darstellen:
-
SILfürRSI -
DILfürRDI -
BPLfürRBP -
SPLfürRSP
Gleiches gilt für die Register R8 bis R15 : Ihre jeweiligen unteren Byte-Teile werden als R8B R15B .
Segmentregister
Segmentierung
Als Intel den ursprünglichen 8086 entwarf, gab es bereits eine Reihe von 8-Bit-Prozessoren, die über 16-Bit-Fähigkeiten verfügten. Sie wollten jedoch einen echten 16-Bit-Prozessor herstellen. Sie wollten auch etwas Besseres und Stärkeres produzieren als das, was es bereits gibt, und deshalb auf mehr als 65.536 Bytes an Speicher zugreifen, die von 16-Bit-Adressierungsregistern impliziert werden.
Ursprüngliche Segmentregister
Sie implementierten die Idee von "Segmenten" - einem 64-Kilobyte-Speicherblock, der von den 16-Bit-Adressregistern indiziert wird - und könnte neu adressiert werden, um verschiedene Bereiche des Gesamtspeichers zu adressieren. Um diese Segmentbasen zu halten, wurden Segmentregister eingeschlossen:
-
CSDas Codesegmentregister.
Dies enthält den Abschnitt des Codes, der gerade ausgeführt wird, indiziert durch das impliziteIPRegister (Instruction Pointer). -
DSDas Datensegmentregister.
Dies enthält das Standardsegment für Daten, die vom Programm bearbeitet werden. -
ESDas Zusatzsegmentregister.
Dies enthält ein zweites Datensegment für gleichzeitige Datenoperationen über den gesamten Speicher. -
SSDas Stack-Segmentregister.
Dies enthält das Speichersegment, das den aktuellen Stapel enthält.
Segmentgröße
Die Segmentregister können beliebig groß sein, aber da sie 16 Bit breit sind, ist es leicht, mit den anderen Registern zusammenzuarbeiten. Die nächste Frage war: Sollten sich die Segmente überlappen und wenn ja, wie viel? Die Antwort auf diese Frage würde die gesamte Speichergröße bestimmen, auf die zugegriffen werden könnte.
Wenn es überhaupt keine Überlappung gab, dann wäre der Adressraum 32 Bit - 4 Gigabyte - eine damals völlig unbekannte Größe! Eine "natürliche" Überlappung von 8 Bit würde einen 24-Bit-Adressraum oder 16 Megabyte erzeugen. Am Ende entschied sich Intel dafür, vier weitere Adress-Pins auf dem Prozessor zu speichern, indem der Adressraum mit einer Überlappung von 12 Bit auf 1 Megabyte erhöht wurde - dies war für die Zeit ausreichend groß!
Weitere Segmentregister!
Als Intel den 80386 entwarf, erkannten sie, dass die vorhandene Gruppe von 4 Segmentregistern nicht ausreichte, um die Komplexität der Programme zu unterstützen, die sie unterstützen wollten. Also fügten sie zwei weitere hinzu:
-
FSDas Fernsegmentregister -
GSDas globale Segmentregister
Diese neuen Segmentregister hatten keine durch den Prozessor erzwungenen Verwendungen: Sie waren lediglich für das, was der Programmierer wollte, verfügbar.
Einige sagen, dass die Namen gewählt wurden, um einfach das Thema
C,D,Edes bestehenden Sets fortzusetzen ...
64-Bit-Register
AMD ist ein Prozessorhersteller, der das Design des 80386 von Intel für die Herstellung kompatibler, aber konkurrierender Versionen lizenziert hatte. Sie haben interne Änderungen am Design vorgenommen, um den Durchsatz oder andere Verbesserungen des Designs zu verbessern, während sie dennoch die gleichen Programme ausführen können.
Für Intel gab es eine 64-Bit-Erweiterung für das 32-Bit-Design von Intel und der erste 64-Bit-Chip, auf dem noch 32-Bit-x86-Code ausgeführt werden konnte. Intel folgte dem Design von AMD in seinen Versionen der 64-Bit-Architektur.
Das 64-Bit-Design hat eine Reihe von Änderungen am Registersatz vorgenommen und ist dennoch abwärtskompatibel:
- Die vorhandenen Universalregister wurden auf 64 Bit erweitert und mit einem
RPräfix bezeichnet:RAX,RBX,RCX,RDX,RSI,RDI,RBPundRSP.Die unteren Hälften dieser Register waren wieder dieselben
EPräfix-Register wie zuvor, und auf die oberen Hälften konnte nicht unabhängig zugegriffen werden. - 8 weitere 64-Bit-Register wurden hinzugefügt und nicht benannt, sondern lediglich nummeriert:
R8,R9,R10,R11,R12,R13,R14undR15.- Die niedrige 32-Bit-Hälfte dieser Register besteht aus
R8DbisR15D(D für DWORD wie üblich). - Auf die untersten 16 Bits dieser Register kann zugegriffen werden, indem ein
Wan den RegisternamenR8W:R8WbisR15W.
- Die niedrige 32-Bit-Hälfte dieser Register besteht aus
- Auf die untersten 8 Bits aller 16 Register kann jetzt zugegriffen werden:
- Die traditionellen
AL,BL,CLundDL; - Die niedrigen Bytes der (traditionellen) Zeigerregister:
SIL,DIL,BPLundSPL; - Und die niedrigen Bytes der 8 neuen Register:
R8BbisR15B. - Auf
AH,BH,CHundDHjedoch nicht in BefehlenDHwerden, die ein REX-Präfix verwenden (für 64-Bit-Operandengröße oder für den Zugriff auf R8-R15 oder für den Zugriff aufSIL,DIL,BPLoderSPL). Bei einem REX-Präfix bedeutet das Maschinencode-Bitmuster, das früherAHbedeutete,SPLusw. Siehe Tabelle 3-1 des Intels Anweisungshandbuchs (Band 2).
- Die traditionellen
Beim Schreiben in ein 32-Bit-Register werden immer die oberen 32 Bit des Registers mit voller Breite auf Null gesetzt, im Gegensatz zum Schreiben in ein 8- oder 16-Bit-Register (das mit dem alten Wert zusammengeführt wird, was eine zusätzliche Abhängigkeit für die Ausführung außerhalb der Reihenfolge darstellt ).
Flaggen registrieren
Wenn die x86 Arithmetic Logic Unit (ALU) Operationen wie NOT und ADD , werden die Ergebnisse dieser Operationen ("Null", "Überlauf", "Negativ") in einem speziellen 16-Bit- FLAGS Register FLAGS . 32-Bit-Prozessoren haben dies auf 32 Bit aufgerüstet und EFLAGS , während 64-Bit-Prozessoren auf 64 Bit aufgerüstet und RFLAGS .
Bedingungscodes
Aber unabhängig vom Namen ist das Register nicht direkt zugänglich (abgesehen von ein paar Anweisungen - siehe unten). Stattdessen wird in bestimmten Anweisungen auf einzelne Flags verwiesen, z. B. bedingter Sprung oder bedingter Satz ( Jcc und SETcc wobei cc "Bedingungscode" bedeutet und auf die folgende Tabelle verweist:
| Bedingungscode | Name | Definition |
|---|---|---|
E , Z | Gleich Null | ZF == 1 |
NE , NZ | Nicht gleich, nicht Null | ZF == 0 |
O | Überlauf | OF == 1 |
NO | Kein Überlauf | OF == 0 |
S | Unterzeichnet | SF == 1 |
NS | Nicht unterschrieben | SF == 0 |
P | Parität | PF == 1 |
NP | Keine Parität | PF == 0 |
| -------------- | ---- | ---------- |
C , B , NAE | Tragen Sie unten, nicht oben oder gleich | CF = 1 |
NC , NB , AE | Kein Carry, nicht darunter, oben oder gleich | CF == 0 |
A , NBE | Oben, nicht darunter oder gleich | CF == 0 und ZF == 0 |
NA , BE | Nicht über, unter oder gleich | CF == 1 oder ZF == 1 |
| --------------- | ---- | ---------- |
GE , NL | Größer oder gleich, nicht weniger | SF == OF |
NGE , L | Nicht größer oder gleich, weniger | SF ! = OF |
G , NLE | Größer, nicht weniger oder gleich | ZF == 0 und SF == OF |
NG , LE | Nicht größer, kleiner oder gleich | ZF == 1 oder SF ! = OF |
In 16 Bits ist das Subtrahieren von 1 von 0 entweder 65,535 oder -1 je nachdem, ob eine vorzeichenlose oder vorzeichenbehaftete Arithmetik verwendet wird. Das Ziel enthält jedoch 0xFFFF . Nur durch die Interpretation der Bedingungscodes ist die Bedeutung klar. Noch 0x8000 ist es, wenn 1 von 0x8000 subtrahiert 0x8000 : In vorzeichenloser Arithmetik ändert sich lediglich 32,768 in 32,767 ; In der signierten Arithmetik ändert sich -32,768 in 32,767 - ein viel bemerkenswerterer Überlauf!
Die Bedingungscodes sind in der Tabelle in drei Blöcke gruppiert: vorzeichenlos, vorzeichenlos und vorzeichenbehaftet. Die Benennung innerhalb der letzten beiden Blöcke verwendet "Vor" und "Unter" für unsigniert und "Größer" oder "Weniger" für Vorzeichen. JB wäre also "Jump if Below" (unsigned), während JL "Jump if Less" (signiert) wäre.
FLAGS Zugriff auf FLAGS
Die oben genannten Bedingungscodes sind nützlich, um vordefinierte Konzepte zu interpretieren, die eigentlichen Flag-Bits stehen jedoch auch direkt mit den folgenden beiden Anweisungen zur Verfügung:
-
LAHFAHRegister mit Flags laden -
SAHFAHRegister in FlagsSAHF
Mit diesen Anweisungen werden nur bestimmte Flags kopiert. Das gesamte FLAGS / EFLAGS / RFLAGS Register kann auf dem Stack gespeichert oder wiederhergestellt werden:
-
PUSHF/POPF16-Bit-FLAGSauf / aus dem StackPUSHF/POPF -
PUSHFD/POPFD32-Bit-EFLAGSauf / aus dem StackPUSHFD/POPFD -
PUSHFQ/POPFQPush / Pop-64-Bit-RFLAGS/ auf den Stack
Beachten Sie, dass Interrupts die aktuelle [R/E]FLAGS Registrierung automatisch speichern und wiederherstellen.
Andere Flaggen
Neben den oben beschriebenen ALU-Flags definiert das FLAGS Register weitere Flags für den FLAGS :
-
IFdas Interrupt-Flag.
Dies wird mit demSTIBefehl festgelegt, um Interrupts global zu aktivieren, und mit demCLIBefehl gelöscht, um Interrupts global zu deaktivieren. -
DFDie Richtungsflagge.
Speicher-zu-Speicher-Operationen wieCMPSundMOVS(zum Vergleichen und Verschieben zwischen Speicherplätzen)MOVSoder verringern automatisch die Indexregister als Teil der Anweisung. DasDFFlag gibt an, welches geschieht: Wenn mit derCLDAnweisung gelöscht, werden sie inkrementiert. Wenn mit derSTDAnweisung festgelegt, werden sie dekrementiert. -
TFDie Fallenflagge. Dies ist ein Debug-Flag. Durch Setzen dieser Option wird der Prozessor in den Modus "Einzelschritt" versetzt: Nach Ausführung jeder Anweisung wird der "Einzelschritt-Interrupt-Handler" aufgerufen, von dem erwartet wird, dass er von einem Debugger verarbeitet wird. Es gibt keine Anweisungen zum Setzen oder Löschen dieses Flags: Sie müssen das Bit bearbeiten, während es sich im Speicher befindet.
80286 Flaggen
Um die neuen Multitasking-Funktionen des 80286 zu unterstützen, fügte Intel dem FLAGS Register zusätzliche Flags hinzu:
-
IOPLDie E / A-IOPL.
Zum Schutz von Multitasking-Code benötigten einige Aufgaben Berechtigungen für den Zugriff auf E / A-Ports, während andere für den Zugriff auf sie gesperrt werden mussten. Intel führte eine Privilege-Skala mit vier Stufen ein, wobei002 die höchste Priorität und112 die niedrigste Priorität hatte. WennIOPLunter der aktuellenIOPLlag, würde jeder Versuch, auf E / A-Ports zuzugreifen oder Interrupts zu aktivieren oder zu deaktivieren, stattdessen eine allgemeine Schutzverletzung verursachen. -
NTFlag für geschachtelte Aufgaben
Dieses Flag wurde gesetzt, wenn eine TaskCALLandere TaskCALL, was zu einem Kontextwechsel führte. Das gesetzte Flag wies den Prozessor an, einen Kontextwechsel durchzuführen, wenn derRETausgeführt wurde.
80386 Flaggen
Die '386 benötigte zusätzliche Flags, um die in den Prozessor integrierten zusätzlichen Funktionen zu unterstützen.
-
RFDas Resume-Flag.
Die `386 fügte Debug-Register hinzu, die den Debugger bei verschiedenen Hardware-Zugriffen aufrufen konnten, z. B. Lesen, Schreiben oder Ausführen eines bestimmten Speicherorts. Wenn der Debug-Handler jedoch zurückkehrt, um die Anweisung auszuführen, würde der Zugriff den Debug-Handler sofort erneut aufrufen! Zumindest wäre dies der Fall, wenn es nicht für das Resume-Flag wäre, das bei der Eingabe in den Debug-Handler automatisch gesetzt und nach jeder Anweisung automatisch gelöscht wird. Wenn das Resume-Flag gesetzt ist, wird der Debug-Handler nicht aufgerufen. -
VMDas virtuelle 8086-Flag.
Um älteren 16-Bit-Code sowie neueren 32-Bit-Code zu unterstützen, kann der 80386 16-Bit-Tasks in einem "Virtual 8086" -Modus mithilfe eines Virtual 8086-Managers ausführen. DasVMFlag zeigte an, dass es sich bei dieser Aufgabe um eine virtuelle 8086-Aufgabe handelt.
80486 Flaggen
Mit der Verbesserung der Intel-Architektur wurde diese Technologie durch Caches und Superskalar-Ausführung schneller. Das musste den Zugriff auf das System durch Annahmen optimieren. Um diese Annahmen zu kontrollieren, wurden mehr Flaggen benötigt:
-
ACAusrichtungsüberprüfungsflag Die x86-Architektur konnte immer auf Multi-Byte-Speicherwerte an jeder Byte-Grenze zugreifen, im Gegensatz zu einigen Architekturen, bei denen eine Größenanpassung erforderlich war (4-Byte-Werte mussten auf 4-Byte-Grenzen liegen). Dies war jedoch weniger effizient, da für den Zugriff auf nicht ausgerichtete Daten mehrere Speicherzugriffe erforderlich waren. Wenn dasACFlag gesetzt wurde, würde ein nicht ausgerichteter Zugriff eine Ausnahme auslösen, anstatt den Code auszuführen. Auf diese Weise könnte der Code während der Entwicklung mitACSet verbessert werden, er wurde jedoch für den Produktionscode deaktiviert.
Pentiumflaggen
Der Pentium fügte weitere Unterstützung für die Virtualisierung hinzu sowie die CPUID Anweisung:
-
VIFDas Flag für virtuelle Unterbrechungen.
Dies ist eine virtuelle Kopie derIFdieser Task - unabhängig davon, ob diese Task Interrupts deaktivieren möchte oder nicht, ohne dass dies Auswirkungen auf globale Interrupts hat. -
VIPDas Kennzeichen für die Unterbrechung der virtuellen Unterbrechung.
Dies zeigt an, dass ein Interrupt vonVIFvirtuell blockiert wurde. Wenn der Task einenSTIausführt, kann ein virtueller Interrupt ausgelöst werden. -
IDDasCPUIDFlag, das zugelassen wurde.
Gibt an, ob diese Task dieCPUIDAnweisung ausführen soll. Ein virtueller Monitor könnte dies nicht zulassen und den anfordernden Task "belügen", wenn er die Anweisung ausführt.