Remix.run Logo
jcranmer 5 hours ago

In this context:

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.

uecker 4 hours ago | parent | next [-]

Correct (although the nightmare part is a bit exaggerated since return-oriented programming showed that non-executable stack does not help a lot). GCC can also put the trampoline on the heap, but this also has downsides.

For me the main downside of trampolines is that the optimizer can not de-virtualize the trampoline again. This could be implemented, but avoiding the creation of the trampoline in the first place is much better.

kccqzy 3 hours ago | parent | prev [-]

C++ solves this problem by simply not allowing a nested function (lambda) to be converted to a function pointer, and thereby avoids this problem of trampolines and executable stack altogether. I think that’s a better design.

uecker 3 hours ago | parent | next [-]

C++ has the same solution as I propose here: A wide function pointer type.

In C++ it is called std::function, but this comes with a bit of baggage. C++ 26 has std::function_ref which would be the exact equivalent to my wide pointer.

https://godbolt.org/z/GaP9jb5rE

jcranmer 3 hours ago | parent | prev [-]

A C++ lambda that doesn't close over anything can be converted to a function pointer: https://eel.is/c++draft/expr.prim.lambda#closure-12 This feature does turn out to be useful if you need to pun a C++ interface into a function pointer for a C ABI function.