x86-Programmierung und -Betriebsarten (Teil 2)

Adressierungsarten

Soll ein Register (hier beispielsweise der Akkumulator EAX) über

MOV EAX, wert

mit einem Wert geladen werden, dann stehen drei Möglichkeiten zur Verfügung:

  • Unmittelbarer Operand (Immediate): MOV EAX, 6a02h: Das Akkumulatorregister EAX wird mit dem Wert 6a02h geladen. Dieser Wert wird zur Programmierzeit fest vorgegeben und ist Bestandteil des Programmcodes, das heißt er erscheint als Bestandteil des Befehlsstroms, der von der Busschnittstelle in die Prefetch-Queue geladen wird. Das zugeordnete Segment ist also das Codesegment CS und nicht das Datensegment DS oder ein Extrasegment. Die Steuereinheit gibt ihn aber an das Register EAX und nicht an die Ausführungseinheit weiter, wie das für einen Befehl der Fall ist.

  • Registeroperand: MOV EAX, EBX: Das Register EAX wird mit dem Wert im Register EBX geladen. Auch im obigen Beispiel war EAX ein Registeroperand (nämlich der Ziel- oder Destination-Operand). Hier ist auch der Quellen- oder Source-Operand ein Register (nämlich EBX).

  • Speicheroperand: MOV EAX, mem32: Anstelle von mem32 muss in diesem Fall die effektive Adresse (siehe unten) des symbolischen Operanden stehen, der in den Akkumulator übertragen werden soll. Ist die effektive Adresse fest, das heißt eine schon zur Assemblierzeit bekannte Größe, wird sie bereits vom Assembler berechnet. mem32 ist in diesem Fall ein direkter Speicheroperand. Direkte Speicheroperanden werden in einem Makroassembler meist mit einem festen Symbol bezeichnet (wie array). Weist die effektive Adresse einen veränderlichen Anteil auf, wie beispielsweise ein Register mit veränderlichem Wert, so berechnet die CPU zur Laufzeit die effektive Adresse. In diesem Fall stellt mem32 einen indirekten Speicheroperanden dar.

Als effektive Adresse bezeichnet man den Offset des Operanden innerhalb des ausgewählten Segments (hier: DS). Die effektive Adresse setzt sich aus bis zu vier Elementen zusammen:

  • Displacement: MOV EAX, array[0]: Das erste Element des Feldes array wird in den Akkumulator geladen. array[0] ist eine symbolische Bezeichnung, wie sie ein Makroassembler verarbeiten kann, um dem Programmierer die Arbeit zu erleichtern. Im assemblierten Programm steht anstelle von array[0] eine Zahl, die die Adresse des symbolischen array[0] angibt. Befindet sich array[0] beispielsweise bei der Adresse 0f2h, so lautet der Befehl in diesem Fall MOV EAX, [0f2h]. Verwechseln Sie dies nicht mit einem unmittelbaren Operanden: Bei einem Displacement wird der Wert an der angegebenen Adresse und nicht der Wert selbst angesprochen. In unserem Beispiel wird also der Wert im Segment DS bei Offset 0f2h geladen und nicht der Wert 0f2h selbst.

  • Basisregister: MOV EAX, [EBX]: Der Befehl lädt den Operanden im Segment DS bei dem Offset, den der Wert im Register EBX angibt, in den Akkumulator. Weist EBX beispielsweise den Wert 0f2h auf, so ist dieser Befehl äquivalent zu MOV EAX, array[0]. Der Unterschied zwischen [EBX] und array[0] besteht darin, dass der Wert von EBX vom Programm dynamisch geändert werden kann, array[0] jedoch einen während des Programmablaufs stets festen und konstanten Wert darstellt. Durch eine Veränderung von EBX kann bei Verwendung einer Schleife beispielsweise das gesamte Feld array abgearbeitet werden. Das ist der Anweisung FOR I=0 TO 99 ... NEXT I in BASIC ähnlich. Als Basisregister sind EBX und EBP gültig.

  • Indexregister: MOV EAX, [ESI]: In dieser Grundform ist die Verwendung des Indexregisters identisch mit der Benutzung des Basisregisters. Zusätzlich haben Sie aber beim Indexregister noch die Möglichkeit, einen Skalierungsfaktor zuzuordnen. Als Indexregister sind ESI und EDI gültig.

  • Skalierungsfaktor: MOV EAX, [ESI*4]: Um die effektive Adresse zu berechnen, wird beim angegebenen Beispiel der Wert des Indexregisters ESI mit vier multipliziert. Hierdurch können beispielsweise Felder indiziert werden, deren Elemente vier Byte lang sind. Der Prozessor führt die Skalierung (oder anders ausgedrückt: Multiplikation) mit einem Faktor größer als 1 ohne Verzögerung aus. Für den Skalierungsfaktor können Sie die Werte 1, 2, 4 und 8 verwenden. Der Skalierungsfaktor wurde mit dem 80386 in die Adressierung eingeführt.