Skip to content

Commit 1ed5320

Browse files
committed
Setup unwinder for JIT functions
This is not a general solution. It works while all the JIT-ed functions have the same "fixed stack frame". Unwinder uses hard-coded unwind data this "fixed dtack frame".
1 parent 8c69cf0 commit 1ed5320

File tree

1 file changed

+61
-0
lines changed

1 file changed

+61
-0
lines changed

ext/opcache/jit/zend_jit_ir.c

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3213,6 +3213,63 @@ static zend_never_inline void zend_jit_set_sp_adj_vm(void)
32133213
}
32143214
#endif
32153215

3216+
#ifdef _WIN64
3217+
/*
3218+
* We use a single unwind entry for the whole JIT buffer.
3219+
* This works, because all the JIT-ed PHP functions have the same "fixed stack frame".
3220+
*/
3221+
static PRUNTIME_FUNCTION zend_jit_uw_func = NULL;
3222+
3223+
#ifdef ZEND_JIT_RT_UNWINDER
3224+
static PRUNTIME_FUNCTION zend_jit_unwind_callback(DWORD64 pc, PVOID context)
3225+
{
3226+
return zend_jit_uw_func;
3227+
}
3228+
#endif
3229+
3230+
static void zend_jit_setup_unwinder(void)
3231+
{
3232+
/* Hardcoded SEH unwinf data for JIT-ed PHP functions with "fixed stack frame" */
3233+
static const unsigned char uw_data[] = {
3234+
0x01, // UBYTE: 3 Version , UBYTE: 5 Flags
3235+
0x10, // UBYTE Size of prolog
3236+
0x09, // UBYTE Count of unwind codes
3237+
0x00, // UBYTE: 4 Frame Register, UBYTE: 4 Frame Register offset (scaled)
3238+
// USHORT * n Unwind codes array
3239+
0x10, 0x82, // c: subq $0x48, %rsp
3240+
0x0c, 0xf0, // a: pushq %r15
3241+
0x0a, 0xe0, // 8: pushq %r14
3242+
0x08, 0xd0, // 6: pushq %r13
3243+
0x06, 0xc0, // 4: pushq %r12
3244+
0x04, 0x70, // 3: pushq %rdi
3245+
0x03, 0x60, // 2: pushq %rsi
3246+
0x02, 0x50, // 1: pushq %rbp
3247+
0x01, 0x30, // 0: pushq %rbx
3248+
};
3249+
3250+
zend_jit_uw_func = (PRUNTIME_FUNCTION)*dasm_ptr;
3251+
*dasm_ptr = (char*)*dasm_ptr + ZEND_MM_ALIGNED_SIZE_EX(sizeof(RUNTIME_FUNCTION) + sizeof(uw_data), 16);
3252+
3253+
zend_jit_uw_func->BeginAddress = 0;
3254+
zend_jit_uw_func->EndAddress = (uintptr_t)dasm_end - (uintptr_t)dasm_buf;
3255+
zend_jit_uw_func->UnwindData = (uintptr_t)zend_jit_uw_func + sizeof(RUNTIME_FUNCTION) - (uintptr_t)dasm_buf;
3256+
memcpy((char*)zend_jit_uw_func + sizeof(RUNTIME_FUNCTION), uw_data, sizeof(uw_data));
3257+
3258+
#ifdef ZEND_JIT_RT_UNWINDER
3259+
RtlInstallFunctionTableCallback(
3260+
(uintptr_t)dasm_buf | 3,
3261+
(uintptr_t) dasm_buf,
3262+
(uintptr_t)dasm_end - (uintptr_t)dasm_buf,
3263+
zend_jit_unwind_callback,
3264+
NULL,
3265+
NULL);
3266+
#else
3267+
RtlAddFunctionTable(zend_jit_uw_func, 1, (uintptr_t)dasm_buf);
3268+
#endif
3269+
}
3270+
#endif
3271+
3272+
32163273
static void zend_jit_setup(void)
32173274
{
32183275
#if defined(IR_TARGET_X86)
@@ -3420,6 +3477,10 @@ static void zend_jit_setup(void)
34203477
zend_jit_calc_trace_prologue_size();
34213478
zend_jit_setup_stubs();
34223479
JIT_G(debug) = debug;
3480+
3481+
#ifdef _WIN64
3482+
zend_jit_setup_unwinder();
3483+
#endif
34233484
}
34243485

34253486
static void zend_jit_shutdown_ir(void)

0 commit comments

Comments
 (0)