Im Folgenden werden wir den Maschinencode betrachten, den der Compiler aus Ihrem Programm erzeugt hat.
Erstellen Sie eine Datei gauss.c mit folgendem Inhalt:
#include <stdio.h>
int main(int argc, char **argv) {
int sum = 0;
for (int i = 1; i <= 100; i++)
sum += i;
printf("sum = %d\n", sum);
return 0;
}
Kompilieren Sie das Programm wie folgt: gcc -o gauss gauss.c
Verwenden Sie nun den Befehl objdump, um den Maschinencode der kompilierten Datei in lesbarer Form anzuzeigen: objdump -d -M intel gauss | less
Sie können die Ansicht von less mit der Taste q beenden. Die Repräsentation der Ausgabe von objdump ist:
<address>: instruction_bytes instruction_mnemonic
Die lesbare Repräsentation des Programms findet sich in instruction_mnemonic.
Suchen Sie in der Ausgabe von objdump (der sogenannten Disassembly) nach der Funktion main. Können Sie die Schleife aus der Hochsprache im Assemblercode lokalisieren?
Die Funktion main sieht wie folgt aus; die Schleife befindet sich zwischen den Adressen 0x670 und 0x67e. Zu erkennen ist diese am Sprung zum Compare und dem bedingten Sprung zurück. Das Programm ist einfacher zu verstehen, wenn man sich klar macht, dass die Variable i an der Adresse rbp-0x4 steht und die Variable sum an der Adresse rbp-0x8.
000000000000064a <main>:
// ...
659: c745f800000000 mov DWORD PTR [rbp-0x8],0x0 // sum = 0
660: c745fc00000000 mov DWORD PTR [rbp-0x4],0x0 // i = 0
667: c745fc01000000 mov DWORD PTR [rbp-0x4],0x1 // i = 1
66e: eb0a jmp 67a <main+0x30> // Sprung zu Vergleich
670: 8b45fc mov eax,DWORD PTR [rbp-0x4] // eax = i
673: 0145f8 add DWORD PTR [rbp-0x8],eax // sum = sum + eax
676: 8345fc01 add DWORD PTR [rbp-0x4],0x1 // i = i + 1
67a: 837dfc64 cmp DWORD PTR [rbp-0x4],0x64 // Vergleich i, 100
67e: 7ef0 jle 670 <main+0x26> // Sprung, wenn i<=100
// ...
69c: c3 ret
Kompilieren Sie Ihr Programm erneut unter der Verwendung der Optionen -O0, -O1 oder -O2. Wie verändert sich die Disassembly?
Bei höheren Optimierungsstufen (GCC unterstüzt die Stufen bis -O3) fällt auf, dass die Schleife nicht mehr existert; sie wurde zur Compile-Zeit berechnet und im Programm durch eine Konstante ersetzt.
Als Vorgriff: Zudem werden nicht alle Variablen ständig auf dem Stack gespeichert und wieder geladen.