Freigeben über


x86-Architektur

Der Intel x86-Prozessor verwendet komplexe Anweisungssatz-Computerarchitektur (CISC), was bedeutet, dass es eine geringe Anzahl von speziellen Registern anstelle großer Mengen von allgemeinen Registern gibt. Es bedeutet auch, dass komplexe Sonderanweisungen vorherrschen.

Der x86-Prozessor verfolgt sein Erbe mindestens so weit zurück wie der 8-Bit Intel 8080-Prozessor. Viele Besonderheiten im x86-Anweisungssatz sind auf die Abwärtskompatibilität mit diesem Prozessor (und mit seiner Zilog Z-80 Variante) zurückzuführen.

Microsoft Win32 verwendet den x86-Prozessor im 32-Bit-Flachmodus. Diese Dokumentation konzentriert sich nur auf den flachen Modus.

Register

Die x86-Architektur besteht aus den folgenden nicht privilegierten ganzzahligen Registern.

eax

Akkumulator

ebx

Basisregister

ecx

Leistungsindikatorregister

edx

Datenregister – kann für E/A-Portzugriff und arithmetische Funktionen verwendet werden

Esi

Quellindexregister

edi

Zielindexregister

ebp

Basiszeigerregister

ASW

Stack-Pointer

Alle ganzzahligen Register sind 32 Bit. Viele davon verfügen jedoch über 16-Bit- oder 8-Bit-Unterregister.

Axt

Niedrige 16 Bit eax

Bx

Niedrige 16 Bits von ebx

cx

Niedrige 16 Bit ecx

Dx

Niedrige 16 Bits von Edx

si

Niedrige 16 Bits von esi

di

Niedrige 16 Bit edi

Bp

Niedrige 16 Bit ebp

sp

Niedrige 16 Bits von esp

al

Niedrige 8 Bit eax

ah

Hohe 8 Bit ax

bl

Niedrige 8 Bits von ebx

bh

Hohe 8 Bits von bx

Cl

Niedrige 8 Bit ecx

Ch

Hohe 8 Bits cx

dl

Niedrige 8 Bits von edx

dh

Hohe 8 Bits von dx

Das Arbeiten auf einer Unterregisterregister betrifft nur das Unterregister und keines der Teile außerhalb der Unterregisterregister. Das Speichern im Ax-Register lässt beispielsweise die hohen 16 Bit des Eax-Registers unverändert.

Bei Verwendung der ? (Auswerten des Ausdrucks) Befehl, Register sollten einem "at"-Zeichen ( @ ) vorangestellt werden. Sie sollten z. B. ? @ax anstelle von ? ax verwenden. Dadurch wird sichergestellt, dass der Debugger ax nicht als Symbol, sondern als Register erkennt.

Das (@) ist jedoch im Befehl r (Registers) nicht erforderlich. Beispielsweise wird r ax=5 immer richtig interpretiert.

Zwei weitere Register sind für den aktuellen Zustand des Prozessors wichtig.

eip

Anweisungszeiger

flags

flags

Der Anweisungszeiger ist die Adresse der ausgeführten Anweisung.

Das Kennzeichenregister ist eine Sammlung von Single-Bit-Flags. Viele Anweisungen ändern die Flags, um das Ergebnis der Anweisung zu beschreiben. Diese Flags können dann durch bedingte Sprunganweisungen getestet werden. Details finden Sie unter "x86 Flags ".

Aufrufkonventionen

Die x86-Architektur verfügt über verschiedene Aufrufkonventionen. Glücklicherweise befolgen sie alle die gleichen Regeln für die Registerarchivierung und Funktionsrückgabe:

  • Funktionen müssen alle Register beibehalten, mit Ausnahme von eax, ecx und edx, die über einen Funktionsaufruf geändert werden können, und esp, die gemäß der Aufrufkonvention aktualisiert werden müssen.

  • Das Eax-Register empfängt Funktionsrücklaufwerte, wenn das Ergebnis 32 Bit oder kleiner ist. Wenn das Ergebnis 64 Bit ist, wird das Ergebnis im edx:eax-Paar gespeichert.

