Trampoline (computer science)

from Wikipedia, the free encyclopedia

A trampoline is a piece of program code that jumps to another function after configuring environment variables. A trampoline serves as a stepping stone to access other functions. This is particularly useful if you want to pass parameters that cannot be found in the signature of the function.

motivation

In the C language , the function can be qsortused to sort fields of data. qsorthas the following signature:

 void qsort(void *feld,
            size_t elementzahl,
            size_t elementgroesse,
            int(*vergleichsfunktion)(const void *a, const void *b));

A field as a pointer, the number of elements in the field, the size of each element in bytes and a comparison function are transferred to the function. The comparison function receives two pointers to the elements to be compared ( aand b) as an argument and returns a value less than zero for a < b, zero for a == band a value greater than zero for the case a > b.

Suppose you want to write a function that unsigned intsorts an array of unsigned integers first according to their remainder with respect to a fixed divisor and then according to their size. If the divisor is a fixed constant DIVISORthen the function is modsorteasy to implement:

#include <stdlib.h>

/* Hilfsfunktion zum Vergleich */
static int modvergleich(unsigned int *a, unsigned int *b) {
  unsigned int rest_a = a % DIVISOR, rest_b = b % DIVISOR;

  /* nach Rest sortieren, dann nach Wert sortieren */
  if (rest_a != rest_b) {
    if (rest_a > rest_b)
      return 1;
    else
      return -1;
  } else {
    if (a == b) return 0;
    else if (a > b) return 1;
    else return -1;
  }
}

/* eigentliche Sortierfunktion */
void modsort(unsigned int *feld, size_t elementzahl) {
  qsort(feld,elementzahl,sizeof(unsigned int),&modvergleich);
}

But what do you do if DIVISORit is only known at runtime? You could use a global variable here, but this is a problem especially with parallel code: Another thread could overwrite the variable and thus falsify the results ( this can be solved with modern compiler extensions such as thread-local storage ). So what do you do? This is where trampolines come into play: The address of a trampoline calculated at runtime is transferred to the function qsort. This fills in the divisor as an additional argument and thus allows a solution to the problem.

Use of trampolines

As a rule, trampolines are not used directly because most languages ​​do not provide direct support for them. GCC has a language extension for the C language that allows nested functions , i.e. function definitions in other function definitions. If you request a pointer to an inner function, gcc generates a trampoline on the stack:

#include <stdlib.h>

/* Sortierfunktion mit Extra-Divisor */
void modsort2(unsigned int *feld, size_t elementzahl, unsigned int divisor) {
  int modvergleich(unsigned int *a, unsigned int *b) {
    unsigned int rest_a = a % divisor, rest_b = b % divisor;

    /* nach Rest sortieren, dann nach Wert sortieren */
    if (rest_a != rest_b) {
      if (rest_a > rest_b)
        return 1;
      else
        return -1;
    } else {
      if (a == b) return 0;
      else if (a > b) return 1;
      else return -1;
    }
  }

  qsort(feld,elementzahl,sizeof(unsigned int),&modvergleich);
}

Trampolines can also be created on other memory areas that are writable and executable. This does not have to be the case at the same time; the storage attributes can be switched between creating and executing if necessary. Harvard architectures , as is typical in microcontrollers , cannot be used for trampolines.

The dynamic generation of machine code requires bits of processor-specific source code if this is not built into the (processor-specific) compiler.

safety

Trampolines do not in themselves pose any safety problems. However, if the compiler automatically generates these as described above, it is necessary to allow code to be executed on the stack. This is possibly a security risk because you have to deactivate mechanisms that otherwise prohibit the normally undesired execution of code from the stack.

Modern APIs avoid the compulsion to use trampolines or thread-local variables by providing a data pointer with each function pointer. However, “lugging around” such data pointers makes such APIs a bit unwieldy.

With object-oriented programming languages , abstract or polymorphic objects can be defined in a simple and secure way , which can be processed individually using bound but overwritable methods in a comparable way, but depending on the data types used.

Individual evidence

  1. Question on the topic of "Implementation of nested functions" on Stack Overflow. Retrieved May 20, 2012 .