From 7544cfd52831c1f81fd10ceedacb8234b423248f Mon Sep 17 00:00:00 2001 From: deadlynch <20408322+deadlynch@users.noreply.github.com> Date: Thu, 5 Nov 2026 01:07:45 -0300 Subject: [PATCH] Align the stack of Linux fibers to the System V ABI plat_fiber_entry is reached by a ret with rsp at top - 8 and called the fiber function without realigning, so the function started with rsp = 0 mod 16 and every 16-byte local was off by 8. The VEX instructions of a v3 build tolerate that; the SSE ones of a v2 build fault on it, and probe-kernel's fiber test crashed in same_regs on pcmpeqb with a memory operand. plat_fiber_entry now aligns rsp to 16 bytes before the call. Co-Authored-By: Claude Opus 5.5 --- runtime/platform/linux.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/runtime/platform/linux.c b/runtime/platform/linux.c index 1c29cdde..f761968f 100644 --- a/runtime/platform/linux.c +++ b/runtime/platform/linux.c @@ -270,7 +270,8 @@ int plat_intr_resume(PlatIntr *t, uint64_t to) { // ---- fibers: a stack switch of our own. glibc's swapcontext saves and restores the signal mask with a system call // on every switch, and the game switches fibers often. fiber_swap saves the callee-saved registers, the MXCSR and the // x87 control word on the current stack, stores the stack pointer in *save and loads the other one. A new fiber's -// stack is laid out as fiber_swap leaves one, returning into fiber_entry, which calls fn(arg) (r12 and r13). +// stack is laid out as fiber_swap leaves one, returning into fiber_entry, which realigns the stack and calls fn(arg) +// (r12 and r13). struct PlatFiber { void *sp; void *stack; // mapped stack (NULL for a thread's own context) @@ -312,6 +313,11 @@ __asm__(".text\n" ".type plat_fiber_entry, @function\n" ".p2align 4\n" "plat_fiber_entry:\n" + // fiber_swap's ret lands here with rsp = top - 8, as at the entry of a called function. The call below must + // be made with rsp 16-byte aligned so that fn starts with rsp = 8 mod 16, as the System V ABI demands; without + // the realignment every 16-byte local of fn is off by 8, which the VEX instructions of a v3 build tolerate + // but the SSE ones of a v2 or k10 build (movdqa, pcmpeqb with a memory operand) fault on. + " andq $-16, %rsp\n" " movq %r13, %rdi\n" " callq *%r12\n" " ud2\n"