Martin Uecker
Blog
Contact/Impressum
Using GCC's Nested Functions with Wide Pointers and no Trampolines II
Martin Uecker, 2026-07-14
Introduction
When the address of a nested function is taken, GCC creates at<br>trampoline at run-time. This trampoline is placed<br>on the stack, which means that the stack has to be executable.<br>This is problematic because a non-executable stack is an important security feature.<br>For some time now, GCC has the option to place the trampoline on the heap,<br>which is better but still not ideal as the allocation has a higher cost and the<br>trampoline could leak when longjmp is used.
Previously, I pointed out how this could be avoided with a new wide pointer<br>type, and also talked about a preliminary patch to GCC that implements<br>some core functionality that would be necessary for this.
Here, I want to give two updates.
GCC 16: Nested Functions Without Capture
First, GCC 16 was released. In GCC 16<br>it is guaranteed that a nested function that does not access variables of<br>a parent function will not require a trampoline. In practice, this was<br>already ensured when optimizing, but now it is also ensured when not<br>optimizing and documented. This also means that you can safely return such a<br>function from its parent and that you will get a warning when trying to return<br>a function that does access the local context (at least in simple<br>cases where this is obvious to the compiler) as in the following example<br>(Godbolt Example)
typedef int cb_f(int);
cb_f *foo(int x)<br>int worker(int y)<br>return x + y; // capture
return worker;
cb_f *bar(int _x)<br>static int x;<br>x = _x;
int worker(int y)<br>return x + y; // no capture
return worker;
Nested function that do not access variables of the parent function<br>can still access static variables, named constants, or types<br>(if not variably modified). This is useful for writing<br>callback functions (Godbolt Example).
typedef int cb_f(void *, int y);
int process(cb_f *cb, void *data)<br>return cb(data, 5);
int foo(int x)<br>struct { int x; } data = { .x = x };
int worker(void *_data, int y)<br>typeof(data) *data = _data;<br>return data->x + y;
return process(worker, &data);
Still, the true power of nested functions is being able to directly<br>access the variables of the parent function. Also, the code above seems<br>like we just simulate such functions by manually adding some boilerplate<br>code - the compiler should certainly be able to help us with this.<br>This is what my second update is about.
GCC 17: Nested Functions with Capture
Recently, a version of<br>my patch was merged into the development branch of GCC that implements<br>the two new built-in functions that can be used together with the existing<br>built-in __builtin_call_with_static_chain to write this<br>example<br>(Godbolt Example)<br>without requiring trampolines.
typedef int cb_f(int y);
static int process(cb_f *cb, void *data)<br>return __builtin_call_with_static_chain(cb(5), data);
int main()<br>int x = 7;
int worker(int y)<br>return x + y;
return process(__builtin_call_code_address(worker),<br>__builtin_call_static_chain(worker));
In fact, with trampolines out of the picture, all that GCC does under<br>the hood is to automatically transform this into the example above!<br>The only difference to the manually written version that the data pointer<br>is passed via a special register. This register is used by many other<br>programming language for passing the static chain and therefor already<br>reserved for this use by the ABI.
Even without proper language support, we can still make this example<br>a bit nicer by defining a generic wide pointer type and wrapping<br>the built-ins via macros.<br>(Godbolt Example)
#define wide(T) struct wide_##T { typeof(T) *code; void *chain; }
typedef int cb_f(int y);
int baz(wide(cb_f) p, int x)<br>return CALL(p, (x));
int foo(int k)<br>int bar(int x) { return k + x; }<br>return baz(CLOSURE(cb_f, bar), 2 * k);
The compiler will happily optimize this to a single assembly instruction<br>that implements a multiplication by three.
foo:<br>lea eax, [rdi+rdi*2]<br>ret
Outlook
While there are compilers other than GCC that support nested functions, this<br>feature is not really portable. In the future, I will discuss how one can use<br>nested functions with both clang and GCC and how one can, with a hack,<br>avoid creating trampolines even on older versions of GCC.
Literature
GCC, GCC 16 Release Series Changes, New Features, and Fixes
GCC, Nested Functions
GCC, Constructing Function Calls