Skip to content

Commit

Permalink
Move shadow space reservation to x86_64 makecontext
Browse files Browse the repository at this point in the history
The shadow space (or home space) is a requirement of the x64 call
convention: we must reserve 32 bytes before the return address on the
stack. It only applies to x64, not to arm64 for example.

We don't have to deal with this when creating the stack. This is a
consideration for each individual `makecontext` to handle.
  • Loading branch information
ysbaddaden committed Feb 7, 2025
1 parent 8823b75 commit b680987
Show file tree
Hide file tree
Showing 2 changed files with 6 additions and 17 deletions.
18 changes: 3 additions & 15 deletions src/fiber.cr
Original file line number Diff line number Diff line change
Expand Up @@ -108,21 +108,9 @@ class Fiber

fiber_main = ->(f : Fiber) { f.run }

# FIXME: This line shouldn't be necessary (#7975)
stack_ptr = nil
{% if flag?(:win32) %}
# align stack bottom to 16 bytes
@stack_bottom = Pointer(Void).new(@stack_bottom.address & ~0x0f_u64)

# It's the caller's responsibility to allocate 32 bytes of "shadow space" on the stack right
# before calling the function (regardless of the actual number of parameters used)

stack_ptr = @stack_bottom - sizeof(Void*) * 6
{% else %}
# point to first addressable pointer on the stack (@stack_bottom points past
# the stack because the stack grows down):
stack_ptr = @stack_bottom - sizeof(Void*)
{% end %}
# point to first addressable pointer on the stack (@stack_bottom points past
# the stack because the stack grows down):
stack_ptr = @stack_bottom - sizeof(Void*)

# align the stack pointer to 16 bytes:
stack_ptr = Pointer(Void*).new(stack_ptr.address & ~0x0f_u64)
Expand Down
5 changes: 3 additions & 2 deletions src/fiber/context/x86_64-microsoft.cr
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,15 @@ class Fiber
# A great explanation on stack contexts for win32:
# https://web.archive.org/web/20220527113808/https://cfsamson.gitbook.io/green-threads-explained-in-200-lines-of-rust/supporting-windows

# 8 registers + 3 qwords for NT_TIB + 1 parameter + 10 128bit XMM registers
@context.stack_top = (stack_ptr - (12 + 10*2)).as(Void*)
# 4 shadow space + (8 registers + 3 qwords for NT_TIB + 1 parameter) + 10 128bit XMM registers
@context.stack_top = (stack_ptr - (4 + 12 + 10*2)).as(Void*)
@context.resumable = 1

# actual stack top, not including guard pages and reserved pages
LibC.GetNativeSystemInfo(out system_info)
stack_top = @stack_bottom - system_info.dwPageSize

stack_ptr -= 4 # shadow space (or home space) before return address
stack_ptr[0] = fiber_main.pointer # %rbx: Initial `resume` will `ret` to this address
stack_ptr[-1] = self.as(Void*) # %rcx: puts `self` as first argument for `fiber_main`

Expand Down

0 comments on commit b680987

Please sign in to comment.