• Keine Ergebnisse gefunden

Die indirekte Speicheradressierung

2.4 Adressierungsarten

2.4.4 Die indirekte Speicheradressierung

Die direkte Adressierung reicht nicht mehr aus, wenn die Adresse der Speicherzelle erst zur Laufzeit bestimmt wird. Das kommt z.B. bei Feldern h¨aufig vor. Nehmen wir z.B. folgende Aufgabenstellung:

F¨ur eine Zeichenkette soll die H¨aufigkeit der darin vorkommenden Zeichen bestimmt werden.

Man braucht ein weiteres Feld um die H¨aufigkeit jedes Zeichens abzuspeichern. Bei der Bestim-mung der H¨aufigkeit muss f¨ur jedes erkannte Zeichen der dazu geh¨orende H¨aufigkeitsz¨ahler um eins erh¨oht werden. Auf welchen Speicherplatz zugegriffen wird, ergibt sich also erst zur Lauf-zeit und h¨angt von den Daten ab. Eine direkte Adressierung, wie z.B. inc [Haufigkeit+5]

usw. reicht nicht aus. Ebenso liegt der Fall bei der Programmierung von Sortieralgorithmen und vielen anderen Problemstellungen der Informatik.

Bei dem Problem der H¨aufigkeitsbestimmung w¨are nach den Deklarationen .DATA Zeichenkette DB ’ABCDEfGH’ Haeufigkeit DB 26 DUP (0)

im Codesegment eine direkte Adressierung wie z.B.

inc [Haeufigkeit+3]

2.4. ADRESSIERUNGSARTEN 31 nicht zweckm¨aßig, sie w¨urde immer das Feldelement Nr.3 (das vierte) ansprechen. Man m¨ußte statt der 6 etwas Variables einsetzen k¨onnen.

Genau dies erlaubt die Register-indirekte Adressierung, auch kurz indirekte Adressierung. Mit den Befehlen

mov bx, 3 ;Vorbereitung

inc [Haeufigkeit+bx] ;indirekte Adressierung

wird nun auch das Feldelement Nr.3 angesprochen, hier kann man aber zur Laufzeit berechnen, welcher Speicherplatz angesprochen wird!

Die indirekte Adressierung bietet die M¨oglichkeit, den Offset zur Laufzeit flexibel zu berechnen, und zwar als Summe aus dem Inhalt eines Basisregisters (BX oder BP), dem eines Indexregisters (DI oder SI) und beliebig vielen Konstanten. Die Konstanten k¨onnen auch Variablennamen sein.

Die allgemeine Form der indirekten Adressierung in 16-Bit-Umgebungen ist:

[Basisregister + Indexregister + Konstanten]

Es d¨urfen auch ein oder zwei Anteile entfallen. (Wenn nur eine Konstante in den Klammern steht, ergibt sich eine direkte Adressierung.) Die eckigen Klammern sind Pflicht. Die m¨oglichen Varianten sind also:

[ BX ] [ BX + Konstante]

[ BP ] [ BP + Konstante]

[ DI ] [ DI + Konstante]

[ SI ] [ SI + Konstante]

[ BX + DI ] [ BX + DI + Konstante]

[ BX + SI ] [ BX + SI + Konstante]

[ BP + DI ] [ BP + DI + Konstante]

[ BP + SI ] [ BP + SI + Konstante]

[ Konstante ]

Stehen innerhalb der eckigen Klammern mehrere Konstante, so werden sie schon bei der ¨ Uber-setzung vom Assembler zusammengefasst. Beispiel:

inc [1+Haeufigkeit+30+5]

wird bei der ¨Ubersetzung zu

inc [Haeufigkeit+36]

Eine wichtige Frage ist: In welchem Segment wird zugegriffen? Dies ist durch die Bauart des Prozessors festgelegt. Es gilt:

32 KAPITEL 2. ORGANISATION UND BENUTZUNG DES HAUPTSPEICHERS

• Der Prozessor greift im Stacksegment zu, wenn das Basisregister BP ist.

• Der Prozessor greift in allen anderen F¨allen im Datensegment zu.

Zum Laden der beteiligten Register mit dem Offset einer Variablen kann der Operator Offset verwendet werden. So ergeben sich dann sehr viele M¨oglichkeiten die Adressierung aufzubauen.

An einem kleinen Beispiel sei die Vielfalt demonstriert. Es soll das Zeichen Nr. 5 in einem Feld von Zeichen ¨uberschrieben werden.

.DATA\\

Zeichenkette DB ’ABCDEfGH’

.CODE

mov ax,@data mov ds,ax

mov [zeichenkette + 5],’F’ ;direkte Adressierung mov bx,5

mov [zeichenkette + bx],’F’ ;indirekte Adressierung mit BX + Konst.

mov bx,5

mov [zeichenkette + di],’F’ ;indirekte Adressierung mit DI + Konst.

mov bx,offset zeichenkette ;Offset von zeichenkette nach BX mov [bx+5],’F’ ;indirekte Adressierung mit BX + Konstante mov bx,offset zeichenkette ;Offset von zeichenkette nach bx mov si,5

mov [bx+si],’F’ ;indirekte Adressierung mit BX+SI mov bx,offset zeichenkette ;Offset von zeichenkette nach bx

add bx,5 ;BX um 5 erh¨ohen

mov [bx],’F’ ;indirekte Adressierung mit bx mov bx,offset zeichenkette ;Offset von zeichenkette nach bx mov si,4

mov [bx+si+1],’F’ ;indirekte Adressierung mit BX+SI+Konst.

