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 {