feat(setjmp): x86_64 setjmp/longjmp/sigsetjmp

This commit is contained in:
2026-09-03 17:39:20 -04:00
parent dec1017527
commit b2d588885e
6 changed files with 684 additions and 0 deletions
+117
View File
@@ -0,0 +1,117 @@
#ifndef VLIBC_SETJMP_H
#define VLIBC_SETJMP_H
/*
* vlibc — <setjmp.h>.
*
* Non-local jumps. setjmp(env) saves the calling environment and returns 0;
* longjmp(env, val) makes that setjmp return val, with 0 coerced to 1 so the
* two returns are distinguishable. sigsetjmp/siglongjmp additionally save and
* restore the signal mask when the buffer's saved-mask flag is set.
*
* jmp_buf is an array type (C23 7.13.1 requires it); both types below are
* arrays of unsigned long. The word layout is ABI: the x86_64 assembly in
* src/setjmp/x86_64/{setjmp,longjmp,sigsetjmp,siglongjmp}.s reads and writes
* exactly these slots. This comment is the single authoritative map — keep it
* and those files in sync:
*
* [0] rbx callee-saved general registers (System V AMD64 ABI)
* [1] rbp
* [2] r12
* [3] r13
* [4] r14
* [5] r15
* [6] rsp the caller's stack pointer (just past the return address)
* [7] rip the return address, where longjmp resumes execution
* [8] mxcsr SSE control/status register (stmxcsr/ldmxcsr)
* [9] x87 cw x87 control word (fnstcw/fldcw)
*
* sigjmp_buf extends the base layout with two more words:
*
* [10] saved-mask flag (1 when the signal mask was saved)
* [11] signal mask (the x86_64 Linux sigset_t: a single 64-bit word)
*
* Because the base layout occupies words 0..9 of both types, the plain
* setjmp/longjmp assembly works verbatim on sigjmp_buf storage as well.
*/
#include <vlibc/features.h>
#ifdef __cplusplus
extern "C" {
#endif
/* Word counts and per-slot indices (see the authoritative map above). */
#define VLIBC_JMP_BUF_WORDS 10
#define VLIBC_JMP_RBX 0
#define VLIBC_JMP_RBP 1
#define VLIBC_JMP_R12 2
#define VLIBC_JMP_R13 3
#define VLIBC_JMP_R14 4
#define VLIBC_JMP_R15 5
#define VLIBC_JMP_RSP 6
#define VLIBC_JMP_RIP 7
#define VLIBC_JMP_MXCSR 8
#define VLIBC_JMP_X87CW 9
#define VLIBC_SIGJMP_BUF_WORDS 12
#define VLIBC_SIGJMP_FLAG 10
#define VLIBC_SIGJMP_MASK 11
typedef unsigned long jmp_buf[VLIBC_JMP_BUF_WORDS];
typedef unsigned long sigjmp_buf[VLIBC_SIGJMP_BUF_WORDS];
/*
* Save the calling environment and return 0; after longjmp(env, val) the
* matching setjmp invocation returns val. A macro (C23 7.13.1: usable without
* a prototype in scope); it expands to _setjmp(env).
*/
#define setjmp(env) _setjmp(env)
/*
* Like setjmp, plus the current signal mask is saved into env when savemask is
* nonzero (siglongjmp then restores it). Macro expanding to
* __sigsetjmp(env, savemask).
*/
#define sigsetjmp(env, savemask) __sigsetjmp(env, savemask)
/*
* The save behind the setjmp macro; identical semantics (POSIX _setjmp).
*/
int
_setjmp(jmp_buf env); // NOLINT(bugprone-reserved-identifier)
/*
* Restore the environment saved by _setjmp/setjmp and make it return val, with
* 0 coerced to 1. Does not return.
*/
__attribute__((noreturn)) void
_longjmp(jmp_buf env, int val); // NOLINT(bugprone-reserved-identifier)
/*
* ISO C longjmp: same as _longjmp.
*/
__attribute__((noreturn)) void
longjmp(jmp_buf env, int val);
/*
* The save behind the sigsetjmp macro. Implementation-reserved name, so the
* public API keeps only the macro; declared because the macro expansion must
* have a prototype in scope (C23 removed implicit declarations).
*/
int
__sigsetjmp(sigjmp_buf env, int savemask); // NOLINT(bugprone-reserved-identifier)
/*
* Restore the environment saved by sigsetjmp and make it return val, with 0
* coerced to 1; when the buffer's saved-mask flag is set, the signal mask is
* restored first. Does not return.
*/
__attribute__((noreturn)) void
siglongjmp(sigjmp_buf env, int val);
#ifdef __cplusplus
}
#endif
#endif /* VLIBC_SETJMP_H */