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.
Unterprogramm/Stack - Aufgaben
Oh Man, diese Aufgabe find ich echt hart, vor allem wenn man vom Assembler in die Hochsprche übersetzen muss. Hoffe es hat schon jemand gemacht…
In Übungen hatten wir so nen Zeug, aber ich hab leider so gut wie gar nix verstanden. :vogel:
Der untenstehende Code wurde von einem Compiler aus einem Hochsprachen-Code generiert. Wie
könnte die ursprüngliche Hochsprachen-Funktion ausgesehen haben?
func:
subl $24,%esp
pushl %ebx
movl 32(%esp),%ebx
cmpl $1,%ebx
jle .L3
addl $-12,%esp
leal -1(%ebx),%eax
pushl %eax
call func
imull %eax,%ebx
movl %ebx,%eax
addl $16,%esp
jmp .L2
.L3:
movl $1,%eax
.L2:
popl %ebx
addl $24,%esp
ret
Ach du Schande, das ist ja der blanke Horror! Unübersichtlicher geht’s wirklich nicht mehr. In der Klausur bräuchte ich für sowas eine ganze Menge Schmierpapier und viel Zeit.
Nach unzähligen Hirnverknotungen sieht mein Ergebnis dafür dann um so einfacher aus:
int func(int a)
{
if (a <= 1) {
return 1;
} else {
return a * func(a - 1);
}
}
Sieht mir stark nach einer rekursiven Funktion zur Fakultätsberechnung aus.
Mal schauen, ob ich das Ganze noch etwas aufschlüsseln kann:
// So heißt die Funktion nun mal.
func:
// Aus irgendeinem Grund wird hier der Stack-Pointer dekrementiert. Das wird ganz unten aber wieder rückgängig gemacht.
subl $24,%esp
// Wir holen uns das Argument der Funktion ins Register %ebx.
// Da wir rekursiv arbeiten, müssen wir davor dessen aktuellen Inhalt auf dem Stack sichern.
pushl %ebx
movl 32(%esp),%ebx
// Wir vergleichen das Argument mit 1. Wenn es kleiner gleich 1 ist, springen wir nach .L3.
cmpl $1,%ebx
jle .L3
// Ansonsten geht es hier weiter.
// Wir pfuschen nochmal mit dem Stack-Pointer rum. Das wird aber ein Stück weiter unten auch wieder rückgängig gemacht.
addl $-12,%esp
// Wir verringern den Wert des Arguments mit leal um 1.
// Das Ergebnis wird (als Funktionsargument) auf den Stack gepusht und die Funktion rekursiv aufgerufen.
leal -1(%ebx),%eax
pushl %eax
call func
// Wir setzen als Rückgabewert dieser Funktion das Produkt aus der Rückgabe des Funktionsaufrufs und dem ursprünglichen Argument.
imull %eax,%ebx
movl %ebx,%eax
// Wir räumen den Stack wieder auf und springen ans Ende der Funktion.
addl $16,%esp
jmp .L2
// Hier kommen wir hin, falls die obige Abbruchbedingung erfüllt ist.
.L3:
// Wir setzen 1 als Rückgabewert dieser Funktion.
movl $1,%eax
// Funktionsende. Hier wird noch ein bisschen aufgeräumt.
.L2:
// Wir schreiben den vorhin auf den Stack gesicherten Inhalt von %ebx zurück ins Register.
popl %ebx
// Wir räumen den Stack auf und springen dann dorthin zurück, von wo die Funktion aufgerufen wurde.
addl $24,%esp
ret
Das wird bestimmt a) zur Verwirrung oder für’s korrekte Alignment auf dem Stack gemacht.
Also ich kann keinen Sinn darin erkennen, dass man auf dem Stack ein paar ungenutzte Bytes einfügt. Mit Alignment kann das nichts zu tun haben, denn wenn der Stack-Pointer vorher nicht durch 4 teilbar war, wird er es nach dem Subtrahieren von 24 bzw. 12 auch nicht sein.
Ich finde es recht irritierend, dass bei jedem rekursiven Abstieg 24 + 12 Bytes einfach so in den Sand gesetzt werden. Bei der Fakultätsberechnung für sehr große Zahlen wird man da wohl recht schnell an die Grenzen des Stacks stoßen.
Hm, da ist schon was dran - aber schau dir mal den Assemblercode der Mainmethode an.
Wo finde ich den?
Schreib ein Programm in C.
gcc -S main.c
Ach so - ich hab gedacht, die [m]main()[/m]-Funktion wäre auch noch irgendwo angegeben.
Wie man den [m]gcc[/m] bedient, ist mir klar. :finger: Schließlich ist mein Rechner seit inzwischen 12 Stunden damit beschäftigt, das gesamte System neu zu bauen, nachdem Gentoo heute endlich den gcc-4.1.1 als stabil erklärt hat!
[offtopic]
Pah, boeses neues Gentoo, ipw3945 auf der LiveCD wurde auf die release 2007.x verschoben, weil die Probleme beim bauen hatten.
[/offtopic]
:*)
Ich lasse meine Pakete bauen - nur ausgewählte Sachen werden selbstkompiliert. Und dann knallehart mit O3.
Vielen Dank dir ,Airhardt für viel mühe und ausführliche erklärung, ich weiss das zu schätzen !