add esp,4



  • Wir haben in der Vorlesung Rechnerarchitektur mit Assembler begonnen. Dort haben wir ein erstes Programm geschrieben:

    global main
    extern printf
    
    segment .data:
    message: db 'Hallo Welt', 10, 0
    
    segment .text:
    push message
    call printf
    add esp,4
    ret
    

    (Ich hoffe, ich habe das nun richtig reproduziert.)
    Nun, was macht add esp,4 ? Der Prof. hat es zwar erklärt, jedoch war das nicht sonderlich verständlich. Kann mir das hier einer näher bringen?



  • Beim Push wird ein Wert auf die aktuelle Stackadresse geschrieben und der Stackpointer weiter geschoben (Stack wächst nach unten), damit der nächste Wert dahinter landet. Mit dem add wird der Stackpointer wieder zurück geschoben, damit der Wert beim nächsten Push überschrieben wird. Es ist praktisch also ein entfernen des Wertes vom Stack ohne das du den Wert ausliest, wie es beim Pop geschehen würde.



  • Das heißt, rein theoretisch könnte ich das auch weglassen, solange sich Stack und Heap nicht treffen?



  • CrispyTurtleAlligator schrieb:

    Das heißt, rein theoretisch könnte ich das auch weglassen, solange sich Stack und Heap nicht treffen?

    Der Bereich für den Stack wird üblicherweise vom Betriebssystem begrenzt (zwischen 1-12 MB am PC schon alles gesehen), das du dort vorher schon Probleme bekommst. Ansonsten geht in so einem Minimalbeispiel natürlich nichts kaputt, aber ein Stück Code sollte schon das wegräumen was es belegt hat und nicht annehmen das der Rest des Programms schon nicht zu viel belegen wird.



  • CrispyTurtleAlligator schrieb:

    push message
    call printf
    add esp,4
    ret
    

    Das hat etwas mit sogenannten "calling conventions" zu tun. Hier handelt es sich um CDECL, die übliche calling convention für C (16-bit und 32-bit, 64-bit benutzt eine andere calling convention).

    Der C-Aufruf würde folgendermaßen aussehen:

    printf(&message);
    

    Das Argument landet auf dem Stack ( push message ), wo es von printf erwartet und verarbeitet wird. printf räumt den Stack aber nicht auf, d.h. wenn printf zurückkehrt, ist das Argument immer noch auf dem Stack. Das würde aber** ret **durcheinanderbringen, da es auf dem Stack eine Rücksprungadresse und kein Argument erwartet. Deshalb muss der Stack zurückgestellt werden, so dass ret wieder die Rücksprungadresse zu sehen bekommt ( add esp,4 ).

    Es gibt Tricks, die Aufräumerei wegzulassen, von denen ein Compiler im Optimierungsmodus ausgiebig Gebrauch macht. Wichtig ist aber, dass der Stack auf die richtigen Werte zeigt, wenn es z.B. für ret benötigt wird.

    viele grüße
    ralph



  • CrispyTurtleAlligator schrieb:

    Nun, was macht add esp,4 ? Der Prof. hat es zwar erklärt, jedoch war das nicht sonderlich verständlich. Kann mir das hier einer näher bringen?

    Probieren geht über Studieren. Kennst du das Märchen von Hänsel und Gretel?
    Mit push und pop kann man z.B. Registerwerte retten und refreshen, mit mit den beiden (amtlichen) Hardware-Stack-Pointern esp (Gretel) und ebp (Hänsel) Ausgänge sichern und Brotkrumen verteilen UND der Hexe in den Hintern treten (Programme abstürzen lassen/nicht abstürzen lassen).
    (das Märchen passt nicht ganz genau, es ist ja Hänsel, der nicht zu dick werden darf - das ist aber erstmal egal.)

    http://download-mirror.savannah.gnu.org/releases//pgubook/ProgrammingGroundUp-1-0-booksize.pdf ist ein hilfreicher Text in diesem Zusammenhang.



  • Also, ich hätte ja eher an den Fischer und seine Frau gedacht:

    Kompje, Kompje, Timpe Tack,
    Intje, Intje in dem Stack,
    Mine Reg, der E-es-pill,
    Will nich so, as ik wol will.

    viele grüße
    ralph



  • Auch nicht schlecht.
    Aber das mit dem Gretel/esp passt u.a. gut weil Frauen ja gerne schlanker sein wollen, als sie tatsächlich sind.


Anmelden zum Antworten