mov si,offset zeichenkette+5 ;Offset von zeichenkette+5 nach si mov [si],’F’ ;indirekte Adressierung mit bx

Alle Adressierungen in diesem Beispiel adressieren die gleiche Speicherzelle! Man beachte, dass die Adressierungen mit BP bewusst vermieden wurden, da dies den Stack adressieren w¨urde.

Die indirekte Adressierung gibt uns also die M¨oglichkeit, den Inhalt eines Registers als variablen Zeiger in Speicher zu benutzen.

Wichtig: Variable Zeiger lassen sich nur mit Registern realisieren!

2.4. ADRESSIERUNGSARTEN 33 Eine Konstruktion ¨uber Speichervariable, die als Zeiger wirken sollen ist nicht m¨oglich. Beispiel:

.DATA

Zeichenkette DB ’ABCDEfGH’

Zeiger DW ? .CODE

mov ax,@data mov ds,ax

mov zeiger, offset zeichenkette ;Offset von zeichenkette in zeiger mov [zeiger+5],’F’ ;ACHTUNG: FEHLER!!!

Dieses Programmst¨uck wird klaglos ¨ubersetzt, funktioniert aber nicht so, wie es gedacht war.

Bei der ¨Ubersetzung wird f¨ur den Bezeichner ’zeiger’ der Offset dieser Variablen eingesetzt (8), in der eckigen Klammer steht also der konstante Ausdruck [8+5] also wird in dieser Zeile fest Speicherzelle 13 adressiert!

Typoperatoren

Ein Problem bleibt noch: Der 8086 kann bei einem Speicherzugriff 8 Bit ansprechen (Bytezugriff) oder 16 Bit (Wortzugriff). Der 386 kann sogar in einem Schritt auf ein Doppelwort mit 32 Bit zugreifen. Wenn der Speicher nun unter Verwendung eines Variablennamens adressiert wird, ist durch die Definition der Variablen die Art des Zugriffs festgelegt. Wird dagegen ein Registerinhalt als Adresse benutzt, ist evtl. der Assembler nicht in der Lage, die Art des Zugriffs zu bestimmen.

Beispiel:

.DATA

Zaehler DB (0) Spalte DW ? Feld DB 10 DUP(?) .CODE

. .

inc Zaehler ;Bytezugriff wegen Variablendeklaration dec Spalte ;Wortzugriff wegen Variablendeklaration mov bx,offset Feld

mov al,[bx] ;Aus Zielregister AL erkannt: Bytezugriff inc [bx] ;Unklar ob Byte- oder Wortzugriff!!

;Assembler codiert Wortzugriff und gibt Warning aus

Diese Unklarheit wird beseitigt durch die Verwendung einesTypoperators .

inc BYTE PTR [bx] ; Bytezugriff

34 KAPITEL 2. ORGANISATION UND BENUTZUNG DES HAUPTSPEICHERS Die erlaubten Typoperatoren sind:

BYTE PTR Auf die adressierte Speicherstelle wird als 8-Bit-Dateneinheit (Byte) zugeriffen.

WORD PTRAuf die adressierte Speicherstelle wird als 16-Bit-Dateneinheit (2 Byte, ein Wort) zugeriffen.

DWORD PTR Auf die adressierte Speicherstelle wird als 32-Bit-Dateneinheit (4 Byte, ein Doppelwort) zugeriffen.

In dem folgenden Beispiel wird der Typoperator BYTE PTR ausgenutzt um auf die beiden Bytes eines Wortes getrennt zuzugreifen

.DATA

Zaehler DW ? .CODE

. .

mov al,BYTE PTR [Zaehler] ; niederwertiges Byte laden mov bl,BYTE PTR [Zaehler+1] ; h¨oherwertiges Byte laden

Nun sei noch das Beispiel mit der Bestimmung der H¨aufigkeit der Buchstaben in einer Zeichen-kette vollst¨andig angegeben.

.MODEL SMALL ; Speichermodell "SMALL"

.STACK 100h ; 256 Byte Stack reservieren .DATA

Zeichenkette DB ’Morgenstund hat Gold im Mund’,0

; Zeichenkette DB ’AAABBC’,0 ; zum Testen Haeufigkeit DB 256 DUP (0)

.CODE

Programmstart:

mov ax,@data

mov ds,ax ; Laufzeitadresse des Datensgments nach DS

mov di,offset zeichenkette ;indirekte Adressierung vorbereiten

; wegen SMALL: Verw. von NEAR-Zeigern Zeichenholen:

mov bl,[di] ;indirekte Adressierung der Zeichenkette mit DI

;ein Zeichen aus der Kette nach bl laden mov bh,0 ;indirekte Adressierung mit BX vorbreiten

inc [Haeufigkeit + bx] ;Adresse wird zusammengesetzt aus Startadresse Haeufigkeit

;und dem Inhalt des Registers BX

;Beispiel: Das gelesene Zeichen war ein ’A’ (Code: 65)

;Bx enth¨alt jetzt den Wert 65 und es wird der

;Speicherplatz [Haeufigkeit+65] indirekt adressiert inc di ;Zeiger auf n¨achstes Zeichen weiterruecken

cmp bl,0 ;Ende der Zeichenkette? Begrenzungszeichen ist 0.

jne Zeichenholen ;Wenn Zeichen nicht gleich 0 n¨achstes Zeichen einlesen

2.5. TESTFRAGEN 35 mov ah,04Ch

int 21h ;Programm beenden

END Programmstart ;Ende der ¨Ubersetzung