Interesting, m1lkweed, thanks for sharing. I couldn't get it working with
GCC 10 or 12. Maybe I just don't understand how it works, but I don't see
how it even *could* work. Here's my current understanding:
The target of the jump is a thunk, and xjmp_buf is the size of a pointer,
just enough to hold the address of the thunk. The rest of jump context is
therefore embedded at the call site. Clever!
However, you clearly state that it does not require an executable stack,
so then how could the thunk work? When I inspect the xjmp_buf with GDB I
see a stack address for "fun" which makes sense, but that address won't be
executable. My tests crash jumping to this stack address.
Further, since __jmp is defined in that macro-level block scope, isn't it
out of scope and therefore dead before it's used? Even if it works now, it
seems like something that may not work in the future.
xlongjmp is just a function call. It doesn't restore the stack pointer to
the saved value. In the compiled assembly it's just a jmp instruction. Or
worse, if not a tail call then it's compiled as a call. (Marking "fun" as
noreturn should cause it to be a tail call in optimized builds.) I suppose
the xsetjmp thunk could restore the stack pointer when called, and it
could find its closure context using rip-relative addressing (as usual).