Hier werden die Unterschiede zwischen zwei Versionen gezeigt.
tux:debug_hello_world [2011/10/09 14:30] wikisysop [Disassemble Binary] |
tux:debug_hello_world [2011/10/10 15:13] (aktuell) wikisysop [Disassemble Binary] |
||
---|---|---|---|
Zeile 1: | Zeile 1: | ||
[[:tux|{{ :linux.png?40|}}]] | [[:tux|{{ :linux.png?40|}}]] | ||
- | ===== "Hello, world" im Debugger ===== | + | ===== "Hello World!" im Debugger ===== |
Das Debuggen eines Programms gehört sicherlich zu den anspruchsvollsten Angelegenheiten, kann aber unter gegebenen Umständen äußerst nützlich sein. | Das Debuggen eines Programms gehört sicherlich zu den anspruchsvollsten Angelegenheiten, kann aber unter gegebenen Umständen äußerst nützlich sein. | ||
Zeile 69: | Zeile 69: | ||
End of assembler dump.</xterm> | End of assembler dump.</xterm> | ||
- | <xterm><fc #800000>(gdb)</fc><fc #008000>break main</fc> | + | <xterm><fc #800000>(gdb)</fc> <fc #008000>break main</fc> |
Breakpoint 1 at 0x80483bd: file firstprog.c, line 6.</xterm> | Breakpoint 1 at 0x80483bd: file firstprog.c, line 6.</xterm> | ||
Zeile 166: | Zeile 166: | ||
Nicht weiter von Belang aber die mov-Instruktion möchte die Adresse >><fc #FF00FF>0x80484b0</fc><< dort hin schreiben. Aber warum? Was ist so besonders an der Speicheradresse >><fc #FF00FF>0x80484b0</fc><<? Finden wir es raus und lassen wir uns mal die ersten 8 Byte dieser Adresse anzeigen: | Nicht weiter von Belang aber die mov-Instruktion möchte die Adresse >><fc #FF00FF>0x80484b0</fc><< dort hin schreiben. Aber warum? Was ist so besonders an der Speicheradresse >><fc #FF00FF>0x80484b0</fc><<? Finden wir es raus und lassen wir uns mal die ersten 8 Byte dieser Adresse anzeigen: | ||
- | <xterm><fc #800000>(gdb)</fc> (gdb) <fc #008000>x/8xb 0x80484b0</fc> | + | <xterm><fc #800000>(gdb)</fc> <fc #008000>x/8xb 0x80484b0</fc> |
<fc #FF00FF>0x80484b0</fc>: 0x48 0x65 0x6c 0x6c 0x6f 0x20 0x57 0x6f</xterm> | <fc #FF00FF>0x80484b0</fc>: 0x48 0x65 0x6c 0x6c 0x6f 0x20 0x57 0x6f</xterm> | ||
Zeile 217: | Zeile 217: | ||
0x80483dd <main+41>: jle 0x80483c7 <main+19></xterm> | 0x80483dd <main+41>: jle 0x80483c7 <main+19></xterm> | ||
- | Hier folgt nun der zweite Durchlauf der for()-Schleife im Zusammenhang: | + | Hier folgt nun der zweite Durchlauf der for()-Schleife im Zusammenhang. Die kursiv gestellte >>cmp<<-Instruktion repräsentiert dann bereits den übernächsten Durchlauf der for()-Schleife: |
<xterm><fc #800000>(gdb)</fc> <fc #008000>x/i $eip</fc> | <xterm><fc #800000>(gdb)</fc> <fc #008000>x/i $eip</fc> | ||
Zeile 242: | Zeile 242: | ||
<fc #800000>(gdb)</fc> <fc #008000>x/4xb $esp + 0x1c</fc> | <fc #800000>(gdb)</fc> <fc #008000>x/4xb $esp + 0x1c</fc> | ||
0xbffff6fc: 0x02 0x00 0x00 0x00 | 0xbffff6fc: 0x02 0x00 0x00 0x00 | ||
+ | //<fc #808080>(gdb)x/i $eip | ||
+ | => 0x80483d8 <main+36>: cmp DWORD PTR [esp+0x1c],0x9 | ||
+ | (gdb)</fc>//</xterm> | ||
+ | |||
+ | Schauen wir uns nun noch einmal das gesamte Disassembling an, kann der Verlauf der Schleife bzw. der gesamte Programmverlauf nachvollzogen werden: | ||
+ | |||
+ | <xterm><fc #800000>(gdb)</fc> <fc #008000>disassemble main</fc> | ||
+ | Dump of assembler code for function main: | ||
+ | //0x080483b4 <+0>: push ebp | ||
+ | 0x080483b5 <+1>: mov ebp,esp | ||
+ | 0x080483b7 <+3>: and esp,0xfffffff0 | ||
+ | 0x080483ba <+6>: sub esp,0x20// | ||
+ | <fc #008080>0x080483bd <+9>: mov DWORD PTR [esp+0x1c],0x0</fc> | ||
+ | <fc #FF00FF>0x080483c5 <+17>: jmp 0x80483d8 <main+36></fc> | ||
+ | ⇓ <fc #0000FF>0x080483c7 <+19>: mov DWORD PTR [esp],0x80484b0 | ||
+ | 0x080483ce <+26>: call 0x80482f0 <puts@plt> | ||
+ | 0x080483d3 <+31>: add DWORD PTR [esp+0x1c],0x1 | ||
+ | 0x080483d8 <+36>: cmp DWORD PTR [esp+0x1c],0x9 | ||
+ | 0x080483dd <+41>: jle 0x80483c7 <main+19></fc> | ||
+ | 0x080483df <+43>: leave | ||
+ | 0x080483e0 <+44>: ret | ||
+ | End of assembler dump.</xterm> | ||
+ | |||
+ | Die dunklegrün markierte Zeile mit der ersten >><fc #008080>mov</fc><<-Instruktion initialisiert die Variable >><fc #008080>i</fc><< und belegt diese mit >><fc #008080>0x0</fc><<, die pink markierte Zeile mit der >><fc #FF00FF>jmp</fc><<-Instruktion springt in die Schleife zur >><fc #0000FF>cmp</fc><<-Instruktion und die blau markierten Zeilen repräsentieren die eigentliche >><fc #FF0000>for()</fc><<-Schleife in dem zuerst verglichen wird >><fc #0000FF>cmp</fc><< und solange das Ergebnis dieses Vergleichs ≤ 9 ist >><fc #0000FF>jle</fc><< der Instruktion Pointer >>EIP<< zur zweiten >><fc #0000FF>mov</fc><<-Instruktion springt, wo die Adresse >>0x80484b0<< in >>ESP<< geschrieben wird (Wir erinnern uns, in dieser Adresse ist der String >>"Hello World!<< gespeichert), danach springt >>EIP<< weiter an die nächste Adresse mit der >><fc #0000FF>call</fc><<-Instruktion, welche den in ESP gespeicherten String >>"Hello World!"<< ausgibt. >>EIP<< springt nun weiter zu >><fc #0000FF>add</fc><<-Instruktion, wo >><fc #0000FF>0x1</fc><< zu der Adresse >>[esp+0x1c]<< hinzu addiert wird und der Vergleich dieser Adresse mit ≤ 9 wird erneut durchgeführt. | ||
+ | |||
+ | Der Vollständigkeit wegen sollte noch gezeigt werden, dass die Schleife auch wie vorgesehen verlassen (>><fc #0000FF>leave</fc><<) wird, wenn die Variable >>i<< den Wert >><fc #FF0000>0xa</fc><< (10<sub>10</sub>) erreicht hat: | ||
+ | |||
+ | <xterm><fc #800000>(gdb)</fc> <fc #008000>x/4xb $esp + 0x1c</fc> | ||
+ | 0xbffff6fc: <fc #FF0000>0x0a</fc> 0x00 0x00 0x00 | ||
+ | (gdb) x/i $eip | ||
+ | => 0x80483d8 <main+36>: cmp DWORD PTR [esp+0x1c],0x9 | ||
+ | <fc #800000>(gdb)</fc> nexti | ||
+ | 0x080483dd 6 for(i=0; i < 10; i++) | ||
<fc #800000>(gdb)</fc> <fc #008000>x/i $eip</fc> | <fc #800000>(gdb)</fc> <fc #008000>x/i $eip</fc> | ||
- | <fc #0000FF>=> 0x80483d8 <main+36>: cmp DWORD PTR [esp+0x1c],0x9</fc> | + | => 0x80483dd <main+41>: jle 0x80483c7 <main+19> |
+ | <fc #800000>(gdb)</fc> <fc #008000>nexti</fc> | ||
+ | <fc #0000FF>10 }</fc> | ||
+ | <fc #800000>(gdb)</fc> x/i $eip | ||
+ | => 0x80483df <main+43>: <fc #0000FF>leave</fc> | ||
<fc #800000>(gdb)</fc></xterm> | <fc #800000>(gdb)</fc></xterm> | ||
+ | |||
+ | Mächtig viel Zenober für ein Programm, welches in gerade mal 2 Millisekunden vom Prozessor ausgeführt wird. Ich habe ein ganzes Wochenende mit diesem Artikel verbracht, habe aber viel dabei gelernt ;-) | ||
+ | |||
+ | <xterm>$ <fc #008000>time ./a.out</fc> | ||
+ | Hello World! | ||
+ | Hello World! | ||
+ | Hello World! | ||
+ | Hello World! | ||
+ | Hello World! | ||
+ | Hello World! | ||
+ | Hello World! | ||
+ | Hello World! | ||
+ | Hello World! | ||
+ | Hello World! | ||
+ | |||
+ | real 0m0.002s | ||
+ | user 0m0.000s | ||
+ | sys 0m0.000s</xterm> | ||
+ | |||
+ | --- //pronto 2011/10/09 15:21// |