Unterschiede

Hier werden die Unterschiede zwischen zwei Versionen gezeigt.

Link zu dieser Vergleichsansicht

tux:debug_hello_world [2011/10/09 14:07]
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 204: Zeile 204:
 => <fc #​FF00FF>​0x80483d3</​fc>​ <​main+31>:​ <​fc #​0000FF>​add ​   DWORD PTR [esp+0x1c],​0x1</​fc></​xterm>​ => <fc #​FF00FF>​0x80483d3</​fc>​ <​main+31>:​ <​fc #​0000FF>​add ​   DWORD PTR [esp+0x1c],​0x1</​fc></​xterm>​
  
-Hier wird der Wert >><​fc #​0000FF>​0x1</​fc><<​ zu dem uns bereits bekannten Wert >>​0x0<<​ in Adresse >><​fc #​0000FF>​[esp+0x1c]</​fc><<​ addiert. Somit wird die letzte Anweisung in der >>​for()<<​-Schleife -> >>​i++<<​ ausgeführt und der Wert >>​i<<​ um >>​1<<​ inkrementiert:​+Hier wird der Wert >><​fc #​0000FF>​0x1</​fc><<​ zu dem uns bereits bekannten Wert >><fc #0000FF>0x0</fc><< in Adresse >><​fc #​0000FF>​[esp+0x1c]</​fc><<​ addiert. Somit wird die letzte Anweisung in der >><fc #FF0000>for()</fc><<​-Schleife -> >><fc #FF0000>i++</fc><< ausgeführt und der Wert >><fc #FF0000>i</fc><< um >><fc #FF0000>1</fc><< inkrementiert:​
  
 <​xterm><​fc #​800000>​(gdb)</​fc>​ <fc #​008000>​nexti</​fc>​ <​xterm><​fc #​800000>​(gdb)</​fc>​ <fc #​008000>​nexti</​fc>​
-0x080483d8 6  ​ for(i=0; i < 10; i++)+0x080483d8 6   ​<fc #FF0000>for(i=0; i < 10; i++)</fc>
 <fc #​800000>​(gdb)</​fc>​ <fc #​008000>​x/​4xb $esp + 0x1c</​fc>​ <fc #​800000>​(gdb)</​fc>​ <fc #​008000>​x/​4xb $esp + 0x1c</​fc>​
 0xbffff6fc:​ <​fc #​0000FF>​0x01</​fc>​ 0x00 0x00 0x00</​xterm>​ 0xbffff6fc:​ <​fc #​0000FF>​0x01</​fc>​ 0x00 0x00 0x00</​xterm>​
 +
 +Der erste Durchlauf der >><​fc #​FF0000>​for()</​fc><<​-Schleife ist nun abgeschlossen und der Befehlszeiger springt zur nächsten Adresse, welche wieder die >><​fc #​0000FF>​cmp</​fc><<​-Instruktion enthält und einen neuen Durchlauf der >><​fc #​FF0000>​for()</​fc><<​-Schleife anstößt. Dieses ganze Prozedere wiederholt sich nun solange, wie der Wert >><​fc #​FF0000>​i</​fc><<​ in Adresse >><​fc #​FF00FF>​$esp + 0x1c</​fc><<​ ≤ <fc #​FF0000>​9</​fc>​ ist.
 +
 +<​xterm><​fc #​800000>​(gdb</​fc>​) <fc #​008000>​x/​2i $eip</​fc>​
 +=> 0x80483d8 <​main+36>:​ <​fc #​0000FF>​cmp ​   DWORD PTR [esp+0x1c],​0x9</​fc>​
 +   ​0x80483dd <​main+41>:​ jle ​   0x80483c7 <​main+19></​xterm>​
 +   
 +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>​
 +<fc #​0000FF>​=>​ 0x80483d8 <​main+36>:​ cmp ​   DWORD PTR [esp+0x1c],​0x9</​fc>​
 +<fc #​800000>​(gdb)</​fc>​ <fc #​008000>​nexti</​fc>​
 +0x080483dd 6  ​ for(i=0; i < 10; i++)
 +<fc #​800000>​(gdb)</​fc>​ <fc #​008000>​x/​i $eip</​fc>​
 +<fc #​0000FF>​=>​ 0x80483dd <​main+41>:​ jle ​   0x80483c7 <​main+19></​fc>​
 +<fc #​800000>​(gdb)</​fc>​ <fc #​008000>​nexti</​fc>​
 +8     printf("​Hello World!\n"​);​
 +<fc #​800000>​(gdb)</​fc>​ <fc #​008000>​x/​i $eip</​fc>​
 +<fc #​0000FF>​=>​ 0x80483c7 <​main+19>:​ mov ​   DWORD PTR [esp],​0x80484b0</​fc>​
 +<fc #​800000>​(gdb)</​fc>​ <fc #​008000>​nexti</​fc>​
 +0x080483ce 8  ​   printf("​Hello World!\n"​);​
 +<fc #​800000>​(gdb)</​fc>​ <fc #​008000>​x/​i $eip</​fc>​
 +<fc #​0000FF>​=>​ 0x80483ce <​main+26>:​ call ​  ​0x80482f0 <​puts@plt></​fc>​
 +<fc #​800000>​(gdb)</​fc>​ <fc #​008000>​nexti</​fc>​
 +Hello World!
 +6   for(i=0; i < 10; i++)
 +<fc #​800000>​(gdb)</​fc>​ <fc #​008000>​x/​i $eip</​fc>​
 +<fc #​0000FF>​=>​ 0x80483d3 <​main+31>:​ add ​   DWORD PTR [esp+0x1c],​0x1</​fc>​
 +<fc #​800000>​(gdb)</​fc>​ <fc #​008000>​nexti</​fc>​
 +0x080483d8 6  ​ for(i=0; i < 10; i++)
 +<fc #​800000>​(gdb)</​fc>​ <fc #​008000>​x/​4xb $esp + 0x1c</​fc>​
 +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>​
 +=> 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>​
 +
 +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//
tux/debug_hello_world.1318162057.txt.gz (9545 views) · Zuletzt geändert: 2011/10/09 14:07 von wikisysop
CC Attribution-Share Alike 3.0 Unported
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0