Die Ausgangssituation für das Praktikum ist ein rekursives Programm zur Berechnung der Fibonacci-Zahlen von 0 < n <= 5
.
#include <stdio.h>
#include <stdlib.h>
int fib(int n){
if ( n == 0 )
return 0;
else if ( n == 1 )
return 1;
else{
return ( fib(n-1) + fib(n-2) );
}
}
`int main() {
int n, c;
printf("Zahl n:\n");
scanf("%d",&n);
if(n < 0) printf("Nur groesser 0 du depp!\n"); exit(0);
if(n > 5) printf("Nix groesser als 5 du depp und %d ist groesser! ... weiss man doch", n); exit(0);
printf("Ergebnis ist %d!\n",fib(n));
` return 0;
}
Es soll die Aufrufhierarchie des Fibonacci-Programms angezeigt werden. Dafür müssen die folgenden Funktionen in das Programm hinzugefügt werden und das Programm mit -finstrument-functions
kompiliert werden.
void __cyg_profile_func_enter(void *this_fn, void *call_site) __attribute__((no_instrument_function));
void __cyg_profile_func_enter(void *this_fn, void *call_site) {
printf("ENTER: %p(%s) from %p\n", this_fn, __func__, call_site);
}
void __cyg_profile_func_exit(void *this_fn, void *call_site) __attribute__((no_instrument_function));
void __cyg_profile_func_exit(void *this_fn, void *call_site) {
printf("EXIT: %p(%s) from %p\n", this_fn, __func__, call_site);
}
Problem:
Das Problem tritt auf, wenn die Funktions-Prototypen ohne __attribute__((no_instrument_function))
geschrieben werden. Denn wenn die Funktionen ohne __attribute__(...)
deklariert & ausgeführt werden führt das dazu, dass die Funktion __cyg_profile_func_enter()
sich selbst rekursiv aufruft und dabei jedes Mal einen neuen Stack-Eintrag erstellt, solange bis der Stack überläuft (=> Stackoverflow). Die __attribute__()
Funktion ist eine Art Präprozessor-Direktive die vom Compiler interpretiert werden und Compiler-Flags setzen um sein Verhalten zu steuern.
#include <stdio.h>
#include <stdlib.h>
int fib(int n);
void hidden(void);
void __cyg_profile_func_enter(void *this_fn, void *call_site) __attribute__((no_instrument_function));
void __cyg_profile_func_exit(void *this_fn, void *call_site) __attribute__((no_instrument_function));
static void* addrs[10];
void __cyg_profile_func_enter(void *this_fn, void *call_site) {
// if (this_fn == addrs[2]) {
// printf("Target main!\n");
// } else if(fib_call.from >= addrs[2] && fib_call.to == addrs[0]) {
// printf("ENTER FIB: %p from %p\n", fib_call.to, fib_call.from);
// } else if((call_site >= addrs[0] && call_site < addrs[1]) && fib_rec_call.to == addrs[0]) {
// printf("ENTER FIB REC: %p from %p\n", fib_call.to, fib_call.from);
// }else {
// printf("Nope!\n");
// printf("ALLOW %p FROM %p\n", fib_call.to, fib_call.from);
// printf("TRY TO ENTER %p FROM %p\n", this_fn, call_site);
// exit(1);
// }
printf("TRY TO ENTER %p FROM %p\n", this_fn, call_site);
}
void __cyg_profile_func_exit(void *this_fn, void *call_site) {
printf("EXIT: %p,(%s) from %p\n", this_fn, __func__, call_site);
}
int fib(int n){
if ( n == 0 )
return 0;
else if ( n == 1 )
return 1;
else{
return ( fib(n-1) + fib(n-2) );
}
}
void hidden(void){
printf("Ich bin eigentlich geheim! Zieh ab!\n");
}
int main() {
int n, c;
addrs[0] = fib;
addrs[1] = hidden;
addrs[2] = main;
addrs[3] = main + 194; // Next op afterCall of fib in main
printf("Enter the number of terms\n");
scanf("%d",&n);
if(n>5){
printf("Nix groesser als 5 du depp und %d ist groesser... weiss man doch",n);
exit(0);
}
printf("%d\n",fib(n));
return 0;
}