Die Assembler Sprache kennt nicht den Begriff
"Unterprogramm". Wir können aber eine Folge von Befehlen schreiben
die von anderen Zonen des Programmes gerufen werden können, und nach der
Ausführung des Unterprogrammes folgt die weitere Ausführung des Ruferprogramms.
Ein "Unterprogramm" kann durch einem jmp Befehl
gerufen werden. Das Problem ist aber dass der Prozessor sich nicht erinnern
kann von wo er zum "Unterprogramm geschickt" wurde, deswegen weiss er
nicht wohin er nach der Ende des Unterprogrammes zurückspringen soll. Es ist also
nötig, dass, wenn ein Unterprogramm gerufen ist, die Rückkehradresse irgendwo
gespeichert wird, und die Rückkehr ist eigentlich ein
Sprungbefehl (jmp) auf diese Adresse.
Der Ort wo die Rückkehradresse gespeichert wird ist der
sogenannte Stapel (stack). Wir brauchen einen Stapel, weil das Unterprogramm ein
anderes Unterprogramm rufen kann, dieses Unterprogramm wieder ein anderes rufen
kann, usw.
Es gibt zwei Befehle: call und ret(urn).
Das call Befehl hat die folgende Syntax:
call Label
Es ist eigentlich ein jmp Sprungbefehl der auf der Spitze
des Stapels noch zusätzlich die Adresse des folgenden Befehls (das gleich nach
dem call kommt) stellt.
Der ret Befehl nimmt von der Spitze des Stapels eine
Adresse, dann wird ein Sprungbefehl zu diese Adresse durchgefürt.
Der Befehl hat keine Argumente, weil die Adresse nicht
explizit gegeben ist, sondern es wird von der Spitze des Stapels genommen.
Der Stapel soll als Segment von Typ stack deklariet werden
und man soll auch Raum für die Daten besetzen, die im Stapel gespeichert
werden.
Beispiel:
Stapel segment stack
db 512 dup (?)
Stapel ends
Hier wird ein Segment von 512 Bytes deklariert, das als
Stapel benützt wird. Den Stapel kann man auch fürs (temporäre) Memorieren der Variablen
benützen. Der "push" Befehl legt das Argument auf der Spitze des Stapels,
während der "pop" Befehl nimmt den Wert von der Spitze des Stapels heraus,
und schreibt es in ein, als Argument gegebenes Register oder
Speicherstelle.
Merken Sie sich dass die Unterprogrammen keine lokale
Variablen oder lokale Labels haben können. Alle Namen sind vom ganzen Programm
sichtbar, deswegen sollen wir aufpassen damit es nicht mehrere Labels mit dem
gleichen Namen im Hauptprogramm und im Unterprogramm gibt.
Beispiel
Sehen Sie das Beispiel UnterPr.asm.
Ein Assembler Programm kann in mehrere Quelldateien geteilt
werden. Wenn wir ein Programm schreiben möchten, das mehrere Module hat, sollen
wir auf die folgende beachten:
-
Alle Segmenten sollen als public (siehe Norton Guide)
deklariert werden, weil im endgültigen Programm wird das Kodesegment durch die
Zusammenfügung der Kodesegmenten aus den verschiedenen Modulen aufgebaut; das
gleiche gilt fürs Datensegment.
-
Die Labels und Variablennamen, auf die von einem
anderen Modul zugegriffen werden soll, soll man mit der Direktive public
deklarieren.
-
Die Labels und Variablen die in einem Modul deklariert
sind und in einem anderen Modul benützt werden, sollen mit der Direktive extrn
"importiert" werden.
-
Eine Variable soll ganz in einem Modul deklariert
werden (es kann nicht ein Teil davon in einem Modul und der Rest in einem
anderen sein). Der Übergang, bei der Ausführung der Befehle, von einem Modul zu
den anderen ist durch Sprungbefehle (jmp, call oder ret) durchgefürt.
-
Der Eintrittspunkt wird nur im Hauptmodul - wo der
"Hauptprogramm" ist - gegeben werden.
-
Alle Modulen werden getrennt übersetzt (mit tasm), dann
werden die Modulen mit dem Befehl
tlink /v modul_1 modul_2 ...
modul_n
zusammengelegt.
Das ausführbare Programm wird der
Name des ersten Modules haben.
Beispiel
HauptP.asm ausgeb.asm