Ein kleines Beispiel: die bereits oben erwähnte (fiktive) Instruktion “0110110101”, ausgesprochen “addiere den Wert 5 auf den im Akkumulator gespeicherten Wert”, würde sich mit Hilfe einer Assemblersprache auf die folgende Art schreiben lassen:
Das Mnemonic al
bezeichnet hier übrigens das Akkumulator-Register. Die Zusammenfassung mehrerer Assemblerbefehle, die zusammenhängend ausgeführt werden sollen, um eine Aufgabe zu lösen, nennt man Assemblerprogramm. Assemblerprogramme werden in der Regel auch nicht mehr über externe Geräte eingegeben und dann in Lochkarten gestanzt, sondern direkt im Computer eingegeben. Die Übersetzung in echten Maschinencode (denn nur solchen kann der Prozessor verstehen) übernimmt dann ein sogenannter Assembler. Das ist ein relativ einfaches Programm, welches die geschriebenen Assembler-Befehle aus einer Datei lesen und in Maschinencode übersetzen kann und am Ende zum Beispiel eine ausführbare Datei (unter Windows sind das die Dinger mit “.exe” hinten dran) erzeugt.
An dieser Stelle möchte ich noch auf eine kleine Eigenheit in Bezug auf Assemblersprachen hinweisen, um spätere Verwirrung zu vermeiden: in der Umgangssprache (unter Informatikern) werden nicht nur die Übersetzungsprogramme “Assembler” genannt, sondern mitunter auch der geschriebene Code selber. Man sagt dann, dass ein Programm “in Assembler geschrieben” ist – gemeint ist natürlich, dass es in einer Assemblersprache geschrieben wurde, aber Informatiker sind zuweilen recht faul, was diese Unterscheidung angeht. Ich werde nach Möglichkeit versuchen, die beiden Begriffe immer zu unterscheiden; wenn es mir einmal nicht gelingt, sollte es aber deswegen jetzt auch keine Verwirrung mehr geben.
Nun ist allein schon die Möglichkeit, Mnemonics anstelle von komplizierten Instruktions-Codes benutzen zu können, eine große Erleichterung beim Programmieren. In einer Assemblersprache sind allerdings noch mehr Dinge möglich. Eine in den Assembler-Anfangszeiten besonders wichtige Eigenschaft war die Unterstützung bei der Behandlung von Variablen und Sprungbefehlen.
Genauso, wie ein Programm im Speicher liegt, da es nicht nur ausschließlich in den Registern des Prozessors gehalten werden kann (dafür gibt es nicht genügend), können die Daten eines Programms meist auch nicht nur in den Registern vorhanden sein. Bisher habe ich es noch nicht erwähnt, aber eigentlich ist klar, dass auch Daten im Speicher gehalten werden. Sie sind genauso wie Instruktionen über eine Adresse ansprechbar; so könnte etwa das Register al in der obigen add-Anweisung auch durch eine Adresse ersetzt werden, so dass die 5 nicht mehr in den Akkumulator, sondern in den Speicher geschrieben wird. Nun ist das Hantieren mit Speicheradressen natürlich höchst unkomfortabel; aus diesem Grund können in einem Assemblerprogramm sogenannte Variablen deklariert werden. Das sind im Grunde nichts anderes als eindeutige Bezeichner für bestimmte Adressen im Speicher; die zugrundeliegende Adresse dabei entweder von Hand angegeben oder – und hier liegt der große Vorteil – automatisch vom Assembler bestimmt werden. Die Deklaration und Benutzung von Variablen im Code ist relativ simpel; nachfolgend ein kleines Beispiel, in welchem eine Variable var deklariert und anschließend an die von ihr bezeichnete Adresse im Speicher der Wert 5 geschrieben wird (das db bedeutet nur, dass lediglich ein einziges Byte an Speicher reserviert werden soll):
mov var, 5
Für die Bearbeitung komplexerer Aufgabenstellungen, die über das reine Verrechnen von Zahlen hinausgehen, ist die Kontrolle des Programmflusses unerlässlich. In unseren bisherigen Betrachtungen sah es immer so aus, als würde streng eine Instruktion nach der anderen geladen; bei näherer Betrachtung erweist sich das allerdings als sehr nachteilig, da so nur wirklich lineare Probleme zu lösen sind. In der Regel sind allerdings auch Verzweigungen im Programmfluss und Wiederholungen von Programmcode nötig, außerdem auch der Aufruf sogenannter Unterprogramme (ein Unterprogramm ist im Grunde nichts anderes als ein Codeabschnitt, der eine meist kleinere Aufgabe löst). Und hier kommen die Sprungbefehle ins Spiel; sie ermöglichen, dass der sonst streng lineare Programmablauf unterbrochen werden kann, indem die nächste zu ladende Instruktion angegeben wird. Springt man dabei zurück zu einer bereits ausgeführten Instruktion, hat man eine Wiederholung; überspringt man einen Teil der Instruktionen, hat man eine Verzweigung im Programmcode; und springt man schließlich an eine ganz andere Stelle im Code, so entspricht dies dem Aufruf eines Unterprogramms. Wir erinnern uns: die Adresse der nächsten zu ladenden Instruktion steht im Instruktionsregister; modifiziert man nun also nun diesen Wert, kann ein Sprung in der Instruktionsreihenfolge durchgeführt werden. Der mnemonische Code für die einfachste derartige Anweisung, den unbedingten Sprung, ist jmp (als Abkürzung für “jump”, also Sprung), dass als Operanden das Sprungziel, also die Adresse der nächsten Instruktion erwartet. Zu Zeiten der Erstellung von Maschinencode per Hand war es dabei noch nötig, die exakte Adresse (die Adresse der konkreten Speicherzelle, welche die gewünschte Instruktion enthält) zu kennen, was insbesondere bei Vorwärtssprüngen kompliziert war. Außerdem hatte jede Änderung am Maschinencode zur Folge, dass unter Umständen die Sprungziele angepasst werden mussten (da sich durch das Einfügen von Befehlen ja die Adressen aller nachfolgenden Instruktionen ändern). Im Assemblercode ist es nun möglich, dieses Problem zu umgehen, und zwar dank der Verwendung von Sprungmarken; dies sind einfache Bezeichner, die an beliebigen Stellen im Code zwischen zwei Instruktionen eingefügt werden können und bei der Übersetzung in Maschinencode automatisch in konkrete Adressen umgewandelt werden. Hierzu ein kleines (nicht sinnvolles!) Beispiel (var ist unsere Variable von vorhin):
loop:
add al, 1
jmp loop
Der Code macht nichts anderes, als zu Anfang in das Register al
den Wert zu schreiben, der im Speicher an der durch var
beschriebenen Stelle steht und dann in einer (unendlich lang laufenden) Schleife immer wieder den Wert 1 darauf zu addieren.
Kommentare (20)