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