Skip to content
Tech News
← Back to articles

Indirect Calling of Nested Functions on GCC Without Executable Stack

read original more articles
Why This Matters

This article explores a method to support indirect calls to nested functions in GCC without requiring an executable stack, which is crucial for maintaining security and compatibility with older compiler versions. It highlights how trampolines and static chains can be manipulated to enable nested function calls securely, impacting both compiler design and runtime performance. This approach offers developers a way to write safer, more portable code while avoiding potential security vulnerabilities associated with executable stacks.

Key Takeaways

Indirect Calling of Nested Functions on GCC Without Executable Stack

Martin Uecker, 2026-08-29

Introduction

We discussed last time how one can use nested functions on GCC 17 and Clang for callbacks with requiring an executable stack. But what if ones needs to support older versions of GCC? Of course, one can simply accept an executable stack (it is not quite as terrible as some people claim), but it is also possible to avoid this with a hack.

GCC: Nested Functions and Trampolines

Let's discuss first how GCC supports taking the address of a nested function. Our toy example without the use of the new macros is shown below (Godbolt Example).

typedef int cb_f(int y); int baz(cb_f p, int x) { return p(x); } int foo(int k) { int bar(int x) { return k + x; } return baz(bar, 2 * k); }

On x86_64, the generated assembly is the following.

bar.0: movl %edi, %eax addl (%r10), %eax ret foo: subq $56, %rsp leaq 64(%rsp), %rax movq %rax, 32(%rsp) movl %edi, (%rsp) leaq 4(%rsp), %rax movw $-17591, 4(%rsp) movabsq $bar.0, %rcx movq %rcx, 6(%rsp) movw $-17847, 14(%rsp) movq %rsp, 16(%rsp) movl $-1864106167, 24(%rsp) addl %edi, %edi call *%rax addq $56, %rsp ret

... continue reading