Es folgt eine Liste der Aufrufkonventionen, die für die x86-Architektur verwendet werden:

  • Win32 (__stdcall)

    Funktionsparameter werden im Stapel übergeben, rechts nach links verschoben, und der Angerufene bereinigt den Stapel.

  • Systemeigener C++-Methodenaufruf (auch bekannt als thiscall)

    Funktionsparameter werden an den Stapel übergeben, rechts nach links verschoben, der Zeiger "this" wird im ecx-Register übergeben, und der Angerufene bereinigt den Stapel.

  • COM (__stdcall für C++-Methodenaufrufe)

    Funktionsparameter werden im Stapel übergeben, von rechts nach links verschoben, dann wird der Zeiger "this" auf den Stapel verschoben, und dann wird die Funktion aufgerufen. Der Angerufene bereinigt den Stapel.

  • __fastcall

    Die ersten beiden DWORD-oder-kleineren Argumente werden in den ecx - und edx-Registern übergeben. Die verbleibenden Parameter werden an den Stapel übergeben, rechts nach links verschoben. Der Angerufene bereinigt den Stapel.

  • __cdecl

    Funktionsparameter werden im Stapel übergeben, rechts nach links verschoben, und der Aufrufer bereinigt den Stapel. Die __cdecl Aufrufkonvention wird für alle Funktionen mit Parametern mit variabler Länge verwendet.

Debuggeranzeige von Registern und Flags

Hier ist eine Beispieldebuggerregisteranzeige:

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

Im Benutzermodusdebugging können Sie die iopl und die gesamte letzte Zeile der Debuggeranzeige ignorieren.

x86-Flags

Im vorangehenden Beispiel sind die Zwei-Buchstaben-Codes am Ende der zweiten Zeile Kennzeichnungen. Dies sind Single-Bit-Register und haben eine Vielzahl von Verwendungsmöglichkeiten.

In der folgenden Tabelle sind die x86-Flags aufgeführt:

Kennzeichnungscode Flagname Wert Kennzeichnungsstatus Beschreibung
von Überlaufkennzeichnung 0 1 nvov Kein Überlauf - Überlauf
df Richtungsflag 0 1 updn Richtung nach oben - Richtung nach unten
if Interrupt-Kennzeichnung 0 1 diei Interrupts disabled - Interrupts enabled
sf Signaturkennzeichnung 0 1 Plng Positiv (oder Null) - Negativ
zf Nullkennzeichnung 0 1 nzzr Nonzero - Null
af Hilfstragsflagge 0 1 naac Kein Hilfstrag - Hilfstrag
pf Paritätskennzeichen 0 1 Pepo Parität ungerade - Parität sogar
vgl Kennzeichnung tragen 0 1 nccy Kein Tragen - Tragen
tf Trap-Flag Wenn tf gleich 1 ist, löst der Prozessor nach der Ausführung einer Anweisung eine STATUS_SINGLE_STEP Ausnahme aus. Dieses Kennzeichen wird von einem Debugger verwendet, um die Ablaufverfolgung in einem Schritt zu implementieren. Sie sollte nicht von anderen Anwendungen verwendet werden.
iopl E/A-Berechtigungsstufe E/A-Berechtigungsstufe Dies ist eine zwei-Bit-Ganzzahl mit Werten zwischen Null und 3. Es wird vom Betriebssystem verwendet, um den Zugriff auf Hardware zu steuern. Sie sollte nicht von Anwendungen verwendet werden.

Wenn Register als Ergebnis eines Befehls im Fenster "Debuggerbefehl" angezeigt werden, handelt es sich um den Flagstatus, der angezeigt wird. Wenn Sie jedoch ein Flag mit dem Befehl r (Registers) ändern möchten, sollten Sie über den Kennzeichnungscode darauf verweisen.

Im Fenster "Registers" von WinDbg wird der Kennzeichencode verwendet, um Flags anzuzeigen oder zu ändern. Der Kennzeichnungsstatus wird nicht unterstützt.

Beispiel: In der vorherigen Registeranzeige wird der Kennzeichnungsstatus ng angezeigt. Dies bedeutet, dass das Kennzeichen derzeit auf 1 festgelegt ist. Um dies zu ändern, verwenden Sie den folgenden Befehl:

r sf=0

Dadurch wird das Kennzeichen auf Null festgelegt. Wenn Sie eine andere Registeranzeige ausführen, wird der ng-Statuscode nicht angezeigt. Stattdessen wird der Pl-Statuscode angezeigt.

