C Stack



  • Hallo Leute,

    wir nehmen im Studium gerade Stacks und deren Eigenschaften durch. Bisher haben wir alles in Assembler geschrieben und soweit hab ich das auch verstanden. Nur habe ich nun folgenden C Code:

    int main()   {
    	double a, b, c;
    	a = 10;
    	b = 10;
    	F1(a, b);
           return (a);
    }
    
    int F1(double x, double y)  
    {
    	int i[3];
           double n;
    //hier adresse von SBP und SP angeben
    	n = 6.04 * x - 8.5;
    	return (n);
    }
    

    Wir sollen nun den Stackframe nach Aufruf der Funktion F1 zeichnen und Adressen des SBP und des SP wie gefordert angeben.
    Zum SBP:
    die Adresse des PC wird beim Funktionsaufruf in den Stack gespeichert.
    Somit müsste doch auch die Adresse immer noch die gleiche sein wie beim Aufruf oder?

    SP:
    diese müsste eig auf die call adresse bzw Ret Adresse zeigen da Int i[3] und double n keine Werte am Stack speichern odeR?

    Stackframe:
    habe ich absolut keine Ahnung^^ Kann mir nur vorstellen das hier die Rückgabewerte der aufgerufenen Funktion stehen F1+ (x,y)

    Entschuldigt falls ich hier einiges durcheinander bringe. In Assembler war es iwie kla ersichtlicher was gerade auf dem Stack liegt bzw wo der SP gerade hinzeigt.

    Könnte mir jemand weiterhelfen?

    Danke !

    VG
    Daniel



  • nehmen wir an die argumente werden auch über den stack übergeben, dann kommen zuerst rücksprungadresse, x und y auf den stack, bevor die funktion aufgerufen wird. in der funktion kommen noch einmal 3 integer und 1 double auf den stack. der compiler merkt sich das und bevor die funktion verlassen wird, wird der stack wieder bereinigt.

    nachtrag: da i[3] nicht benutzt wird, werden warscheinlich die integer nicht auf dem stack landen. n könnte auch in registern berechnet werden. eventuell kommen nur die return-adresse und die argumente x und y auf den stack.



  • @Bushmaster sagte in C Stack:

    bevor die funktion verlassen wird, wird der stack wieder bereinigt.

    Das mag für Pascal gelten, aber nicht für C.

    In C räumt der Caller den Stack auf, da die Funktion nicht weiß, mit wieviel Parametern sie aufgerufen wurde.



  • @DirkB sagte in C Stack:

    @Bushmaster sagte in C Stack:

    bevor die funktion verlassen wird, wird der stack wieder bereinigt.

    Das mag für Pascal gelten, aber nicht für C.

    In C räumt der Caller den Stack auf, da die Funktion nicht weiß, mit wieviel Parametern sie aufgerufen wurde.

    danke für die berichtigung. die funktion wird aber wohl ihre lokalen variablen von stack nehmen. denn damit hat der caller ja nichts zu tun.



  • @Bushmaster sagte in C Stack:

    die funktion wird aber wohl ihre lokalen variablen von stack nehmen.

    Wie soll sie das denn machen?
    Gelöscht (überschrieben) wird nicht.

    Die Funktion ruft die Rücksprungadresse auf und der Caller setzt den Stack so, wie vor dem Aufruf. Somit sind auch die lokalen Variablen der Funktion ungültig. Die Daten sind aber noch da.



  • @DirkB sagte in C Stack:

    Wie soll sie das denn machen?

    sie setzt den stackpointer wieder auf den wert, wie er beim eintritt in die funktion war. damit sind die lokalen variablen nicht mehr existent.



  • #include <stdio.h>
    
    int F1(double x, double y)  
    {
        int i[3];
        double n;
    
     /*hier adresse von SBP und SP angeben*/
        unsigned ebp,esp;
        asm volatile ("movl %%ebp,%0" : "=r" (ebp));
        asm volatile ("movl %%esp,%0" : "=r" (esp));
        printf("%lX\n%lX",ebp,esp);
    
        n = 6.04 * x - 8.5;
        return (n);
    }
    
    int main()  
    {
        double a, b, c;
        a = 10;
        b = 10;
        F1(a, b);
        return 0;
    }
    

    FF9C28D8
    FF9C28A0

    http://codepad.org/z1BZV02T



  • @Bushmaster sagte in C Stack:

    sie setzt den stackpointer wieder auf den wert, wie er beim eintritt in die funktion war. damit sind die lokalen variablen nicht mehr existent.

    Das ist überflüssig, da das der Caller gleich nochmal macht - für die Funktionsparameter, zudem sind die Daten immer noch da.



  • @DirkB sagte in C Stack:

    Das ist überflüssig, da das der Caller gleich nochmal macht - für die Funktionsparameter, zudem sind die Daten immer noch da.

    ich hab den aufruf mal disassemblen lassen

        F1(a, b);
    00152072  sub         esp,8  
    00152075  movsd       xmm0,mmword ptr [b]  
    0015207A  movsd       mmword ptr [esp],xmm0  
    0015207F  sub         esp,8  
    00152082  movsd       xmm0,mmword ptr [a]  
    00152087  movsd       mmword ptr [esp],xmm0  
    0015208C  call        F1 (015103Ch)  
    00152091  add         esp,10h  
    
    

    die main-funktion tut die beiden doubles auf den stack und, dann die return-adresse (durch den call) und räumt den stack danach mit add esp, 16 wieder auf. falls die andere funktion den esp verändert hat, würde das schief gehen. also geht main davon aus, dass die andere funktion ihren dreck auch wieder weg macht. 🙂



  • @Bushmaster sagte in C Stack:

    also geht main davon aus, dass die andere funktion ihren dreck auch wieder weg macht.

    Danke für die Klarstellung.





  • Hallo zusammen,

    erstmal danke für die Antworten! Hat mich sehr gefreut.

    Zusammengefasst müsste also der Stack nach dem Funktionsaufruf leer sein?
    Danke an @Wutz habe einfach ein paar mehr Ausgaben hinzugefügt:
    http://codepad.org/wmJ3CxxI
    BP und SP zeigen auf die gleichen Adressen wie am Anfang von main.

    BP:
    Zeigt in der geforderten Zeile auf die Return Adresse

    SP:
    Adresse ergibt sich aus den Werten der beiden Double Variablen und dem Call ?

    Sehe ich das so richtig?



  • @sh_run sagte in C Stack:

    Zusammengefasst müsste also der Stack nach dem Funktionsaufruf leer sein?

    Zusammengefasst ist der Stack Pointer nachher wo er vorher war. Wo genau "vorher" und "nachher" ist halt abhängig von der Calling Convention.


Log in to reply