Ein Programm für einen Prozessor, den du nicht hast
Handys, Laptops und Server haben verschiedene Prozessoren, und jeder versteht nur seine eigenen Befehle. RISC-V ist ein offener Entwurf, den jeder bauen darf. Diese Maschine ist kein RISC-V, aber ein Emulator lässt sie trotzdem ein RISC-V-Programm ausführen.
Am Ende dieser Lektion
Notiz
Ich kann ein kurzes RISC-V-Programm von seinem Assembler bis zu seinem Exit-Status verfolgen.
Schlüsselwörter
- Prozessor: der Teil eines Computers, der Befehle ausführt.
- Befehl: ein kleiner Schritt, den ein Prozessor kann, etwa Addieren.
- Register: ein winziger, schneller Speicher im Prozessor.
- Emulator: ein Programm, das sich wie ein anderer Prozessor verhält.
- Exit-Status: die Zahl, die ein Programm am Ende zurückgibt.
- Cache: ein kleiner, schneller Speicher für das zuletzt Benutzte.
Zum Start: Was du schon weißt
Notiz
Antworte im Kopf. 1. Worin übersetzt ein Compiler den Quellcode? 2. Welcher Schritt verbindet Maschinencode zu einem Programm? 3. Was ist Assembler? Heute liest du Assembler, den ein Mensch geschrieben hat.
Bevor du anfängst
Notiz
Klicke oben in der Leiste dieser Lektion auf Lab starten. Dieses Lab ist eine ganze Ubuntu-Maschine nur für dich, deshalb dauert der Start etwas länger als bei einem Container. Jede Schaltfläche Ausführen tippt ihren Befehl ins Terminal der Maschine, einen nach dem anderen in derselben Sitzung. Wenn eine sagt, dass die Maschine noch startet, warte ein paar Sekunden und drücke sie noch einmal. Wo in der Lektion Tippe das ein steht, wartet das Programm auf deine Eingabe. Klicke dann in der Leiste auf Terminal öffnen (neuer Tab) und tippe selbst.
Ein RISC-V-Programm, Zeile für Zeile
add.s hat fünf Befehle. li legt eine Zahl in ein Register: 2 in a0 und 3 in a1. add addiert beide und legt das Ergebnis in a0. li a7, 93 wählt den Linux-Systemaufruf, der ein Programm beendet, und ecall führt ihn aus. Linux nimmt die Zahl in a0 als Exit-Status.
cd ~/archHier angezeigt, nicht ausgeführt. Erstellen Sie ein kostenloses Konto, um „Ausführen“ zu drücken und ihn im Terminal Ihres eigenen Labs einzugeben.
cat add.sHier angezeigt, nicht ausgeführt. Erstellen Sie ein kostenloses Konto, um „Ausführen“ zu drücken und ihn im Terminal Ihres eigenen Labs einzugeben.
Prüfe dich
Tipp
Was steht nach add a0, a0, a1 in a0? Antwort: 5, die Summe von 2 und 3.
Bauen und im Emulator ausführen
Der Assembler macht aus den Wörtern Maschinencode, und der Linker macht daraus ein Programm. file sagt, dass es für RISC-V ist. Dieser Prozessor kann es nicht ausführen, also führt qemu-riscv64 es aus, einen RISC-V-Befehl nach dem anderen. Es gibt nichts aus. echo $? zeigt den Exit-Status, den das Programm hinterlassen hat: 5.
riscv64-linux-gnu-as add.s -o add.oHier angezeigt, nicht ausgeführt. Erstellen Sie ein kostenloses Konto, um „Ausführen“ zu drücken und ihn im Terminal Ihres eigenen Labs einzugeben.
riscv64-linux-gnu-ld add.o -o addHier angezeigt, nicht ausgeführt. Erstellen Sie ein kostenloses Konto, um „Ausführen“ zu drücken und ihn im Terminal Ihres eigenen Labs einzugeben.
file addHier angezeigt, nicht ausgeführt. Erstellen Sie ein kostenloses Konto, um „Ausführen“ zu drücken und ihn im Terminal Ihres eigenen Labs einzugeben.
qemu-riscv64 ./addHier angezeigt, nicht ausgeführt. Erstellen Sie ein kostenloses Konto, um „Ausführen“ zu drücken und ihn im Terminal Ihres eigenen Labs einzugeben.
echo $?Hier angezeigt, nicht ausgeführt. Erstellen Sie ein kostenloses Konto, um „Ausführen“ zu drücken und ihn im Terminal Ihres eigenen Labs einzugeben.
Ein häufiger Fehler
Warnung
Viele glauben, echo $? zeige das Letzte, was ein Programm ausgegeben hat. Es zeigt den Exit-Status, eine Zahl von 0 bis 255, die das Programm am Ende zurückgibt. Ändere 2 und 3 in 200 und 100, baue neu, und die Antwort ist 44: 300 passt nicht hinein, also wird von vorn gezählt.
Befehle sind Zahlen
objdump -d zeigt das Programm so, wie der Prozessor es sieht. Jede Zeile nennt eine Adresse, den Befehl als Zahl in Hexadezimal und dann den Befehl in Wörtern. Jede Zahl hat acht Hexadezimalstellen, weil jeder dieser Befehle 32 Bit lang ist. ecall ist 00000073.
riscv64-linux-gnu-objdump -d addHier angezeigt, nicht ausgeführt. Erstellen Sie ein kostenloses Konto, um „Ausführen“ zu drücken und ihn im Terminal Ihres eigenen Labs einzugeben.
Ein Cache lässt Speicher schnell wirken
loop.c addiert zweimal eine Tabelle mit 16 Millionen Zahlen. Zeile für Zeile liegt die nächste Zahl direkt neben der letzten im Speicher, und der Cache hat sie schon geholt. Spalte für Spalte liegt jede Zahl 16 KB weiter, also wartet der Prozessor fast jedes Mal auf den Speicher. Die Summe ist gleich, 16777216; die Zeit nicht: Spalte für Spalte dauert ein Mehrfaches.
gcc -O2 -o loop loop.cHier angezeigt, nicht ausgeführt. Erstellen Sie ein kostenloses Konto, um „Ausführen“ zu drücken und ihn im Terminal Ihres eigenen Labs einzugeben.
./loopHier angezeigt, nicht ausgeführt. Erstellen Sie ein kostenloses Konto, um „Ausführen“ zu drücken und ihn im Terminal Ihres eigenen Labs einzugeben.
Tippe das ein: dem Prozessor beim Schritt zusehen
Tippe im Terminal gdb ./loop. Tippe break main und dann run: Das Programm hält am Anfang von main an. Tippe info registers pc, um den Befehlszähler (pc) zu sehen, die Adresse des nächsten Befehls. Tippe stepi, um einen einzigen Befehl auszuführen, und sieh dir pc noch einmal an: Er ist weitergerückt. Tippe quit und dann y.
Abschlusscheck
Tipp
Antworte, ohne zurückzuschauen. 1. Was ist ein Register? 2. Welcher Befehl führt auf dieser Maschine ein RISC-V-Programm aus? 3. Was zeigt echo $?? 4. Warum ist Zeile für Zeile schneller? Antworten: ein winziger, schneller Speicher im Prozessor; qemu-riscv64; den Exit-Status des letzten Befehls; die nächste Zahl liegt schon im Cache.
Für Lehrkräfte
Tipp
Diese Lektion läuft in einem VM-Lab: Jede lernende Person hat eine eigene Ubuntu-Maschine, und eine Schaltfläche „Ausführen“ tippt in ihr Terminal und zeigt, was ausgegeben wurde. Wichtige Lernpunkte: 1. Ein Prozessor führt Befehle aus, die mit Registern arbeiten. 2. Assembler und Linker machen aus Assembler ein Programm, und ein Emulator führt es für einen anderen Prozessor aus. 3. Speicher nahe am zuletzt Gelesenen ist dank des Caches schnell. Häufiger Fehler: den Exit-Status für die Ausgabe des Programms halten. Material: das Lab und ein Browser. Tipp: Lassen Sie die Klasse vor ./loop raten, welcher Weg schneller ist und um wie viel. Das Lab hat keine Prüfung und bewertet nichts; stellen Sie eine eigene Abgabe, wenn Sie eine Note brauchen.