Die Kennzeichnung "Sign Flag", "Zero Flag" und "Carry Flag" sind die am häufigsten verwendeten Flags.

Bedingungen

Eine Bedingung beschreibt den Zustand einer oder mehrerer Flags. Alle bedingten Vorgänge auf dem x86 werden in den Bedingungen ausgedrückt.

Der Assembler verwendet eine oder zwei Buchstaben Abkürzung, um eine Bedingung darzustellen. Eine Bedingung kann durch mehrere Abkürzungen dargestellt werden. Beispielsweise ist AE ("über oder gleich") die gleiche Bedingung wie NB ("nicht darunter"). In der folgenden Tabelle sind einige allgemeine Bedingungen und deren Bedeutung aufgeführt.

Bedingungsname Flags Bedeutung

Z

ZF=1

Das Ergebnis des letzten Vorgangs war Null.

NZ

ZF=0

Das Ergebnis des letzten Vorgangs war nicht null.

K

CF=1

Der letzte Vorgang erforderte ein Tragen oder Ausleihen. (Bei nicht signierten ganzzahligen Zahlen gibt dies einen Überlauf an.)

NC

CF=0

Der letzte Vorgang erforderte kein Tragen oder Ausleihen. (Bei nicht signierten ganzzahligen Zahlen gibt dies einen Überlauf an.)

S

SF=1

Das Ergebnis des letzten Vorgangs hat seinen hohen Bitsatz.

NS

SF=0

Das Ergebnis des letzten Vorgangs weist seine hohe Bitlöschung auf.

O

OF=1

Bei der Behandlung als signierter ganzzahliger Vorgang verursachte der letzte Vorgang einen Überlauf oder Unterlauf.

NO

OF=0

Bei der Behandlung als signierter ganzzahliger Vorgang hat der letzte Vorgang keinen Überlauf oder Unterlauf verursacht.

Bedingungen können auch verwendet werden, um zwei Werte zu vergleichen. Die cmp-Anweisung vergleicht die beiden Operanden und legt dann Flags so fest, als würde ein Operand vom anderen subtrahiert werden. Die folgenden Bedingungen können verwendet werden, um das Ergebnis von cmp-Wert1, Wert2 zu überprüfen.

Bedingungsname Flags Bedeutung nach einem CMP-Vorgang.

E

ZF=1

wert1 == Wert2.

NE

ZF=0

wert1 != Wert2.

GE NL

SF=OF

value1>= value2. Werte werden als signierte ganze Zahlen behandelt.

LE NG

ZF=1 oder SF!=OF

value1<= value2. Werte werden als signierte ganze Zahlen behandelt.

G NLE

ZF=0 und SF=OF

wert1>Wert2. Werte werden als signierte ganze Zahlen behandelt.

L NGE

SF!=OF

wert1<Wert2. Werte werden als signierte ganze Zahlen behandelt.

AE NB

CF=0

value1>= value2. Werte werden als ganze Zahlen ohne Vorzeichen behandelt.

BE NA

CF=1 oder ZF=1

value1<= value2. Werte werden als ganze Zahlen ohne Vorzeichen behandelt.

A NBE

CF=0 und ZF=0

wert1>Wert2. Werte werden als ganze Zahlen ohne Vorzeichen behandelt.

B NAE

CF=1

wert1<Wert2. Werte werden als ganze Zahlen ohne Vorzeichen behandelt.

Bedingungen werden in der Regel verwendet, um auf das Ergebnis einer Cmp - oder Testanweisung zu reagieren. Beispiel:

cmp eax, 5
jz equal

Vergleicht das Eax-Register mit der Zahl 5, indem der Ausdruck (eax - 5) und die Einstellungskennzeichnungen entsprechend dem Ergebnis ermittelt werden. Wenn das Ergebnis der Subtraktion null ist, wird das Zr-Flag festgelegt, und die jz-Bedingung ist true, sodass der Sprung ausgeführt wird.

Datentypen

  • Byte: 8 Bit

  • Wort: 16 Bit

  • dword: 32 Bit

  • qword: 64 Bit (enthält Gleitkomma-Doubles)

  • zweird: 80 Bits (einschließlich erweiterter Gleitkomma-Doppelpunkte)

  • oword: 128 Bit

