From 6d17254ae32a0c872dc2de46af07c35c0bd34515 Mon Sep 17 00:00:00 2001 From: smarm-dev Date: Thu, 28 May 2026 05:50:18 +0000 Subject: [PATCH] docs(context): fix off-by-one-slot error in init_actor_stack layout comment The diagram claimed the entry/ret target sits at aligned_top-8 and r15 at aligned_top-56. The code does (top & ~15) - 8 then a -= 8 before the first write, so entry actually lands at aligned_top-16 and r15 at aligned_top-64. Confirmed by single-stepping the shim's ret under llmdbg: the entry slot is at an address with %16==0, giving the required rsp%16==8 on entry. Code was correct; only the comment was wrong (and would mislead a maintainer). --- src/context.rs | 30 +++++++++++++++++++----------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/src/context.rs b/src/context.rs index 75c2840..cf0ea86 100644 --- a/src/context.rs +++ b/src/context.rs @@ -24,18 +24,26 @@ pub fn set_actor_sp(v: usize) { ACTOR_SP.with(|c| c.set(v)) } // --------------------------------------------------------------------------- // Initial stack layout // -// After alignment, sp = top & ~15 - 8. Then we push (downward) six callee- -// saved register slots and a return address. The first `switch_to_actor` -// pops r15..rbx and `ret`s — landing in `entry` with rsp % 16 == 8. +// We start from aligned_top = top & ~15, then bias by 8 and push seven 8-byte +// slots (downward). The first `switch_to_actor` pops r15..rbx and `ret`s — +// landing in `entry` with rsp % 16 == 8 (the x86-64 ABI state at the point +// just after a `call`, which is what `entry` is compiled to expect). // -// Layout (high → low), relative to aligned_top = top & ~15: -// aligned_top - 8 : entry ptr ← `ret` target. Post-ret: rsp % 16 == 8. -// aligned_top - 16 : rbx = 0 -// aligned_top - 24 : rbp = 0 -// aligned_top - 32 : r12 = 0 -// aligned_top - 40 : r13 = 0 -// aligned_top - 48 : r14 = 0 -// aligned_top - 56 : r15 = 0 ← initial rsp +// Layout (high → low), relative to aligned_top = top & ~15. Note the entry +// slot is at aligned_top - 16, NOT aligned_top - 8: the function does +// `(top & ~15) - 8` and *then* a `-= 8` before the first write, so the first +// stored word lands at aligned_top - 16. Verified by single-stepping the +// `ret` under llmdbg: entry sits at an address with %16 == 0, so the post-ret +// rsp is %16 == 8. +// +// aligned_top - 8 : (unused padding; keeps entry's slot %16 == 0) +// aligned_top - 16 : entry ptr ← `ret` target. Post-ret: rsp % 16 == 8. +// aligned_top - 24 : rbx = 0 +// aligned_top - 32 : rbp = 0 +// aligned_top - 40 : r12 = 0 +// aligned_top - 48 : r13 = 0 +// aligned_top - 56 : r14 = 0 +// aligned_top - 64 : r15 = 0 ← initial rsp // --------------------------------------------------------------------------- pub fn init_actor_stack(top: *mut u8, entry: extern "C-unwind" fn()) -> usize {