Eine typische Anwendung ist das tempor¨are Zwischenspeichern von Daten. Beachten Sie im folgenden Beispiel die Reihenfolge der PUSH und POP-Befehle:
push dx ;dx zwischenspeichern push ax ;ax zwischenspeichern
mov dx, offset Meldung ;dx wird gebraucht mov ah,09
9.4. TESTFRAGEN 79 int 21h
pop ax ;ax erh¨alt wieder den alten Wert pop dx ;dx erh¨alt wieder den alten Wert
Manchmal kann auch ein Transport von Daten gut ¨uber den Stack abgewickelt werden. Im folgenden Beispiel soll der Inhalt von DS nach ES kopiert werden. Dies kann geschehen durch
mov ax,ds ; DS kann nicht direkt nach ES kopiert werden mov es,ax ; AX ist ver¨andert
Das gleiche kann auch ¨uber den Stack als Zwischenstation geschehen:
push ds ; Keine anderen Register werden ver¨andert pop es
Die Benutzung des Stack erlaubt z.B. auch beliebig tief geschachtelte Schleifen, die alle mit dem Register CX z¨ahlen.
9.4 Testfragen
1. push di push dl push fs push edi
Welche Befehle sind fehlerhaft?
2. push 8 push 9 push 10 pop ax pop bx pop cx
Welchen Inhalt haben die Register ax,bx,cx?
3. mov cx,10 mult: imul ax,2
push ax dec cx cmp cx,0 jne mult mov di,0
vom_stack_holen: pop ax mov [Feld+di],ax
80 KAPITEL 9. STACK UND STACKBEFEHLE add di,2
cmp di,20
jbe vom_stack_holen
Kommentieren Sie diesen Programmabschnitt!
L¨osungen auf Seite 130
Kapitel 10
Unterprogramme
Unterprogramme, engl. Procedures oder Subroutines, sind notwendig, um gute Assemblerpro-gramme zu schreiben. Die Gr¨unde daf¨ur sind:
• Die Ablaufsteuerung f¨ur Teilaufgaben ist zentral und nur einmal vorhanden
• Gute Unterprogramme sind modular und unterst¨utzen die Wiederverwendung
• Eine unn¨otige Aufbl¨ahung des Maschinencodes wird vermieden
• Die ¨Ubersicht wird verbessert
• Unterprogramme stellen gute Schnittstellen zu Hochsprachen dar
Mit dem Aufruf des Unterprogramms (CALL) verzweigt der Programmablauf ins Unterpro-gramm. Das Unterprogramm endet mit dem Return-Befehl (RET). Dieser bewirkt, dass die Ausf¨uhrung mit dem n¨achsten Befehl, der auf CALL folgt, fortgesetzt wird. Bei den meisten Unterprogrammen werden Informationen mit dem rufenden Programm ausgetauscht. Das Un-terprogramm wird durch Parameter gesteuert und liefert Ergebnisse an das rufende Programm zur¨uck. Unterprogramme k¨onnen ihrerseits wieder Unterprogramme aufrufen. Da Unterprogram-me mit den gleichen Register arbeiten m¨ussen, wie das rufende Programm, k¨onnen nach dem Unterprogramm Register ver¨andert sein. Im folgenden Beispiel bildet ein Unterprogramm den Mittelwert aus AX und BX und gibt ihn in AX zur¨uck.
.model small .stack 100h .code
start:
mov ax,15 ; Vorbereitung des Unterprogrammaufrufs mov bx,19 ; ¨Ubergabe der Parameter in AX und BX CALL Mittelwert_ax_bx ; Unterprogrammaufruf
mov ah,4ch ; Programmende
int 21h ;
81
82 KAPITEL 10. UNTERPROGRAMME PROC Mittelwert_ax_bx
add ax,bx ; Summe aus ax und bx nach ax shr ax,1 ; durch zwei teilen
ret ; Return: R¨ucksprung ENDP Mittelwert_ax_bx
END Start
Die Verwendung von PROC und ENDP ist nicht notwendig, ist aber sehr zu empfehlen. F¨ur die Ubergabe von Parametern und Ergebnissen gibt es verschiedene M¨¨ oglichkeiten:
Ubergabe in Registern¨ Einfach und gut, ¨ublich in reinen Assemblerprogrammen, z.B. BI-OS, DOS. M¨oglich ist auch die R¨uckgabe von Ergebnissen in Flags. Nachteil: Anzahl und Umfang der Parameter begrenzt. Bei großen Datenstrukturen muss man diese in Puffer-speichern halten und Zeiger auf diese Daten in Registern ¨ubergeben.
Stack¨ubergabe In Hochsprachen implementiert, etwas komplizierter erm¨oglicht aber (fast) unbegrenzte ¨Ubergabe
Uber globale Variable¨ f¨uhrt zu Abh¨angigkeiten von Variablendefinitionen im rufenden Pro-gramm. R¨uckgabe der Ergebnisse = Seiteneffekt. Schlecht und nur eine Notl¨osung!
Der R¨ucksprung an die richtige Stelle im rufenden Programm wird auf folgende Art gesichert:
CALL speichert die Adresse des n¨achsten Befehles nach CALL, die R¨ucksprungadresse, im rufenden Programmst¨uck auf den Stack.
RET holt die R¨ucksprungadresse vom Stack und l¨ad sie in das Instruction Pointer Register (IP), so dass dort fortgesetzt wird.
1
Ein wichtiges Thema ist das Ver¨andern von Registern durch Unterprogramme. Es gibt verschie-dene M¨oglichkeiten damit umzugehen:
Unterprogramm ¨andert keine Register Die sichere Methode: Alle im Unterprogramm be-nutzten Register werden zu Beginn des Unterprogramms auf den Stack gerettet und vor dem Return-Befehl wieder hergestellt. Dabei werden allerdings auch die Register gesichert, die im rufenden Programm gar nicht mehr gebraucht werden. Dies verlangsamt das Pro-gramm. Register f¨ur die Ergebnisr¨uckgabe m¨ussen ausgenommen werden.
Unterprogramm k¨ummert sich nicht um ver¨anderte Register Die intelligente Metho-de: Der Programmierer muss sich im rufenden Programm um die Rettung von Registe-rinhalten k¨ummern, allerdings nur, wenn diese Register noch gebraucht werden. Erfordert Aufmerksamkeit, f¨uhrt aber zu den schnellstm¨oglichen Programmen. Die richtige Wahl bei zeitkritischen Programmen.
1 CALL und RET sind also spezielle Sprungbefehle. In einer 16-Bit-Umgebung codiert der Assembler sie je nach Speichermodell als NEAR oder FAR.
83 Registergruppen Dies ist ein Kompromiss aus den beiden ersten L¨osungen: Ein Teil der Re-gister darf frei im Unterprogramm ver¨andert werden, der Rest muss gesichert und wieder-hergestellt werden. In Hochsprachen verwendet.
Tips zum guten Stil
Ein gutes Unterprogramm...
• erledigt eine Aufgabe und nur eine
• ist so kurz wie m¨oglich und so lang wie n¨otig (z.B. max. 100 Zeilen)
• beginnt mit Kommentaren: Aufgabe des Unterprogrammes, ¨Ubergabe der Parameter, ver¨anderte Register, Anmerkungen des Bearbeiters
• kann alleinstehend ¨ubersetzt und verstanden werden
• hat einen treffenden Namen
Kapitel 11
Die Gleitkommaeinheit
Die Gleitkommaeinheit, engl. floating point unit, FPU, ist eine relativ eigenst¨andige Verarbei-tungseinheit des Prozessors. Sie verf¨ugt ¨uber einen eigenen Befehlssatz und eigene Register und sie kann parallel zum Hauptprozessor arbeiten. Die SSE-Verarbeitungseinheiten (ab Pentium III) k¨onnen mehrere Gleitkommazahlen parallel verarbeiten.
11.1 Gleitkommazahlen
Die Gleitkommaeinheit unterst¨utzt drei Gleitkommaformate, die in Abb.11.1 dargestellt sind.
Intern wird immer im 80-Bit-Format gerechnet, die anderen Formate werden beim Laden in den Gleitkommastack in dieses Format umgewandelt. Alle Gleitkommaformate bestehen aus den Anteilen Vorzeichen, Exponent und Mantisse.
Abbildung 11.1: Die unterst¨utzten Gleitkommaformate