Bitte um Erläuterung für diese Disassemblierung
-
Hallo allerseits
Ich habe ein kleines C-Programm geschrieben und es mit dem gdb disassembliert. Im Grunde kann ich das meiste von diesem Code nachvollziehen aber manches ist mir noch unklar. Hier erstmal die Disassemblierung:Dump of assembler code for function main: 0x08048424 <+0>: push ebp 0x08048425 <+1>: mov ebp,esp 0x08048427 <+3>: and esp,0xfffffff0 0x0804842a <+6>: sub esp,0x20 0x0804842d <+9>: mov DWORD PTR [esp+0x1c],0x0 0x08048435 <+17>: mov DWORD PTR [esp+0x18],0x5 0x0804843d <+25>: mov DWORD PTR [esp+0x1c],0x6 0x08048445 <+33>: mov eax,0x8048540 0x0804844a <+38>: mov edx,DWORD PTR [esp+0x1c] 0x0804844e <+42>: mov DWORD PTR [esp+0x8],edx 0x08048452 <+46>: mov edx,DWORD PTR [esp+0x18] 0x08048456 <+50>: mov DWORD PTR [esp+0x4],edx 0x0804845a <+54>: mov DWORD PTR [esp],eax 0x0804845d <+57>: call 0x8048354 <printf@plt> 0x08048462 <+62>: leave 0x08048463 <+63>: ret
So wass machenv die Zeilen 1-4. Ich weiß nur das es etwas mit dem Stack und dem Basepointer zu tun hat. Hoffe mir kann das einer in 2-3 Sätzer erklären
-
ASSA schrieb:
So wass machenv die Zeilen 1-4. Ich weiß nur das es etwas mit dem Stack und dem Basepointer zu tun hat. Hoffe mir kann das einer in 2-3 Sätzer erklären
Zuerst wird der frame pointer (EBP) eingerichtet und anschließend 32 Byte mit einem alignment von 16 (and esp,-16) auf dem stack reserviert (sub esp,0x20).
-
Dump of assembler code for function main: 0x08048424 <+0>: push ebp //alten Basepointer sichern 0x08048425 <+1>: mov ebp,esp //meinen Basepointer auf den Stackpointer setzen //Ab jetzt könnte ich alle meine lokalen Variablen anhand relativ zum ebp angeben. //Aber ich benutze hier keine lokalen Variablen... 0x08048427 <+3>: and esp,0xfffffff0 //auf 16 alignen durch bis zu 15 Bytes Verschwendung 0x0804842a <+6>: sub esp,0x20 //32 Bytes Platz machen für Funktionsargumente 0x0804842d <+9>: mov DWORD PTR [esp+0x1c],0x0 //Diese Argumente auf den Stack schreiben 0x08048435 <+17>: mov DWORD PTR [esp+0x18],0x5 //Statt einzeln zu pushen 0x0804843d <+25>: mov DWORD PTR [esp+0x1c],0x6 0x08048445 <+33>: mov eax,0x8048540 0x0804844a <+38>: mov edx,DWORD PTR [esp+0x1c] 0x0804844e <+42>: mov DWORD PTR [esp+0x8],edx 0x08048452 <+46>: mov edx,DWORD PTR [esp+0x18] 0x08048456 <+50>: mov DWORD PTR [esp+0x4],edx 0x0804845a <+54>: mov DWORD PTR [esp],eax 0x0804845d <+57>: call 0x8048354 <printf@plt> //printf aufrufen 0x08048462 <+62>: leave //macht mov esp,ebp; pop ebp //Also alle loaklen Variablen wegschmeißen und den esp und den ebp dahinstellen, wo er bei Funktionseintritt war. 0x08048463 <+63>: ret
-
Das ist die übliche Parameterübergabeprozedur an Unterprogramme über den Stack bei Hochsprachen.
Schön erklärtAllerdings kommt mir das ganze Prozedere immer irgendwie ein wenig redundant vor, das hin und herkopiere im Speicher - müsste vielleicht gar nicht immer sein, und das ein oder andere proggi wäre eventuell leichter lesbar (wo bin ich denn nun gerade genau im Stack???) und so mancher Stackoverflow eingespart...
-
nachtfeuer schrieb:
Allerdings kommt mir das ganze Prozedere immer irgendwie ein wenig redundant vor, das hin und herkopiere im Speicher - müsste vielleicht gar nicht immer sein, und das ein oder andere proggi wäre eventuell leichter lesbar (wo bin ich denn nun gerade genau im Stack???) und so mancher Stackoverflow eingespart...
Genau dafür gibt es doch die Compiler-Optimierungen, als einfachstes Beispiel sei hier Inlining genannt. Ebenso könen durch Optimierungen bspw. Caller-/Callee-Safe Register gespart werden.
Ansonsten ist das ganze nicht so einfach, wenn man sich mal mit der Mikroarchitektur beschäftigt und sieht, wie das in der digitalen Logik dann hinterher auf dem Chip aussieht.