Notation

In der folgenden Tabelle ist die Schreibweise angegeben, die zum Beschreiben von Anweisungen zur Assemblysprache verwendet wird.

Notation Bedeutung

r, r1, r2...

Register

m

Speicheradresse (weitere Informationen finden Sie im Abschnitt "Adressierungsmodi erfolgreich".)

#n

Direktkonstante

r/m

Registrieren oder Arbeitsspeicher

r/#n

Register- oder direktkonstante

r/m/#n

Registrieren, Arbeitsspeicher oder sofortige Konstante

cc

Ein im vorherigen Abschnitt "Bedingungen" aufgeführter Bedingungscode.

T

"B", "W" oder "D" (Byte, Wort oder dword)

accT

Größe T Akkumulator: al if T = "B", ax if T = "W" oder eax if T = "D"

Adressierungsmodi

Es gibt mehrere verschiedene Adressierungsmodi, aber sie alle nehmen die Form T ptr [ausdruck], wobei T ein Datentyp ist (siehe vorherigen Abschnitt Datentypen) und Ausdruck ist ein Ausdruck, der Konstanten und Register umfasst.

Die Notation für die meisten Modi kann ohne große Schwierigkeiten abgeleitet werden. Beispielsweise bedeutet BYTE PTR [esi+edx*8+3] folgendes: "Nehmen Sie den Wert des esi-Registers ein, addieren Sie ihn acht mal den Wert des edx-Registers , fügen Sie drei hinzu, und greifen Sie dann an der resultierenden Adresse auf das Byte zu."

Befehlsverknüpfung

Der Prozessor ist duales Problem, was bedeutet, dass es bis zu zwei Aktionen in einer Taktuhr ausführen kann. Allerdings sind die Regeln, wann sie in der Lage ist, zwei Aktionen gleichzeitig (als Kopplung bezeichnet) auszuführen, sehr kompliziert.

Da x86 ein CISC-Prozessor ist, müssen Sie sich keine Gedanken über Sprungverzögerungsmodule machen.

Synchronisierter Speicherzugriff

Lade-, Änderungs- und Speicheranweisungen können ein Sperrpräfix erhalten, das die Anweisung wie folgt ändert:

  1. Vor dem Ausgeben der Anweisung löscht die CPU alle ausstehenden Speichervorgänge, um die Kohärenz sicherzustellen. Alle Datenvorschubs werden abgebrochen.

  2. Beim Ausstellen der Anweisung hat die CPU exklusiven Zugriff auf den Bus. Dadurch wird die Atomität des Lade-/Änderungs-/Speichervorgangs sichergestellt.

Die xchg-Anweisung befolgt automatisch die vorherigen Regeln, wenn ein Wert mit Speicher ausgetauscht wird.

Alle anderen Anweisungen sind standardmäßig nicht sperrend.

Sprungvorhersage

Bedingungslose Sprünge werden vorhergesagt.

Bedingte Sprünge werden vorhergesagt oder nicht genommen, je nachdem, ob sie das letzte Mal ausgeführt wurden. Der Cache für den Aufzeichnungssprungverlauf ist in der Größe begrenzt.

Wenn die CPU nicht über einen Datensatz verfügt, ob der bedingte Sprung ausgeführt wurde oder nicht das letzte Mal ausgeführt wurde, prognostiziert sie rückwärtsbedingte Sprünge wie angenommen und vorwärts bedingte Sprünge, wie sie nicht genommen wurden.

Ausrichtung

Der x86-Prozessor korrigiert automatisch den nicht ausgerichteten Speicherzugriff bei Leistungseinbußen. Es wird keine Ausnahme ausgelöst.

Ein Speicherzugriff wird als ausgerichtet betrachtet, wenn die Adresse ein ganzzahliges Vielfaches der Objektgröße ist. Beispielsweise werden alle BYTE-Zugriffe ausgerichtet (alles ist eine ganze Zahl von 1), WORD-Zugriffe auf gerade Adressen werden ausgerichtet, und DWORD-Adressen müssen ein Vielfaches von 4 sein, um ausgerichtet zu werden.

Das Sperrpräfix sollte nicht für nicht ausgerichtete Speicherzugriffe verwendet werden.