Good C style is that every function that accepts a callback should also accept an opaque context pointer it then passes through unchanged to the callback. Usually the caller will allocate a structure on the stack or the heap, stash some of its local variables there, then use them in the callback. A nested function does the structure back-and-forth for you in the stack-allocated case. In GCC’s original formulation it also passes the context pointer implicitly
size_t filter(bool (*predicate)(int), int *p, size_t n) {
for (size_t r = 0, w = 0; r < n; r++) {
if (predicate(p[r])) p[w++] = p[r];
}
return w;
}
size_t lowpass(int limit, int *p, size_t n) {
bool lower(int value) {
return value < limit; // use the parent's local variable
}
return filter(lower, p, n);
}
but that requires an executable stack and TFA is about avoiding that.
Nested functions have a different ABI from regular C functions, due to the invisible static chain register that needs to be set up. C has no way of indicating this different ABI, so GCC happily lets you cast a nested function to a C function pointer by creating a little tiny function that puts the right value in the static chain register before calling the nested function. This little tiny function is the trampoline.
Since the trampoline needs to live somewhere, GCC puts it on the stack, requiring the stack to be executable and consequently a whole lot of people hate the feature because it's a walking security nightmare.
Could be a number of things depending on context. In this case it’s a short function that adjusts some things and jumps to the actual functions (a “thunk” is another term for this). Specifically, if in GCC you write
int f(int x) {
int g(int y) { ... use x and y ... }
...
h(&g);
...
}
then what the compiled code for f does is construct on the stack a short piece of machine code:
mov <well-known register>, <frame pointer>
jmp <start of g’s code>
and &g points to the start not of g’s code but of this snippet on the stack, which has the parent function’s frame pointer compiled into it as a literal constant. The snippet is called a trampoline.
What about your older patch where -fno-trampolines meant a function pointer could either be a code pointer or a closure (descriptor) pointer, distinguished by a tag?
Pascal supports it (at least Turbo Pascal, no idea about ISO Pascal).
Nested functions have a different ABI from regular C functions, due to the invisible static chain register that needs to be set up. C has no way of indicating this different ABI, so GCC happily lets you cast a nested function to a C function pointer by creating a little tiny function that puts the right value in the static chain register before calling the nested function. This little tiny function is the trampoline.
Since the trampoline needs to live somewhere, GCC puts it on the stack, requiring the stack to be executable and consequently a whole lot of people hate the feature because it's a walking security nightmare.
But I prefer this approach anyhow, as it does not impose any run-time cost for checking the tag, and is easier to optimize.