Unterprogramme

Disclaimer: Dieser Thread wurde aus dem alten Forum importiert. Daher werden eventuell nicht alle Formatierungen richtig angezeigt. Der ursprüngliche Thread beginnt im zweiten Post dieses Threads.

Unterprogramme
hoi,

also ich hab hier bei dem code etwas probleme(S.127):

pushl %ebp 
movl %esp, %ebp 
subl $4, %esp 
...
pushl -4(%ebp)
pushl -4(%ebp) 
call proc
addl $8, %esp
...
movl %ebp, %esp 
popl %ebp
ret

kann mir das mal wer vielleicht schrittweise erklären? weil ich z.b. net weiss für was das pushl am anfang sein soll, und wieso man den stack pointer dann um vier verschiebt (speicher reserviert…)

thx

Drager


So wie ich das verstanden hab müsste das so gehn…

//sicher den Framepointer auf dem Stack, schau mal auf S.128 dann siehst du warum
pushl %ebp 
//sicher die Stackadresse(wo die Variablen liegen werden) auf dem Framepointer
movl %esp, %ebp 
//reservier Platz auf dem Stack für die long int x
subl $4, %esp 
...
//proc(x,x) braucht ja 2 mal die Variable x, also wird x 2 mal auf den Stack gepusht(Variablen an proc übergeben)
pushl -4(%ebp)
pushl -4(%ebp) 
//proc normal aufrufen
call proc
//bei rückkehr die übergebenen Variablen wieder "löschen"/freigeben
addl $8, %esp
...
//ursprüngliche Adresse wieder auf den Stackpointer kopieren
movl %ebp, %esp 
//Framepointer vom Stack löschen, Unterprogramm ist ja fertig
popl %ebp
ret

… also ohne Gewähr, aber das klingt logisch für mich :smiley:


hab den satz gefunden für i386:

ansonsten hab ich das gleiche problem :smiley:


hey danke für die erklärung! so langsam hats dadurch bei mir auch gedämmert!


oki danke,

und ist dann das pushl des %ebp “nur” für debug informationen gut?


glaub schon, nen anderen sinn seh ich nicht …und der gcc gibt mir teilweise recht…
hab ne fakultätsfunktion mal mit der option -fomit-frame-pointer(was wohl unnötigen debug code raushaut) in assembler umgewandelt und es sind ein paar pushl %ebp verschwunden … das in der .main ist immer noch da aber ich werte das jetzt trotzdem mal als Bestätigung und was der GCC so ausspuckt is eh manchmal strange :anx:
besonders witzig wirds bei gcc -S -g bla.c :smiley:


hm ich hab mir das nochmal durch den kopf gehn lassen, brauch ich das push und pop von &ebp nicht auch dafür um den alten rücksprung wert wieder zubekommen , wenn ich aus nem unterprogramm zurück komme? weil ich doch im unterprogramm den %ebp überschreiben habe…(mit dem rücksprung wertes des unterprogrammes)

also wenn ich mehrer unterprogramme ineinander schachtle…


Laut meinem Script ist das eher so:
Nachdem sich der Stackpointer bekanntlich bei jedem push/pop ändert, müsste man bei wiederholtem Zugriff z.B. auf die übergebenen Variablen an das Unterprogramm auf dem Stack immer verschiedene Kalkulationen anführen.

Um das zu Vermeiden, gibt es den Framepointer, der zu Beginn des Unterprogramms den Stackpointer sichert. Über den Framepointer kann man dann egal wieviel man gepoppt hat [tm] immer wieder mit dem gleichen Displacement auf die entspr. Variablen zugreifen.

Natürlich ist das auch für Debug-Zwecke sinnvoll, da man den Frame-Pointer zurückverfolgen kann und so weiter.

Im Allgemeinen ist der Framepointer als redundant anzusehen, aber auch als sehr praktisch, spätestens wenn man den Code per Hand schreibt.

Natürlich muss für die Verschachtelung von Unterprogrammen der Framepointer am Anfang gepusht und am ende gepopt werden, was ja auch in dem Beispiel der Fall ist.

cu
Ford Prefect


ich wuerd gern noch wissen warum man im Framepointer Beispiel nur 4 bytes reserviert und dann 8 wieder freigibt? der macht doch “subl $4, %esp”

kann mir das jemand mal erklaeren? ansonsten waere mir das prinzip der benutzung schon klar…


2 pushl rückgängig machen, oder?


ja, aber ich dachte man muss genausoviel allokieren (mindestens) wie man freigibt???


der macht da nur seine eigenen Variablen wieder runter, die er übergeben bekommen hat(anders gesagt, ich glaube, das ist nur von der Unterfunktion)
das Var x freigeben ist wahrscheinlich irgendwo in den Punkten versteckt :o)


ja ich glaub auch das der nur die übergebenen freigibt… x könnte er ja noch in der funktion selbst verweden… aber muss ich das x wirklich freigeben? ich spring doch eh wieder auf den anfang (movl %ebp %esp) zurück dadurch ist es doch eh weg oder?


da hast du ziemlich recht glaub ich… das man sowas nicht gleich selber sieht…


Hallo Welt!

Also ich habe eines noch nicht verstanden - und zwar: Skript Seite 119:

weshalb wird beim Unterprogrammaufruf “substract”, um auf z zuzugreifen, 4(%esp) angegeben, und um auf y zuzugreifen 8(%esp)? Ich verstehe das nicht. Der Stackpointer müsste doch eigentlich aktuell auf y zeigen, sodass die zugriffe so erfolgen müssten: y=(%esp), z=4(%esp).
Also nach “movl y, -(%esp)” müsste der Stackpointer auf den Wert von y aufm Stak zeigen…
Wo wird denn der stackpointer im Hauptprogramm nochmal um 4 runtergesetzt, sodass auf diese Weise ein Displacement von 4 bzw. 8 zustande kommt?

Ich hab das ganze auch selber nochmal geschrieben und als assembler-Code übersetzen lassen - da ist es aber genau wie im skript. Also habe eindeutig ich nen denkfehler.

Vielen Dank
Gruß, Marco


Du darfst die Ruecksprungadresse (beim ‘call subtract’ gesetzt) nicht vergessen. :slight_smile:


ah ok… und das geschieht implizit … ja verdammt… sänks