Fix coroutine implementaion on Windows-Arm64
When setjmp/longjmp/exceptions are used on Windows it's necessary to store+restore additional information from the TEB.
I didn't find any official documentation about the values to be saved, but found the corresponding boost/context implemenataion:
abf8e04e23
This is similar to the special TIB handling on x86/x86_64 on Windows.
Without this fix an exception in a fiber segfaults without any output:
ruby -e "Fiber.new{ raise 'test' }.resume"
This commit is contained in:
parent
11e120dfce
commit
187b8fdb69
Notes:
git
2024-12-17 00:46:44 +00:00
@ -21,6 +21,13 @@
|
|||||||
# error "-mbranch-protection flag specified b-key but Context.S does not support this"
|
# error "-mbranch-protection flag specified b-key but Context.S does not support this"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined(_WIN32)
|
||||||
|
## Add more space for certain TEB values on each stack
|
||||||
|
#define TEB_OFFSET 0x20
|
||||||
|
#else
|
||||||
|
#define TEB_OFFSET 0x00
|
||||||
|
#endif
|
||||||
|
|
||||||
## NOTE(PAC): Use we HINT mnemonics instead of PAC mnemonics to
|
## NOTE(PAC): Use we HINT mnemonics instead of PAC mnemonics to
|
||||||
## keep compatibility with those assemblers that don't support PAC.
|
## keep compatibility with those assemblers that don't support PAC.
|
||||||
##
|
##
|
||||||
@ -39,19 +46,34 @@ PREFIXED_SYMBOL(coroutine_transfer):
|
|||||||
hint #34
|
hint #34
|
||||||
#endif
|
#endif
|
||||||
# Make space on the stack for caller registers
|
# Make space on the stack for caller registers
|
||||||
sub sp, sp, 0xa0
|
sub sp, sp, 0xa0 + TEB_OFFSET
|
||||||
|
|
||||||
# Save caller registers
|
# Save caller registers
|
||||||
stp d8, d9, [sp, 0x00]
|
stp d8, d9, [sp, 0x00 + TEB_OFFSET]
|
||||||
stp d10, d11, [sp, 0x10]
|
stp d10, d11, [sp, 0x10 + TEB_OFFSET]
|
||||||
stp d12, d13, [sp, 0x20]
|
stp d12, d13, [sp, 0x20 + TEB_OFFSET]
|
||||||
stp d14, d15, [sp, 0x30]
|
stp d14, d15, [sp, 0x30 + TEB_OFFSET]
|
||||||
stp x19, x20, [sp, 0x40]
|
stp x19, x20, [sp, 0x40 + TEB_OFFSET]
|
||||||
stp x21, x22, [sp, 0x50]
|
stp x21, x22, [sp, 0x50 + TEB_OFFSET]
|
||||||
stp x23, x24, [sp, 0x60]
|
stp x23, x24, [sp, 0x60 + TEB_OFFSET]
|
||||||
stp x25, x26, [sp, 0x70]
|
stp x25, x26, [sp, 0x70 + TEB_OFFSET]
|
||||||
stp x27, x28, [sp, 0x80]
|
stp x27, x28, [sp, 0x80 + TEB_OFFSET]
|
||||||
stp x29, x30, [sp, 0x90]
|
stp x29, x30, [sp, 0x90 + TEB_OFFSET]
|
||||||
|
|
||||||
|
#if defined(_WIN32)
|
||||||
|
# Save certain values from Thread Environment Block (TEB)
|
||||||
|
# x18 points to the TEB on Windows
|
||||||
|
# Read TeStackBase and TeStackLimit at ksarm64.h from TEB
|
||||||
|
ldp x5, x6, [x18, #0x08]
|
||||||
|
# Save them
|
||||||
|
stp x5, x6, [sp, #0x00]
|
||||||
|
# Read TeDeallocationStack at ksarm64.h from TEB
|
||||||
|
ldr x5, [x18, #0x1478]
|
||||||
|
# Read TeFiberData at ksarm64.h from TEB
|
||||||
|
ldr x6, [x18, #0x20]
|
||||||
|
# Save current fiber data and deallocation stack
|
||||||
|
stp x5, x6, [sp, #0x10]
|
||||||
|
#endif
|
||||||
|
|
||||||
# Save stack pointer to x0 (first argument)
|
# Save stack pointer to x0 (first argument)
|
||||||
mov x2, sp
|
mov x2, sp
|
||||||
@ -61,20 +83,33 @@ PREFIXED_SYMBOL(coroutine_transfer):
|
|||||||
ldr x3, [x1, 0]
|
ldr x3, [x1, 0]
|
||||||
mov sp, x3
|
mov sp, x3
|
||||||
|
|
||||||
|
#if defined(_WIN32)
|
||||||
|
# Restore stack base and limit
|
||||||
|
ldp x5, x6, [sp, #0x00]
|
||||||
|
# Write TeStackBase and TeStackLimit at ksarm64.h to TEB
|
||||||
|
stp x5, x6, [x18, #0x08]
|
||||||
|
# Restore fiber data and deallocation stack
|
||||||
|
ldp x5, x6, [sp, #0x10]
|
||||||
|
# Write TeDeallocationStack at ksarm64.h to TEB
|
||||||
|
str x5, [x18, #0x1478]
|
||||||
|
# Write TeFiberData at ksarm64.h to TEB
|
||||||
|
str x6, [x18, #0x20]
|
||||||
|
#endif
|
||||||
|
|
||||||
# Restore caller registers
|
# Restore caller registers
|
||||||
ldp d8, d9, [sp, 0x00]
|
ldp d8, d9, [sp, 0x00 + TEB_OFFSET]
|
||||||
ldp d10, d11, [sp, 0x10]
|
ldp d10, d11, [sp, 0x10 + TEB_OFFSET]
|
||||||
ldp d12, d13, [sp, 0x20]
|
ldp d12, d13, [sp, 0x20 + TEB_OFFSET]
|
||||||
ldp d14, d15, [sp, 0x30]
|
ldp d14, d15, [sp, 0x30 + TEB_OFFSET]
|
||||||
ldp x19, x20, [sp, 0x40]
|
ldp x19, x20, [sp, 0x40 + TEB_OFFSET]
|
||||||
ldp x21, x22, [sp, 0x50]
|
ldp x21, x22, [sp, 0x50 + TEB_OFFSET]
|
||||||
ldp x23, x24, [sp, 0x60]
|
ldp x23, x24, [sp, 0x60 + TEB_OFFSET]
|
||||||
ldp x25, x26, [sp, 0x70]
|
ldp x25, x26, [sp, 0x70 + TEB_OFFSET]
|
||||||
ldp x27, x28, [sp, 0x80]
|
ldp x27, x28, [sp, 0x80 + TEB_OFFSET]
|
||||||
ldp x29, x30, [sp, 0x90]
|
ldp x29, x30, [sp, 0x90 + TEB_OFFSET]
|
||||||
|
|
||||||
# Pop stack frame
|
# Pop stack frame
|
||||||
add sp, sp, 0xa0
|
add sp, sp, 0xa0 + TEB_OFFSET
|
||||||
|
|
||||||
#if defined(__ARM_FEATURE_PAC_DEFAULT) && (__ARM_FEATURE_PAC_DEFAULT != 0)
|
#if defined(__ARM_FEATURE_PAC_DEFAULT) && (__ARM_FEATURE_PAC_DEFAULT != 0)
|
||||||
# autiasp: Authenticate x30 (LR) with SP and key A
|
# autiasp: Authenticate x30 (LR) with SP and key A
|
||||||
|
@ -17,7 +17,13 @@
|
|||||||
|
|
||||||
#define COROUTINE __attribute__((noreturn)) void
|
#define COROUTINE __attribute__((noreturn)) void
|
||||||
|
|
||||||
enum {COROUTINE_REGISTERS = 0xa0 / 8};
|
#if defined(_WIN32)
|
||||||
|
#define TEB_OFFSET 0x20
|
||||||
|
#else
|
||||||
|
#define TEB_OFFSET 0x00
|
||||||
|
#endif
|
||||||
|
|
||||||
|
enum {COROUTINE_REGISTERS = (0xa0 + TEB_OFFSET) / 8};
|
||||||
|
|
||||||
#if defined(__SANITIZE_ADDRESS__)
|
#if defined(__SANITIZE_ADDRESS__)
|
||||||
#define COROUTINE_SANITIZE_ADDRESS
|
#define COROUTINE_SANITIZE_ADDRESS
|
||||||
@ -87,7 +93,14 @@ static inline void coroutine_initialize(
|
|||||||
memset(context->stack_pointer, 0, sizeof(void*) * COROUTINE_REGISTERS);
|
memset(context->stack_pointer, 0, sizeof(void*) * COROUTINE_REGISTERS);
|
||||||
|
|
||||||
void *addr = (void*)(uintptr_t)start;
|
void *addr = (void*)(uintptr_t)start;
|
||||||
context->stack_pointer[0x98 / 8] = ptrauth_sign_instruction_addr(addr, (void*)top);
|
context->stack_pointer[(0x98 + TEB_OFFSET) / 8] = ptrauth_sign_instruction_addr(addr, (void*)top);
|
||||||
|
#if defined(_WIN32)
|
||||||
|
// save top address of stack as base in TEB
|
||||||
|
context->stack_pointer[0x00 / 8] = (char*)stack + size;
|
||||||
|
// save botton address of stack as limit and deallocation stack in TEB
|
||||||
|
context->stack_pointer[0x08 / 8] = stack;
|
||||||
|
context->stack_pointer[0x10 / 8] = stack;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
struct coroutine_context * coroutine_transfer(struct coroutine_context * current, struct coroutine_context * target);
|
struct coroutine_context * coroutine_transfer(struct coroutine_context * current, struct coroutine_context * target);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user