cpointerstrampolines

using a trampoline with one function as an argument


I know what a trampoline function is, but I've been having trouble avoiding stack overflow using trampolines. So far, the only method I can think of is to use global variables, which are discouraged and can complicate programs.

The trampoline function I want to use is shown below.

void trampoline(void *(*fun)()) {
  while (fun != NULL) {
    void *callback = fun();
    fun = (void *(*)())callback;
  }
}

When I try to pass in functions with parameters, such as those in the code fragment below, I end up creating stacks, which is not what I want. I was wondering if there was a way to use my trampoline function without using global variables or passing in any extra arguments?

void *f1();
void *f2();

void *f1(int *n) {
  if (*n == 0) {
    return NULL;
  } else {
    return f2(n);
  }
}

void *f2(int *n) {
  --*n;
  return f1(n);
}

int main() {
  int a = 1000000;
  trampoline(f1(&a));
  return 0;
}

The program below behaves how I want it to, but it uses a global variable, which is widely discouraged.

#include <stdio.h>
int a = 1000;

void trampoline(void *(*f)()) {
  while (f) {
    void *g = f();
    f = (void *(*)())g;
  }
}

void *f1();
void *f2();

void *f1() {
  if (a == 0) {
    return NULL;
  } else {
    return f2;
  }
}

void *f2() {
  --a;
  return f1;
}

int main() {

  trampoline(f1);
  return 0;
}

Clarification: I do not want to modify the trampoline function above, but I want reduced stack creation.


Solution

  • First probably you mean

    void *f1(int *n) {
      if (*n == 0) {  /* <<< */
        return NULL;
      } else {
        return f2(n);
      }
    }
    

    rather than

    void *f1(int *n) {
      if (n == 0) {
        return NULL;
      } else {
        return f2(n);
      }
    }
    

    Compiling with optimization the compiler will detect the final recursion in both function and the used size of the stack will be constant and not linked with a.

    In fact like that for the compiler you main just does return 0; ;-)

    To hope the calls you can do

    int main(int argc, char ** argv) {
      int a = argc * 1000000;
      trampoline(f1(&a));
      return a;
    }
    

    With your second definition after your edit the compiler cannot optimize replacing all by the right return

    On my PI4 gcc 8.3.0 with the option -O detects the final recursions and the program just uses time to finish, but without a stack overflow


    Note gcc as a special management for the trampoline case, with the dedicated option "-Wtrampoline"