Eine Prüfung aus drei Rechenschritten
Manche Programme prüfen eine Zahl nicht mit einem festen Wert. Sie rechnen erst, etwa mit Addieren, xor und Subtrahieren, und vergleichen das Ergebnis.
Wer die Schritte im Assembler liest, kann sie rückwärts rechnen und die Zahl bestimmen, die die Prüfung besteht.
Am Ende dieser Lektion
Notiz
Ich kann eine Prüfung aus Addieren, xor und Subtrahieren rückwärts auflösen.
Schlüsselwörter
| Begriff | Was er bedeutet | Beispiel |
|---|---|---|
| Konstante | eine feste Zahl im Befehl | 0x19 |
| Hexadezimal | ein Zahlensystem mit 16 Ziffern, geschrieben mit 0x davor | 0x2b |
| xor | verknüpft zwei Zahlen Bit für Bit, gleiche Bits ergeben 0 | |
| Umkehrung | der Rechenschritt, der einen anderen aufhebt | |
| Zielwert | die Zahl, mit der die Prüfung am Ende vergleicht | |
| Überlauf | eine 32-Bit-Zahl beginnt nach 4294967295 wieder bei 0 |
Die Zellen, die Lernende ausfüllen, bleiben in dieser Vorschau leer.
Ein Programm prüft eine Zahl in drei Schritten
Das Programm zahl bekommt eine Zahl und rechnet damit: erst xor mit einer Zahl, dann plus, dann minus. Ist das Ergebnis der Zielwert, sagt es „Zahl stimmt“.
Die vier Zahlen stehen beim Bauen in der Befehlszeile. So kann eine Lehrkraft jedem Studierenden ein anderes Programm geben. Danach löschen Sie wieder den Quelltext.
Den Übungsordner anlegen, falls er fehlt
mkdir -p ~/uebungHier angezeigt, nicht ausgeführt. Erstellen Sie ein kostenloses Konto, um „Ausführen“ zu drücken und ihn im Terminal Ihres eigenen Labs einzugeben.
In den Übungsordner wechseln
cd ~/uebungHier angezeigt, nicht ausgeführt. Erstellen Sie ein kostenloses Konto, um „Ausführen“ zu drücken und ihn im Terminal Ihres eigenen Labs einzugeben.
Den Quelltext von zahl schreiben
printf '%s\n' '#include <stdio.h>' '#include <stdlib.h>' 'static int pruefe(unsigned n) {' ' unsigned x = n;' ' x = x ^ MASKE;' ' x = x + PLUS;' ' x = x - MINUS;' ' return x == ZIEL;' '}' 'int main(int argc, char **argv) {' ' if (argc != 2) {' ' puts("Aufruf: zahl ZAHL");' ' return 2;' ' }' ' if (pruefe((unsigned)strtoul(argv[1], 0, 10))) {' ' puts("Zahl stimmt.");' ' return 0;' ' }' ' puts("Zahl stimmt nicht.");' ' return 1;' '}' > zahl.cHier angezeigt, nicht ausgeführt. Erstellen Sie ein kostenloses Konto, um „Ausführen“ zu drücken und ihn im Terminal Ihres eigenen Labs einzugeben.
Das Programm mit vier Zahlen bauen
gcc -O0 -no-pie -fno-stack-protector -DMASKE=43 -DPLUS=25 -DMINUS=9 -DZIEL=1000 -o zahl zahl.cHier angezeigt, nicht ausgeführt. Erstellen Sie ein kostenloses Konto, um „Ausführen“ zu drücken und ihn im Terminal Ihres eigenen Labs einzugeben.
Den Quelltext löschen
rm zahl.cHier angezeigt, nicht ausgeführt. Erstellen Sie ein kostenloses Konto, um „Ausführen“ zu drücken und ihn im Terminal Ihres eigenen Labs einzugeben.
Jeder Rechenschritt wird ein Befehl
Der Compiler macht aus jeder Zeile x = x ^ … einen Befehl: xor, add oder sub. Die Zahl steht als Konstante im Befehl, meist hexadezimal geschrieben.
Die Funktion heißt pruefe. Lesen Sie ihre Befehle mit objdump. Das grep behält die Zeilen mit Befehlen. Achten Sie auf xor, add, sub und das cmp am Ende.
Die Befehle der Funktion pruefe ansehen
objdump -d -M intel --no-show-raw-insn --disassemble=pruefe zahl | grep '^ 'Hier angezeigt, nicht ausgeführt. Erstellen Sie ein kostenloses Konto, um „Ausführen“ zu drücken und ihn im Terminal Ihres eigenen Labs einzugeben.
Beispiel: Befehl, hexadezimale Zahl und Schritt
| Befehl | Zahl im Befehl | Der Schritt |
|---|---|---|
| xor …,0x2b | 0x2b ist 43 | x wird mit 43 xor verknüpft |
| add …,0x19 | 0x19 ist 25 | x wird um 25 größer |
| sub …,0x9 | 0x9 ist 9 | x wird um 9 kleiner |
| cmp …,0x3e8 | 0x3e8 ist 1000 | Vergleich mit dem Zielwert |
Die Zellen, die Lernende ausfüllen, bleiben in dieser Vorschau leer.
Eine hexadezimale Zahl umrechnen
echo $((0x3e8))Hier angezeigt, nicht ausgeführt. Erstellen Sie ein kostenloses Konto, um „Ausführen“ zu drücken und ihn im Terminal Ihres eigenen Labs einzugeben.
Rückwärts rechnen heißt: letzten Schritt zuerst aufheben
Das Programm rechnet xor, dann plus, dann minus. Sie beginnen beim Zielwert und heben die Schritte in umgekehrter Reihenfolge auf: erst das Minus, dann das Plus, zuletzt das xor.
Ein Plus hebt ein Minus auf, und umgekehrt. Ein xor mit derselben Zahl hebt sich selbst auf.
Beispiel: vom Zielwert 1000 zurück zur Zahl
| Schritt zurück | Rechnung | Ergebnis |
|---|---|---|
| Start beim Zielwert | 1000 | 1000 |
| sub 9 aufheben | 1000 + 9 | 1009 |
| add 25 aufheben | 1009 - 25 | 984 |
| xor 43 aufheben | 984 xor 43 | 1011 |
Die Zellen, die Lernende ausfüllen, bleiben in dieser Vorschau leer.
Den Rückweg in der Shell rechnen
echo $(( ((1000 + 9) - 25) ^ 43 ))Hier angezeigt, nicht ausgeführt. Erstellen Sie ein kostenloses Konto, um „Ausführen“ zu drücken und ihn im Terminal Ihres eigenen Labs einzugeben.
Die gefundene Zahl ausprobieren
./zahl 1011Hier 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 rechnen die Schritte in derselben Reihenfolge zurück, in der das Programm sie ausführt. Das ergibt eine falsche Zahl. Das Programm hat zuletzt subtrahiert, also müssen Sie zuerst addieren. Heben Sie die Schritte von unten nach oben auf.
Eine 32-Bit-Zahl läuft über
Zahlen im Prozessor haben 32 Bit. Die größte ist 4294967295, danach beginnt sie wieder bei 0. Zieht ein Programm von einer kleinen Zahl etwas Größeres ab, kommt eine sehr große Zahl heraus.
Beim Zurückrechnen gilt dasselbe. Python rechnet mit dem Rest nach 4294967296, damit das Ergebnis im Bereich bleibt.
Null minus eins mit 32 Bit
echo $(( (0 - 1) & 4294967295 ))Hier angezeigt, nicht ausgeführt. Erstellen Sie ein kostenloses Konto, um „Ausführen“ zu drücken und ihn im Terminal Ihres eigenen Labs einzugeben.
Weiterführend
Bauen Sie zahl neu, mit anderen Zahlen als -DMASKE, -DPLUS, -DMINUS und -DZIEL. Lesen Sie die vier Konstanten aus objdump, rechnen Sie die Zahl zurück und prüfen Sie sie mit ./zahl.
Die Programme des Labs lesen Sie später auf dieselbe Weise. Dort stehen Ihnen die Zahlen nicht in der Befehlszeile zur Verfügung.