[PATCH 0/3] MR9666: ntdll: Rewrite arm64 packed unwind info handling.
Instead of trying to handcraft all the cases for dealing with partial prologues, just synthesize the full unwind info for the function and execute that instead. The packed unwind info format always maps to a combination of regular unwind opcodes. This is how the arm packed unwind info implementation works already; this makes it easier to reason about compared with the handwritten code for dealing with partial prologues. The previous implementation is certainly faster and more efficient, but much harder to reason about, and to modify. Additionally, add testcases for more coverage, and fix another corner case in the handling of packed unwind info. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/9666
From: Martin Storsjö <martin(a)martin.st> We previously lacked a testcase for RegI > 3, which uses a save_regp unwind opcode, which none of the existing packed unwind info tests contain. --- dlls/ntdll/tests/unwind.c | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/dlls/ntdll/tests/unwind.c b/dlls/ntdll/tests/unwind.c index 727cbb08b12..fc658541b11 100644 --- a/dlls/ntdll/tests/unwind.c +++ b/dlls/ntdll/tests/unwind.c @@ -2673,6 +2673,38 @@ static void test_virtual_unwind_arm64(void) { 0x2c, 0x00, 0, ORIG_LR, 0x000, TRUE, { {-1,-1} }}, }; + static const BYTE function_21[] = + { + 0xf3, 0x53, 0xbe, 0xa9, /* 00: stp x19, x20, [sp, #-32]! */ + 0xf5, 0x5b, 0x01, 0xa9, /* 04: stp x21, x22, [sp, #16] */ + 0x1f, 0x20, 0x03, 0xd5, /* 08: nop */ + 0xf5, 0x5b, 0x41, 0xa9, /* 0c: ldp x21, x22, [sp, #16] */ + 0xf3, 0x53, 0xc2, 0xa8, /* 10: ldp x19, x20, [sp], #32 */ + 0xc0, 0x03, 0x5f, 0xd6, /* 14: ret */ + }; + + static const DWORD unwind_info_21_packed = + (1 << 0) | /* Flag */ + (sizeof(function_21)/4 << 2) | /* FunctionLength */ + (0 << 13) | /* RegF */ + (4 << 16) | /* RegI */ + (0 << 20) | /* H */ + (0 << 21) | /* CR */ + (2 << 23); /* FrameSize */ + + static const BYTE unwind_info_21[] = { DW(unwind_info_21_packed) }; + + static const struct results_arm64 results_21[] = + { + /* offset fp handler pc frame offset registers */ + { 0x00, 0x00, 0, ORIG_LR, 0x000, TRUE, { {-1,-1} }}, + { 0x04, 0x00, 0, ORIG_LR, 0x020, TRUE, { {x19,0x00}, {x20,0x08}, {-1,-1} }}, + { 0x08, 0x00, 0, ORIG_LR, 0x020, TRUE, { {x19,0x00}, {x20,0x08}, {x21, 0x10}, {x22, 0x18}, {-1,-1} }}, + { 0x0c, 0x00, 0, ORIG_LR, 0x020, TRUE, { {x19,0x00}, {x20,0x08}, {x21, 0x10}, {x22, 0x18}, {-1,-1} }}, + { 0x10, 0x00, 0, ORIG_LR, 0x020, TRUE, { {x19,0x00}, {x20,0x08}, {-1,-1} }}, + { 0x14, 0x00, 0, ORIG_LR, 0x000, TRUE, { {-1,-1} }}, + }; + static const struct unwind_test_arm64 tests[] = { #define TEST(func, unwind, size, results, unwound_clear, last_ptr, stack_value_index, stack_value) \ @@ -2698,6 +2730,7 @@ static void test_virtual_unwind_arm64(void) TEST(function_18, NULL, 0, results_18, 0, 0, -1, 0), TEST(function_19, unwind_info_19, 0, results_19, 0, 0, -1, 0), TEST(function_20, unwind_info_20, 0, results_20, 0, 0, -1, 0), + TEST(function_21, unwind_info_21, 0, results_21, 0, 0, -1, 0), #undef TEST }; unsigned int i; -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/9666
From: Martin Storsjö <martin(a)martin.st> Instead of trying to handcraft all the cases for dealing with partial prologues, just synthesize the full unwind info for the function and execute that instead. The packed unwind info format always maps to a combination of regular unwind opcodes. This is how the arm packed unwind info implementation works already; this makes it easier to reason about compared with the handwritten code for dealing with partial prologues. The previous implementation is certainly faster and more efficient, but much harder to reason about, and to modify. --- dlls/ntdll/unwind.c | 204 +++++++++++++++++++++----------------------- 1 file changed, 96 insertions(+), 108 deletions(-) diff --git a/dlls/ntdll/unwind.c b/dlls/ntdll/unwind.c index c897a9a97e1..0f8942c20b0 100644 --- a/dlls/ntdll/unwind.c +++ b/dlls/ntdll/unwind.c @@ -523,9 +523,12 @@ static void *unwind_packed_data( ULONG_PTR base, ULONG_PTR pc, ARM64_RUNTIME_FUN ARM64_NT_CONTEXT *context, KNONVOLATILE_CONTEXT_POINTERS_ARM64 *ptrs ) { int i; - unsigned int len, offset, skip = 0; - unsigned int int_size = func->RegI * 8, fp_size = func->RegF * 8, h_size = func->H * 4, regsave, local_size; - unsigned int int_regs, fp_regs, saved_regs, local_size_regs; + unsigned int len, offset; + unsigned int int_size = func->RegI * 8, fp_size = func->RegF * 8, regsave, local_size; + unsigned int int_regs, fp_regs, saved_regs; + BYTE prologue[40], *prologue_end, epilogue[40], *epilogue_end; + unsigned int ppos = 0, epos = 0; + BOOLEAN final_pc_from_lr; TRACE( "function %I64x-%I64x: len=%#x flag=%x regF=%u regI=%u H=%u CR=%u frame=%x\n", base + func->BeginAddress, base + func->BeginAddress + func->FunctionLength * 4, @@ -540,138 +543,123 @@ static void *unwind_packed_data( ULONG_PTR base, ULONG_PTR pc, ARM64_RUNTIME_FUN int_regs = int_size / 8; fp_regs = fp_size / 8; saved_regs = regsave / 8; - local_size_regs = local_size / 8; - /* check for prolog/epilog */ - if (func->Flag == 1) + offset = ((pc - base) - func->BeginAddress) / 4; + + /* Synthesize prologue opcodes */ +#define WRITE_ONE(x) do { prologue[ppos++] = epilogue[epos++] = (x); } while (0) +#define WRITE_TWO(x) do { WRITE_ONE((x) >> 8); WRITE_ONE((x) & 0xff); } while (0) + if (func->CR == 2 || func->CR == 3) { - offset = ((pc - base) - func->BeginAddress) / 4; - if (offset < 17 || offset >= func->FunctionLength - 15) + WRITE_ONE(0xe1); /* set_fp */ + if (local_size <= 512) { - len = (int_size + 8) / 16 + (fp_size + 8) / 16; - switch (func->CR) - { - case 2: - len++; /* pacibsp */ - /* fall through */ - case 3: - len++; /* mov x29,sp */ - len++; /* stp x29,lr,[sp,0] */ - if (local_size <= 512) break; - /* fall through */ - case 0: - case 1: - if (local_size) len++; /* sub sp,sp,#local_size */ - if (local_size > 4088) len++; /* sub sp,sp,#4088 */ - if (func->RegI == 1 && func->CR == 1) len++; /* sub sp,sp,#regsave */ - break; - } - if (offset < len + h_size) /* prolog */ - { - skip = len + h_size - offset; - } - else if (offset >= func->FunctionLength - (len + 1)) /* epilog */ - { - skip = offset - (func->FunctionLength - (len + 1)); - h_size = 0; - } + WRITE_ONE(0x80 | (local_size/8 - 1)); /* save_fplr_x */ + } + else + { + WRITE_ONE(0x40); /* save_fplr */ } } - - if (!skip) + if ((func->CR <= 1 && local_size > 0) || local_size > 512) { - if (func->CR == 3 || func->CR == 2) + if (local_size <= 512) { - /* mov x29,sp */ - context->Sp = context->Fp; - restore_regs( 29, 2, 0, context, ptrs ); + WRITE_ONE(local_size/16); /* alloc_s */ + } + else if (local_size <= 4080) + { + WRITE_TWO(0xc000 | (local_size/16)); /* alloc_m */ + } + else + { + WRITE_ONE((local_size - 4080)/16); /* alloc_s */ + WRITE_TWO(0xc000 | (4080/16)); /* alloc_m */ } - context->Sp += local_size; - if (fp_size) restore_fpregs( 8, fp_regs, int_regs, context, ptrs ); - if (func->CR == 1) restore_regs( 30, 1, int_regs - 1, context, ptrs ); - restore_regs( 19, func->RegI, -saved_regs, context, ptrs ); } - else + if (func->H) { - unsigned int pos = 0; - - switch (func->CR) + prologue[ppos++] = 0xe3; /* nop */ + prologue[ppos++] = 0xe3; /* nop */ + prologue[ppos++] = 0xe3; /* nop */ + prologue[ppos++] = 0xe3; /* nop */ + } + if (func->RegF > 0) + { + if (func->RegF % 2 == 0) { - case 3: - case 2: - /* mov x29,sp */ - if (pos++ >= skip) context->Sp = context->Fp; - if (local_size <= 512) - { - /* stp x29,lr,[sp,-#local_size]! */ - if (pos++ >= skip) restore_regs( 29, 2, -local_size_regs, context, ptrs ); - break; - } - /* stp x29,lr,[sp,0] */ - if (pos++ >= skip) restore_regs( 29, 2, 0, context, ptrs ); - /* fall through */ - case 0: - case 1: - if (!local_size) break; - /* sub sp,sp,#local_size */ - if (pos++ >= skip) context->Sp += (local_size - 1) % 4088 + 1; - if (local_size > 4088 && pos++ >= skip) context->Sp += 4088; - break; + WRITE_TWO(0xdc00 | ((func->RegF) << 6) | (int_regs + fp_regs - 1)); /* save_freg */ } - - pos += h_size; - - if (fp_size) + for (i = (func->RegF + 1) / 2 - 1; i >= 0; i--) { - if (func->RegF % 2 == 0 && pos++ >= skip) - /* str d%u,[sp,#fp_size] */ - restore_fpregs( 8 + func->RegF, 1, int_regs + fp_regs - 1, context, ptrs ); - for (i = (func->RegF + 1) / 2 - 1; i >= 0; i--) - { - if (pos++ < skip) continue; - if (!i && !int_size) - /* stp d8,d9,[sp,-#regsave]! */ - restore_fpregs( 8, 2, -saved_regs, context, ptrs ); - else - /* stp dn,dn+1,[sp,#offset] */ - restore_fpregs( 8 + 2 * i, 2, int_regs + 2 * i, context, ptrs ); - } + if (!i && !int_size) + WRITE_TWO(0xda00 | ((0) << 6) | (saved_regs - 1)); /* save_fregp_x */ + else + WRITE_TWO(0xd800 | ((2*i) << 6) | (int_regs + 2*i)); /* save_fregp d(8+2*i), int_regs + 2*i */ } - + } + if (func->CR == 1 && func->RegI % 2 == 0) + { + if (func->RegI == 0) + WRITE_TWO(0xd400 | ((30 - 19) << 5) | (saved_regs - 1)); /* save_reg_x x30 */ + else + WRITE_TWO(0xd000 | ((30 - 19) << 6) | (int_regs - 1)); /* save_reg x30 */ + } + if (func->RegI > 0) + { if (func->RegI % 2) { - if (pos++ >= skip) + if (func->CR == 1) { - /* stp xn,lr,[sp,#offset] */ - if (func->CR == 1) restore_regs( 30, 1, int_regs - 1, context, ptrs ); - /* str xn,[sp,#offset] */ - restore_regs( 18 + func->RegI, 1, - (func->RegI > 1 || func->CR == 1) ? func->RegI - 1 : -saved_regs, - context, ptrs ); + WRITE_TWO(0xd600 | ((func->RegI - 1)/2) << 6 | (int_regs - 2)); /* save_lrpair x(19+RegI-1), (int_regs-2) */ + if (func->RegI == 1) + WRITE_ONE(saved_regs/2); /* alloc_s */ } - if (func->CR == 1 && func->RegI == 1) + else { - if (pos++ >= skip) context->Sp += regsave; + if (func->RegI == 1) + WRITE_TWO(0xd400 | ((0) << 5) | (saved_regs - 1)); /* save_reg_x x19 */ + else + WRITE_TWO(0xd000 | ((int_regs - 1) << 6) | (int_regs - 1)); /* save_reg x(19+int_regs-1) */ } } - else if (func->CR == 1) - { - /* str lr,[sp,#offset] */ - if (pos++ >= skip) restore_regs( 30, 1, func->RegI ? int_regs - 1 : -saved_regs, context, ptrs ); - } - for (i = func->RegI / 2 - 1; i >= 0; i--) { - if (pos++ < skip) continue; if (i) - /* stp xn,xn+1,[sp,#offset] */ - restore_regs( 19 + 2 * i, 2, 2 * i, context, ptrs ); + WRITE_TWO(0xc800 | ((2*i) << 6) | (2*i)); /* save_regp x(19+2*i), 2*i */ else - /* stp x19,x20,[sp,-#regsave]! */ - restore_regs( 19, 2, -saved_regs, context, ptrs ); + WRITE_TWO(0xcc00 | ((0) << 6) | (saved_regs - 1)); /* save_regp_x x19, saved_regs */ + } + } + if (func->CR == 2) + WRITE_ONE(0xfc); /* pac_sign_lr */ + WRITE_ONE(0xe4); /* end */ + prologue_end = &prologue[ppos]; + epilogue_end = &epilogue[epos]; + + if (func->Flag == 1) + { + if (offset < (prologue_end - prologue) || offset >= func->FunctionLength - (epilogue_end - epilogue)) + { + /* Check prologue */ + len = get_sequence_len( prologue, prologue_end ); + if (offset < len) + { + process_unwind_codes( prologue, prologue_end, context, ptrs, len - offset, &final_pc_from_lr ); + return NULL; + } + /* Check epilogue */ + len = get_sequence_len( epilogue, epilogue_end ); + if (offset >= func->FunctionLength - (len + 1)) /* epilog */ + { + process_unwind_codes( epilogue, epilogue_end, context, ptrs, offset - (func->FunctionLength - (len + 1)), &final_pc_from_lr ); + return NULL; + } } } - if (func->CR == 2) do_pac_auth( context ); + + /* Execute full prologue */ + process_unwind_codes( prologue, prologue_end, context, ptrs, 0, &final_pc_from_lr ); return NULL; } -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/9666
From: Martin Storsjö <martin(a)martin.st> This case isn't mentioned in documentation, but this behaviour seems reasonable. This case was fixed in the same way in llvm-readobj in https://github.com/llvm/llvm-project/pull/170294. --- dlls/ntdll/tests/unwind.c | 82 +++++++++++++++++++++++++++++++++++++++ dlls/ntdll/unwind.c | 10 ++++- tools/winedump/pe.c | 9 ++++- 3 files changed, 98 insertions(+), 3 deletions(-) diff --git a/dlls/ntdll/tests/unwind.c b/dlls/ntdll/tests/unwind.c index fc658541b11..9dea3f3fe60 100644 --- a/dlls/ntdll/tests/unwind.c +++ b/dlls/ntdll/tests/unwind.c @@ -2705,6 +2705,86 @@ static void test_virtual_unwind_arm64(void) { 0x14, 0x00, 0, ORIG_LR, 0x000, TRUE, { {-1,-1} }}, }; + static const BYTE function_22[] = + { + 0xfd, 0x7b, 0xba, 0xa9, /* 00: stp x29, lr, [sp, #-96]! */ + 0xfd, 0x03, 0x00, 0x91, /* 04: mov x29, sp */ + 0xe0, 0x07, 0x02, 0xa9, /* 08: stp x0, x1, [sp, #32] */ + 0xe2, 0x0f, 0x03, 0xa9, /* 0c: stp x2, x3, [sp, #48] */ + 0xe4, 0x17, 0x04, 0xa9, /* 10: stp x4, x5, [sp, #64] */ + 0xe6, 0x1f, 0x05, 0xa9, /* 14: stp x6, x7, [sp, #80] */ + 0x1f, 0x20, 0x03, 0xd5, /* 18: nop */ + 0x1f, 0x20, 0x03, 0xd5, /* 1c: nop */ + 0xbf, 0x03, 0x00, 0x91, /* 20: mov sp, x29 */ + 0xfd, 0x7b, 0xc6, 0xa8, /* 24: ldp x29, lr, [sp], #96 */ + 0xc0, 0x03, 0x5f, 0xd6, /* 28: ret */ + }; + + static const DWORD unwind_info_22_packed = + (1 << 0) | /* Flag */ + (sizeof(function_22)/4 << 2) | /* FunctionLength */ + (0 << 13) | /* RegF */ + (0 << 16) | /* RegI */ + (1 << 20) | /* H */ + (3 << 21) | /* CR */ + (6 << 23); /* FrameSize */ + + static const BYTE unwind_info_22[] = { DW(unwind_info_22_packed) }; + + static const struct results_arm64 results_22[] = + { + /* offset fp handler pc frame offset registers */ + { 0x00, 0x10, 0, ORIG_LR, 0x000, TRUE, { {-1,-1} }}, + { 0x04, 0x10, 0, 0x08, 0x060, TRUE, { {x29, 0x00}, {lr, 0x08}, {-1,-1} }}, + { 0x08, 0x10, 0, 0x18, 0x070, TRUE, { {x29, 0x10}, {lr, 0x18}, {-1,-1} }}, + { 0x0c, 0x10, 0, 0x18, 0x070, TRUE, { {x29, 0x10}, {lr, 0x18}, {-1,-1} }}, + { 0x10, 0x10, 0, 0x18, 0x070, TRUE, { {x29, 0x10}, {lr, 0x18}, {-1,-1} }}, + { 0x14, 0x10, 0, 0x18, 0x070, TRUE, { {x29, 0x10}, {lr, 0x18}, {-1,-1} }}, + { 0x18, 0x10, 0, 0x18, 0x070, TRUE, { {x29, 0x10}, {lr, 0x18}, {-1,-1} }}, + { 0x1c, 0x10, 0, 0x18, 0x070, TRUE, { {x29, 0x10}, {lr, 0x18}, {-1,-1} }}, + { 0x20, 0x10, 0, 0x18, 0x070, TRUE, { {x29, 0x10}, {lr, 0x18}, {-1,-1} }}, + { 0x24, 0x10, 0, 0x08, 0x060, TRUE, { {x29, 0x00}, {lr, 0x08}, {-1,-1} }}, + { 0x28, 0x10, 0, ORIG_LR, 0x000, TRUE, { {-1,-1} }}, + }; + + static const BYTE function_23[] = + { + 0xff, 0x83, 0x01, 0xd1, /* 00: sub sp, sp, #96 */ + 0xe0, 0x07, 0x02, 0xa9, /* 04: stp x0, x1, [sp, #32] */ + 0xe2, 0x0f, 0x03, 0xa9, /* 08: stp x2, x3, [sp, #48] */ + 0xe4, 0x17, 0x04, 0xa9, /* 0c: stp x4, x5, [sp, #64] */ + 0xe6, 0x1f, 0x05, 0xa9, /* 10: stp x6, x7, [sp, #80] */ + 0x1f, 0x20, 0x03, 0xd5, /* 14: nop */ + 0x1f, 0x20, 0x03, 0xd5, /* 18: nop */ + 0xff, 0x83, 0x01, 0x91, /* 1c: add sp, sp, #96 */ + 0xc0, 0x03, 0x5f, 0xd6, /* 20: ret */ + }; + + static const DWORD unwind_info_23_packed = + (1 << 0) | /* Flag */ + (sizeof(function_23)/4 << 2) | /* FunctionLength */ + (0 << 13) | /* RegF */ + (0 << 16) | /* RegI */ + (1 << 20) | /* H */ + (0 << 21) | /* CR */ + (6 << 23); /* FrameSize */ + + static const BYTE unwind_info_23[] = { DW(unwind_info_23_packed) }; + + static const struct results_arm64 results_23[] = + { + /* offset fp handler pc frame offset registers */ + { 0x00, 0x00, 0, ORIG_LR, 0x000, TRUE, { {-1,-1} }}, + { 0x04, 0x00, 0, ORIG_LR, 0x060, TRUE, { {-1,-1} }}, + { 0x08, 0x00, 0, ORIG_LR, 0x060, TRUE, { {-1,-1} }}, + { 0x0c, 0x00, 0, ORIG_LR, 0x060, TRUE, { {-1,-1} }}, + { 0x10, 0x00, 0, ORIG_LR, 0x060, TRUE, { {-1,-1} }}, + { 0x14, 0x00, 0, ORIG_LR, 0x060, TRUE, { {-1,-1} }}, + { 0x18, 0x00, 0, ORIG_LR, 0x060, TRUE, { {-1,-1} }}, + { 0x1c, 0x00, 0, ORIG_LR, 0x060, TRUE, { {-1,-1} }}, + { 0x20, 0x00, 0, ORIG_LR, 0x000, TRUE, { {-1,-1} }}, + }; + static const struct unwind_test_arm64 tests[] = { #define TEST(func, unwind, size, results, unwound_clear, last_ptr, stack_value_index, stack_value) \ @@ -2731,6 +2811,8 @@ static void test_virtual_unwind_arm64(void) TEST(function_19, unwind_info_19, 0, results_19, 0, 0, -1, 0), TEST(function_20, unwind_info_20, 0, results_20, 0, 0, -1, 0), TEST(function_21, unwind_info_21, 0, results_21, 0, 0, -1, 0), + TEST(function_22, unwind_info_22, 0, results_22, 0, 0, -1, 0), + TEST(function_23, unwind_info_23, 0, results_23, 0, 0, -1, 0), #undef TEST }; unsigned int i; diff --git a/dlls/ntdll/unwind.c b/dlls/ntdll/unwind.c index 0f8942c20b0..6e2b8641db5 100644 --- a/dlls/ntdll/unwind.c +++ b/dlls/ntdll/unwind.c @@ -525,7 +525,7 @@ static void *unwind_packed_data( ULONG_PTR base, ULONG_PTR pc, ARM64_RUNTIME_FUN int i; unsigned int len, offset; unsigned int int_size = func->RegI * 8, fp_size = func->RegF * 8, regsave, local_size; - unsigned int int_regs, fp_regs, saved_regs; + unsigned int int_regs, fp_regs, saved_regs, homing = func->H; BYTE prologue[40], *prologue_end, epilogue[40], *epilogue_end; unsigned int ppos = 0, epos = 0; BOOLEAN final_pc_from_lr; @@ -546,6 +546,12 @@ static void *unwind_packed_data( ULONG_PTR base, ULONG_PTR pc, ARM64_RUNTIME_FUN offset = ((pc - base) - func->BeginAddress) / 4; + if (func->H && func->RegI == 0 && func->RegF == 0 && func->CR != 1) + { + local_size += regsave; + homing = 0; + } + /* Synthesize prologue opcodes */ #define WRITE_ONE(x) do { prologue[ppos++] = epilogue[epos++] = (x); } while (0) #define WRITE_TWO(x) do { WRITE_ONE((x) >> 8); WRITE_ONE((x) & 0xff); } while (0) @@ -577,7 +583,7 @@ static void *unwind_packed_data( ULONG_PTR base, ULONG_PTR pc, ARM64_RUNTIME_FUN WRITE_TWO(0xc000 | (4080/16)); /* alloc_m */ } } - if (func->H) + if (homing) { prologue[ppos++] = 0xe3; /* nop */ prologue[ppos++] = 0xe3; /* nop */ diff --git a/tools/winedump/pe.c b/tools/winedump/pe.c index 2b738a2f7c3..6b190d4d03d 100644 --- a/tools/winedump/pe.c +++ b/tools/winedump/pe.c @@ -2116,6 +2116,7 @@ static void dump_arm64_codes( const BYTE *ptr, unsigned int count ) static void dump_arm64_packed_info( const struct runtime_function_arm64 *func ) { int i, pos = 0, intsz = func->RegI * 8, fpsz = func->RegF * 8, savesz, locsz; + int homing = func->H; if (func->CR == 1) intsz += 8; if (func->RegF) fpsz += 8; @@ -2123,6 +2124,12 @@ static void dump_arm64_packed_info( const struct runtime_function_arm64 *func ) savesz = ((intsz + fpsz + 8 * 8 * func->H) + 0xf) & ~0xf; locsz = func->FrameSize * 16 - savesz; + if (func->H && func->RegI == 0 && func->RegF == 0 && func->CR != 1) + { + locsz += savesz; + homing = 0; + } + switch (func->CR) { case 3: @@ -2148,7 +2155,7 @@ static void dump_arm64_packed_info( const struct runtime_function_arm64 *func ) break; } - if (func->H) + if (homing) { printf( " %04x: stp x6,x7,[sp,#%#x]\n", pos++, intsz + fpsz + 48 ); printf( " %04x: stp x4,x5,[sp,#%#x]\n", pos++, intsz + fpsz + 32 ); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/9666
participants (1)
-
Martin Storsjö