Informatik · Klasse 10–13 · aktualisiert
Assembler verstehen: Befehle, Register, Schleifen
Du lernst, was Assemblersprache ist, wie Register, Befehle und Sprünge zusammenarbeiten, und verfolgst eine Schleife Schritt für Schritt.
0 von 10 Aufgaben gelöst
Kurz gesagt
Assemblersprache ist eine Programmiersprache mit Kürzeln wie „mov“ für einen bestimmten Prozessortyp. Ein Assembler übersetzt sie in Maschinensprache. Assemblercode ist architekturabhängig: Er lässt sich im Allgemeinen nicht ohne Anpassung auf andere Prozessoren übertragen.
Jedes Programm läuft am Ende als Folge von Maschinenbefehlen im Prozessor. Assemblersprache ist die Programmiersprache, die diesen Befehlen sehr nahe kommt. Mit ihr siehst du, was sonst hinter Hochsprachen versteckt bleibt. Hier lernst du die Begriffe und verfolgst selbst eine Schleife.
Deine Lernziele
Hake ab, was du schon kannst. Löst du alle Aufgaben eines Abschnitts, hakt Mela das Ziel für dich ab.
4 Abschnitte
Das Wort „Assembler“ meint zwei Dinge, die man leicht verwechselt. Eine Assemblersprache ist eine Programmiersprache, die auf den Befehlsvorrat eines bestimmten Computertyps ausgerichtet ist. Ein Befehl in Maschinensprache besteht aus einem Operationscode (Opcode) und meist weiteren Angaben, den Operanden. Weil Opcodes Zahlenwerte und schwer zu merken sind, nutzt die Assemblersprache leichter merkbare Kürzel in Textform, zum Beispiel „mov“. Diese Kürzel heißen mnemonische Symbole oder Mnemonics. Ein Text in Assemblersprache heißt Assemblercode.
Ein Assembler ist dagegen ein Computerprogramm, das diesen Quelltext in Maschinensprache übersetzt. Dabei ignoriert er Kommentare. Ein Compiler übersetzt Programme einer Hochsprache. Hochsprachen orientieren sich eher an der menschlichen Sprache. Vereinfacht und nicht immer zutreffend sieht man den Unterschied oft so: Ein Compiler macht aus einer Anweisung jeweils mehrere Maschinenbefehle, bei einem Assembler gibt es typischerweise eine Eins-zu-Eins-Abbildung.
Umgekehrt gibt es den Disassembler. Er übersetzt Maschinensprache zurück in Assemblersprache. Das geht, weil es zwischen einfacher Assemblersprache und Maschinensprache eine Eins-zu-Eins-Beziehung gibt. Bezeichner und Kommentare kommen dabei nicht zurück, weil sie bei der Assemblierung verloren gehen.
Im Alltag werden die Wörter oft vermischt: Die Sprache wird kurz auch „Assembler“ genannt, und „Maschinensprache“ und „Assembler(sprache)“ werden häufig gleichgesetzt. Achte deshalb darauf, ob die Sprache oder das Übersetzerprogramm gemeint ist.
Definition
Assemblersprache
Eine Assemblersprache ist eine Programmiersprache, die auf den Befehlsvorrat eines bestimmten Computertyps ausgerichtet ist. Statt Zahlencodes nutzt sie leichter verständliche Kürzel in Textform.
Beispiel: Ein Befehl in Maschinensprache und in Assemblersprache
- 1Maschinensprache (x86): 10110000 01100001, hexadezimal B0 61
- 2Assemblersprache (Intel-Schreibweise): mov al, 61h
- 3Bedeutung: Der hexadezimale Wert 61 steht für dezimal 97. Er wird in den niederwertigen Teil des Registers ax geladen, den man al nennt.
- 4Der Assembler übersetzt die Zeile mov al, 61h in diesen Maschinencode.
Merke: Die Assemblersprache ist die Sprache, der Assembler ist das Programm, das sie in Maschinensprache übersetzt. Der Disassembler arbeitet in die Gegenrichtung.
Teste dich
Register sind kleine, sehr schnelle Speicherbereiche direkt im Prozessor, nahe bei den Rechenwerken. Datenregister speichern zum Beispiel die Zahlen, mit denen gerechnet wird, und die Ergebnisse. Ein Befehl besteht aus einem Kürzel und oft aus Operanden. Operanden sind die Angaben, mit denen der Befehl arbeitet, etwa Register oder Zahlen.
Wir nutzen die Intel-Schreibweise für x86-Prozessoren: „mov wohin, was/woher“. Der Befehl mov kopiert den zweiten Operanden in den ersten. Der Befehl inc addiert 1 zum Zieloperanden, dec subtrahiert 1 davon.
Normalerweise arbeitet der Prozessor die Befehle nacheinander ab. Welcher Befehl dran ist, steht im Befehlszähler (auch Programmzähler, bei x86 Befehlszeiger oder IP-Register). Er enthält je nach Systemarchitektur die Speicheradresse des derzeitigen oder des nächsten auszuführenden Befehls. Eine Sprunganweisung setzt dieses Register auf einen neuen Wert. Beim Befehl jmp (von „jump“, springen) wird die Adresse des Sprungziels geladen, und der Prozessor macht dort weiter.
Die Adresse musst du nicht selbst ausrechnen. Du markierst das Sprungziel mit einem Label, zum Beispiel „ziel:“. Daraus ermittelt der Assembler die Adresse und setzt sie in den Opcode ein.
Bei bedingten Sprüngen wird nicht in jedem Fall gesprungen, sondern in Abhängigkeit von Flags. Flags sind einzelne Zustandsangaben, die das Statusregister nach einem Befehl festhält. Zuerst setzt der Befehl cmp die Flags. Er entspricht einem sub-Befehl, verändert aber nur die Flags und keinen Operanden. Das Zero Flag (ZF) ist 1, falls das Resultat 0 ist, sonst 0. Der Befehl je springt bei ZF = 1, jne springt bei ZF = 0.
Definition
Label
Ein Label ist ein Name, der eine Stelle im Programm als Sprungziel kennzeichnet, zum Beispiel ziel:. Der Assembler ermittelt daraus die Adresse und setzt sie in den Opcode ein.
| Befehl | Wirkung |
|---|---|
| mov a, b | Kopiert den zweiten Operanden in den ersten |
| inc x | Addiert 1 zum Zieloperanden |
| dec x | Subtrahiert 1 vom Zieloperanden |
| jmp ziel | Unbedingter Sprung: Die Adresse des Sprungziels wird ins IP-Register geladen |
| cmp a, b | Vergleicht wie sub, verändert aber nur die Flags |
| jne ziel | Springt zum Label, wenn ZF = 0 ist (Operanden ungleich) |
Beispiel: Ein Sprung mit Label
- 1start: jmp short ziel → Das IP-Register bekommt die Adresse von ziel.
- 2Die Befehle zwischen jmp und dem Label ziel werden übersprungen.
- 3ziel: mov cx, 05h → Hier macht der Prozessor weiter.
Teste dich
Eine Schleife wiederholt Befehle. Mit dem Befehl loop lässt sich eine Schleife bauen, die einer FOR-Schleife ähnelt. Die Schreibweise ist loop adresse, als Adresse nimmst du ein Label. Die Anzahl der Schleifendurchgänge befindet sich im CX-Register (Counter Register, also Zählregister). Bei jedem Durchgang wird CX um 1 verringert. Ist CX gleich 0, wird die Schleife verlassen und der nächste Befehl bearbeitet. Sonst springt der Prozessor zum Label. Man kann loop auch mit den zwei Befehlen dec cx und jne adresse nachbilden.
Das Programm unten berechnet 7!, die Fakultät von 7, also 1 · 2 · 3 · 4 · 5 · 6 · 7. Der Befehl mul bx multipliziert hier AX mit BX. Das Ergebnis liegt im AX-Register. So gehst du vor: Schreibe die Startwerte auf. Führe dann in jedem Durchgang die Befehle der Reihe nach aus. Verringere am Ende CX um 1 und prüfe, ob CX 0 ist.
Belegt sind der Start (CX = 7, BX = 1), das Ende (im letzten Durchgang CX = 1 und BX = 7) und das Ergebnis AX = 13B0 (hexadezimal). Die Zwischenwerte der Tabelle sind aus diesen Regeln hergeleitet, nicht gemessen. Zur Probe (eigene Rechnung): 13B0 hexadezimal ist 1 · 4096 + 3 · 256 + 11 · 16 + 0 = 5040. Das passt zur letzten Tabellenzeile.
Beispiel: Das Programm für 7! Zeile für Zeile
- 1mov cx, 7 → Der Schleifenzähler CX bekommt den Wert 7.
- 2mov ax, 1 und mov bx, 1 → AX = 1 und BX = 1.
- 3schleife: mul bx → AX wird mit BX multipliziert.
- 4inc bx → BX wird um 1 größer.
- 5loop schleife → CX sinkt um 1. Bei CX = 0 endet die Schleife, sonst geht es zurück zum Label schleife.
| Durchgang | Beim Start | AX nach mul bx |
|---|---|---|
| 1 | CX = 7, BX = 1 | 1 |
| 2 | CX = 6, BX = 2 | 2 |
| 3 | CX = 5, BX = 3 | 6 |
| 4 | CX = 4, BX = 4 | 24 |
| 5 | CX = 3, BX = 5 | 120 |
| 6 | CX = 2, BX = 6 | 720 |
| 7 | CX = 1, BX = 7 | 5040 |
Merke: Der Startwert von CX gibt die Zahl der Durchgänge an. loop verringert CX um 1 und springt zurück, bis CX den Wert 0 hat.
Teste dich
Jede Computerarchitektur hat ihre eigene Maschinensprache und damit ihre eigene Assemblersprache. „Assemblersprache“ klingt nach einer einzigen Sprache, ist aber eine ganze Familie von Sprachen. Die Sprachen unterscheiden sich in Anzahl und Typ der Operationen. Auch die Registersätze unterscheiden sich in Größe, Anzahl und Art der Register. Die Tabelle zeigt drei Schreibweisen aus drei Familien. Hier gibt es besonders große Unterschiede, insbesondere welche Register, Adressierungsarten und Operationen es gibt.
Assemblerprogramme sind sehr hardwarenah geschrieben, weil sie direkt die Befehlssätze der einzelnen Prozessorarchitekturen abbilden. Darum kann ein Assemblerprogramm im Allgemeinen nicht auf ein anderes Computersystem übertragen werden, ohne dass der Quelltext angepasst wird. Das erfordert je nach Unterschieden hohen Umstellungsaufwand, unter Umständen ist ein komplettes Neuschreiben nötig. Bei Hochsprachen muss dagegen oft nur ein Compiler für die neue Zielplattform verwendet werden.
Auch ein Assembler ist immer auf einen oder wenige Prozessortypen ausgerichtet. Er weist außerdem Befehle zurück, die für diesen Prozessor oder Modus nicht erlaubt sind. Mitunter gibt es sogar mehrere Dialekte für dieselbe Architektur. Die Intel- und die AT&T-Schreibweise formulieren deutlich verschieden, obwohl derselbe Maschinencode entsteht.
Warum nutzt man Assemblersprache trotzdem? Sie kann alle Möglichkeiten des Mikroprozessors nutzen. Im Allgemeinen wird sie nur noch verwendet, wenn Programme oder einzelne Teile davon sehr zeitkritisch sind oder wenn nur sehr wenig Speicherplatz zur Verfügung steht. Die Grenzen: Quelltexte sind fast immer deutlich länger als in einer Hochsprache, weil die Instruktionen weniger komplex sind. Das erhöht das Risiko für unübersichtlichen Programmcode.
| Prozessor | Beispiel in Assemblersprache |
|---|---|
| Intel 80386 | add eax,[edx+16] |
| Motorola 68000 | add.l 16(a2),d0 |
| MIPS 4000 | lw t2,16(t1); add t0,t3, t2 |
Definition
Cross-Assembler
Ein Cross-Assembler läuft auf einer Computerplattform H (Host) und erzeugt Maschinencode für eine andere Computerplattform T (Target).
Merke: Assemblercode gehört zu einer Prozessorarchitektur. Bei einem Wechsel muss der Quelltext im Allgemeinen angepasst werden, unter Umständen ganz neu geschrieben.
Teste dich
Alles auf einen Blick
Assembler
Begriffe
Die Assemblersprache ist die Programmiersprache, der Assembler das Programm, das sie in Maschinensprache übersetzt.
Register
Sie sind sehr schnelle Speicherbereiche im Prozessor. Der Befehlszähler enthält je nach Architektur die Adresse des derzeitigen oder nächsten Befehls.
Sprünge
Ein Label kennzeichnet das Ziel, ein Sprung setzt den Befehlszähler neu. Bedingte Sprünge hängen von Flags ab.
Schleife
loop verringert CX um 1 und springt zurück, bis CX den Wert 0 hat.
Architektur
Assemblercode bildet den Befehlssatz einer Architektur ab und muss bei einem Wechsel im Allgemeinen angepasst werden.
Musteraufgabe · Schritt für Schritt
Zähler hochzählen (ausgedachtes Beispiel)
- 1Programm: mov cx, 3 · mov ax, 0 · z: inc ax · loop z
- 2Start: CX = 3, AX = 0
- 3Durchgang 1: inc ax → AX = 1; loop: CX = 2, Sprung zu z
- 4Durchgang 2: AX = 2; loop: CX = 1, Sprung zu z
- 5Durchgang 3: AX = 3; loop: CX = 0, die Schleife wird verlassen
- 6Ergebnis: Die Schleife läuft 3-mal, am Ende ist AX = 3.
Fehler finden
Prüfe die Schritte dieser Schleife (ausgedachtes Beispiel) In einer Zeile steckt ein Fehler. Tippe sie an.
Fehler in Zeile 5Die Schleife wird erst bei CX = 0 verlassen, nicht schon bei CX = 1. Richtig: Nach Durchgang 3 gilt CX = 1 und es geht weiter zu z. Erst Durchgang 4 (AX = 6, CX = 0) beendet die Schleife.
Lückentext
Wähl in jeder Lücke das passende Wort und prüf dann deine Antworten.
Ein Assembler übersetzt Quelltext in . Beim Befehl loop steht die Zahl der Durchgänge im Register , bei jedem Durchgang sinkt sie um 1. Ein Assemblerprogramm lässt sich im Allgemeinen auf eine andere Prozessorarchitektur übertragen.
Karteikasten
Erst selbst überlegen, dann umdrehen.
Übung mit Feedback