Currently there is `NtContinue()` test only for `aarch64` so implement it for amd64 aswell.
This implementation is very similar to `aarch64` and it's very basic test.
It doesn't change/test `ContextFlags` so it won't catch https://bugs.winehq.org/show_bug.cgi?id=56050 but that can be implemented later on top of this.
-- v9: ntdll/tests: Implement test_continue() for amd64
From: Dāvis Mosāns davispuh@gmail.com
--- dlls/ntdll/tests/exception.c | 165 +++++++++++++++++++++++++++++++++++ 1 file changed, 165 insertions(+)
diff --git a/dlls/ntdll/tests/exception.c b/dlls/ntdll/tests/exception.c index 76190aef75a..0c69287c15b 100644 --- a/dlls/ntdll/tests/exception.c +++ b/dlls/ntdll/tests/exception.c @@ -4413,6 +4413,170 @@ static void test_thread_context(void) #undef COMPARE }
+static void test_continue(void) +{ + struct context_pair { + CONTEXT before; + CONTEXT after; + } contexts; + NTSTATUS (*func_ptr)( struct context_pair *, BOOL alertable, void *continue_func, void *capture_func ) = code_mem; + int i; + + static const BYTE call_func[] = + { + /* ret at 8*9(rsp) */ + + /* need to preserve these */ + 0x53, /* push %rbx; 8*8(rsp) */ + 0x55, /* push %rbp; 8*7(rsp) */ + 0x56, /* push %rsi; 8*6(rsp) */ + 0x57, /* push %rdi; 8*5(rsp) */ + 0x41, 0x54, /* push %r12; 8*4(rsp) */ + 0x41, 0x55, /* push %r13; 8*3(rsp) */ + 0x41, 0x56, /* push %r14; 8*2(rsp) */ + 0x41, 0x57, /* push %r15; 8*1(rsp) */ + + 0x48, 0x83, 0xec, 0x08, /* sub $0x8, %rsp; reserve space for rsp */ + 0x48, 0x89, 0x24, 0x24, /* mov %rsp, (%rsp); for stack validation */ + + /* save args */ + 0x48, 0x89, 0x4c, 0x24, 0x50, /* mov %rcx, 8*10(%rsp) */ + 0x48, 0x89, 0x54, 0x24, 0x58, /* mov %rdx, 8*11(%rsp) */ + 0x4c, 0x89, 0x44, 0x24, 0x60, /* mov %r8, 8*12(%rsp) */ + 0x4c, 0x89, 0x4c, 0x24, 0x68, /* mov %r9, 8*13(%rsp) */ + + /* invoke capture context */ + 0x41, 0xff, 0xd1, /* call *%r9 */ + + /* overwrite general registers */ + 0x48, 0xb8, 0xef, 0xbe, 0xad, 0xde, 0xef, 0xbe, 0xad, 0xde, /* movabs $0xdeadbeefdeadbeef, %rax */ + 0x48, 0x89, 0xc1, /* mov %rax, %rcx */ + 0x48, 0x89, 0xc2, /* mov %rax, %rdx */ + 0x48, 0x89, 0xc3, /* mov %rax, %rbx */ + 0x48, 0x89, 0xc5, /* mov %rax, %rbp */ + 0x48, 0x89, 0xc6, /* mov %rax, %rsi */ + 0x48, 0x89, 0xc7, /* mov %rax, %rdi */ + 0x49, 0x89, 0xc0, /* mov %rax, %r8 */ + 0x49, 0x89, 0xc1, /* mov %rax, %r9 */ + 0x49, 0x89, 0xc2, /* mov %rax, %r10 */ + 0x49, 0x89, 0xc3, /* mov %rax, %r11 */ + 0x49, 0x89, 0xc4, /* mov %rax, %r12 */ + 0x49, 0x89, 0xc5, /* mov %rax, %r13 */ + 0x49, 0x89, 0xc6, /* mov %rax, %r14 */ + 0x49, 0x89, 0xc7, /* mov %rax, %r15 */ + + /* overwrite SSE registers */ + 0x66, 0x48, 0x0f, 0x6e, 0xc0, /* movq %rax, %xmm0 */ + 0x66, 0x0f, 0x6c, 0xc0, /* punpcklqdq %xmm0, %xmm0; extend to high quadword */ + 0x0f, 0x28, 0xc8, /* movaps %xmm0, %xmm1 */ + 0x0f, 0x28, 0xd0, /* movaps %xmm0, %xmm2 */ + 0x0f, 0x28, 0xd8, /* movaps %xmm0, %xmm3 */ + 0x0f, 0x28, 0xe0, /* movaps %xmm0, %xmm4 */ + 0x0f, 0x28, 0xe8, /* movaps %xmm0, %xmm5 */ + 0x0f, 0x28, 0xf0, /* movaps %xmm0, %xmm6 */ + 0x0f, 0x28, 0xf8, /* movaps %xmm0, %xmm7 */ + 0x44, 0x0f, 0x28, 0xc0, /* movaps %xmm0, %xmm8 */ + 0x44, 0x0f, 0x28, 0xc8, /* movaps %xmm0, %xmm9 */ + 0x44, 0x0f, 0x28, 0xd0, /* movaps %xmm0, %xmm10 */ + 0x44, 0x0f, 0x28, 0xd8, /* movaps %xmm0, %xmm11 */ + 0x44, 0x0f, 0x28, 0xe0, /* movaps %xmm0, %xmm12 */ + 0x44, 0x0f, 0x28, 0xe8, /* movaps %xmm0, %xmm13 */ + 0x44, 0x0f, 0x28, 0xf0, /* movaps %xmm0, %xmm14 */ + 0x44, 0x0f, 0x28, 0xf8, /* movaps %xmm0, %xmm15 */ + + /* FIXME: overwrite debug, x87 FPU and AVX registers to test those */ + + /* load args */ + 0x48, 0x8b, 0x4c, 0x24, 0x50, /* mov 8*10(%rsp), %rcx; context */ + 0x48, 0x8b, 0x54, 0x24, 0x58, /* mov 8*11(%rsp), %rdx; alertable */ + 0x48, 0x83, 0xec, 0x70, /* sub $0x70, %rsp; change stack */ + + /* setup context to return to label 1 */ + 0x48, 0x8d, 0x05, 0x18, 0x00, 0x00, 0x00, /* lea 1f(%rip), %rax */ + 0x48, 0x89, 0x81, 0xf8, 0x00, 0x00, 0x00, /* mov %rax, 0xf8(%rcx); context.Rip */ + + /* flip some EFLAGS */ + 0x9c, /* pushf */ + /* + 0x0001 Carry flag + 0x0004 Parity flag + 0x0010 Auxiliary Carry flag + 0x0040 Zero flag + 0x0080 Sign flag + FIXME: 0x0400 Direction flag - not changing as it breaks Wine + 0x0800 Overflow flag + ~0x4000~ Nested task flag - not changing - breaks Wine + = 0x8d5 + */ + 0x48, 0x81, 0x34, 0x24, 0xd5, 0x08, 0x00, 0x00, /* xorq $0x8d5, (%rsp) */ + 0x9d, /* popf */ + + /* invoke NtContinue... */ + 0xff, 0x94, 0x24, 0xd0, 0x00, 0x00, 0x00, /* call *8*12+0x70(%rsp) */ + + /* validate stack pointer */ + 0x48, 0x8b, 0x0c, 0x24, /* 1: mov (%rsp), %rcx */ + 0x48, 0x39, 0xe1, /* cmp %rsp, %rcx */ + 0x74, 0x02, /* je 2f; jump over ud2 */ + 0x0f, 0x0b, /* ud2; stack pointer invalid, let's crash */ + + /* invoke capture context */ + 0x48, 0x8b, 0x4c, 0x24, 0x50, /* 2: mov 8*10(%rsp), %rcx; context */ + 0x48, 0x81, 0xc1, 0xd0, 0x04, 0x00, 0x00, /* add $0x4d0, %rcx; +sizeof(CONTEXT) to get context->after */ + 0xff, 0x54, 0x24, 0x68, /* call *8*13(%rsp) */ + + /* free stack */ + 0x48, 0x83, 0xc4, 0x08, /* add $0x8, %rsp */ + + /* restore back */ + 0x41, 0x5f, /* pop %r15 */ + 0x41, 0x5e, /* pop %r14 */ + 0x41, 0x5d, /* pop %r13 */ + 0x41, 0x5c, /* pop %r12 */ + 0x5f, /* pop %rdi */ + 0x5e, /* pop %rsi */ + 0x5d, /* pop %rbp */ + 0x5b, /* pop %rbx */ + 0xc3 /* ret */ + }; + + if (!pRtlCaptureContext) + { + win_skip("RtlCaptureContext is not available.\n"); + return; + } + + memcpy( func_ptr, call_func, sizeof(call_func) ); + FlushInstructionCache( GetCurrentProcess(), func_ptr, sizeof(call_func) ); + + func_ptr( &contexts, FALSE, NtContinue, pRtlCaptureContext ); + +#define COMPARE(reg) \ + ok( contexts.before.reg == contexts.after.reg, "wrong " #reg " %p/%p\n", (void *)(ULONG64)contexts.before.reg, (void *)(ULONG64)contexts.after.reg ) + + COMPARE( Rax ); + COMPARE( Rdx ); + COMPARE( Rbx ); + COMPARE( Rbp ); + COMPARE( Rsi ); + COMPARE( Rdi ); + COMPARE( R8 ); + COMPARE( R9 ); + COMPARE( R10 ); + COMPARE( R11 ); + COMPARE( R12 ); + COMPARE( R13 ); + COMPARE( R14 ); + COMPARE( R15 ); + + for (i = 0; i < 16; i++) + ok( !memcmp( &contexts.before.Xmm0 + i, &contexts.after.Xmm0 + i, sizeof(contexts.before.Xmm0) ), + "wrong xmm%u %08I64x%08I64x/%08I64x%08I64x\n", i, *(&contexts.before.Xmm0.High + i*2), *(&contexts.before.Xmm0.Low + i*2), + *(&contexts.after.Xmm0.High + i*2), *(&contexts.after.Xmm0.Low + i*2) ); + +#undef COMPARE +} + static void test_wow64_context(void) { const char appname[] = "C:\windows\syswow64\cmd.exe"; @@ -12459,6 +12623,7 @@ START_TEST(exception) test_debug_registers_wow64(); test_debug_service(1); test_simd_exceptions(); + test_continue(); test_virtual_unwind(); test___C_specific_handler(); test_restore_context();
On Thu Jan 4 15:28:37 2024 +0000, Jinoh Kang wrote:
Nested Task surely breaks Wine; however, I cannot reproduce such breakage with Direction Flag. https://testbot.winehq.org/JobDetails.pl?Key=141583 Therefore, I suggest that DF be included in the mask as well. (Did you make sure to test each flag separately?)
Hmm that's weird, it fails 100% of time for me if I include it:
```diff diff --git a/dlls/ntdll/tests/exception.c b/dlls/ntdll/tests/exception.c index 0c69287c15b..c938dbe37c4 100644 --- a/dlls/ntdll/tests/exception.c +++ b/dlls/ntdll/tests/exception.c @@ -4508,7 +4508,7 @@ static void test_continue(void) ~0x4000~ Nested task flag - not changing - breaks Wine = 0x8d5 */ - 0x48, 0x81, 0x34, 0x24, 0xd5, 0x08, 0x00, 0x00, /* xorq $0x8d5, (%rsp) */ + 0x48, 0x81, 0x34, 0x24, 0xd5, 0x0c, 0x00, 0x00, /* xorq $0xcd5, (%rsp) */ 0x9d, /* popf */
/* invoke NtContinue... */ @@ -4540,6 +4540,8 @@ static void test_continue(void) 0xc3 /* ret */ };
+ printf("entering test_continue()\n"); + if (!pRtlCaptureContext) { win_skip("RtlCaptureContext is not available.\n"); @@ -4574,6 +4576,7 @@ static void test_continue(void) "wrong xmm%u %08I64x%08I64x/%08I64x%08I64x\n", i, *(&contexts.before.Xmm0.High + i*2), *(&contexts.before.Xmm0.Low + i*2), *(&contexts.after.Xmm0.High + i*2), *(&contexts.after.Xmm0.Low + i*2) );
+ printf("leaving test_continue()\n"); #undef COMPARE } ```
``` $ ./wine64 dlls/ntdll/tests/x86_64-windows/ntdll_test.exe exception exception.c:3849: exception: 00012345 flags:0 addr:00007FFFFEAA0010 context: Rip:00007FFFFEAA0010 exception.c:3960: Test marked todo: Frame handler called exception.c:3962: Test marked todo: UnhandledExceptionFilter wasn't called exception.c:3849: exception: 80000003 flags:0 addr:00007FFFFEAA0010 context: Rip:00007FFFFEAA0010 exception.c:3960: Test marked todo: Frame handler called exception.c:3962: Test marked todo: UnhandledExceptionFilter wasn't called exception.c:3849: exception: c0000008 flags:0 addr:00007FFFFEAA0010 context: Rip:00007FFFFEAA0010 exception.c:3960: Test marked todo: Frame handler called exception.c:3962: Test marked todo: UnhandledExceptionFilter wasn't called entering test_continue() 0154:err:seh:call_stack_handlers invalid frame 00007FFFFE0FDE78 (00007FFFFE102000-00007FFFFE300000) 0154:err:seh:call_stack_handlers invalid frame 00007FFFFE0FCB28 (00007FFFFE102000-00007FFFFE300000) 0154:err:seh:NtRaiseException Exception frame is not in stack limits => unable to dispatch exception. ```
and without it ``` exception.c:3849: exception: 00012345 flags:0 addr:00007FFFFEAA0010 context: Rip:00007FFFFEAA0010 exception.c:3960: Test marked todo: Frame handler called exception.c:3962: Test marked todo: UnhandledExceptionFilter wasn't called exception.c:3849: exception: 80000003 flags:0 addr:00007FFFFEAA0010 context: Rip:00007FFFFEAA0010 exception.c:3960: Test marked todo: Frame handler called exception.c:3962: Test marked todo: UnhandledExceptionFilter wasn't called exception.c:3849: exception: c0000008 flags:0 addr:00007FFFFEAA0010 context: Rip:00007FFFFEAA0010 exception.c:3960: Test marked todo: Frame handler called exception.c:3962: Test marked todo: UnhandledExceptionFilter wasn't called entering test_continue() leaving test_continue() [...] ```
Maybe it's some compiler flag? I'm on Arch Linux with mingw-w64-gcc 13.1.0 and it builds with ``` x86_64-w64-mingw32-gcc -c -o dlls/ntdll/tests/x86_64-windows/exception.o ../dlls/ntdll/tests/exception.c -Idlls/ntdll/tests -I../dlls/ntdll/tests \ -Iinclude -I../include -I../include/msvcrt -D_MSVCR_VER=0 -D__WINESRC__ -D__WINE_PE_BUILD -Wall \ -fno-strict-aliasing -Wdeclaration-after-statement -Wempty-body -Wignored-qualifiers -Winit-self \ -Wno-packed-not-aligned -Wshift-overflow=2 -Wstrict-prototypes -Wtype-limits \ -Wunused-but-set-parameter -Wvla -Wwrite-strings -Wpointer-arith -Wlogical-op -Wabsolute-value \ -Wenum-conversion -Wformat-overflow -Wnonnull -mcx16 -mcmodel=small -gdwarf-4 -g -O2 ```
Hi,
It looks like your patch introduced the new failures shown below. Please investigate and fix them before resubmitting your patch. If they are not new, fixing them anyway would help a lot. Otherwise please ask for the known failures list to be updated.
The full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=141827
Your paranoid android.
=== build (build log) ===
error: corrupt patch at line 39 Task: Patch failed to apply
=== debian11 (build log) ===
error: corrupt patch at line 39 Task: Patch failed to apply
=== debian11b (build log) ===
error: corrupt patch at line 39 Task: Patch failed to apply
On Sun Jan 14 16:10:35 2024 +0000, Dāvis Mosāns (davispuh) wrote:
Hmm that's weird, it fails 100% of time for me if I include it:
diff --git a/dlls/ntdll/tests/exception.c b/dlls/ntdll/tests/exception.c index 0c69287c15b..c938dbe37c4 100644 --- a/dlls/ntdll/tests/exception.c +++ b/dlls/ntdll/tests/exception.c @@ -4508,7 +4508,7 @@ static void test_continue(void) ~0x4000~ Nested task flag - not changing - breaks Wine = 0x8d5 */ - 0x48, 0x81, 0x34, 0x24, 0xd5, 0x08, 0x00, 0x00, /* xorq $0x8d5, (%rsp) */ + 0x48, 0x81, 0x34, 0x24, 0xd5, 0x0c, 0x00, 0x00, /* xorq $0xcd5, (%rsp) */ 0x9d, /* popf */ /* invoke NtContinue... */ @@ -4540,6 +4540,8 @@ static void test_continue(void) 0xc3 /* ret */ }; + printf("entering test_continue()\n"); + if (!pRtlCaptureContext) { win_skip("RtlCaptureContext is not available.\n"); @@ -4574,6 +4576,7 @@ static void test_continue(void) "wrong xmm%u %08I64x%08I64x/%08I64x%08I64x\n", i, *(&contexts.before.Xmm0.High + i*2), *(&contexts.before.Xmm0.Low + i*2), *(&contexts.after.Xmm0.High + i*2), *(&contexts.after.Xmm0.Low + i*2) ); + printf("leaving test_continue()\n"); #undef COMPARE }
$ ./wine64 dlls/ntdll/tests/x86_64-windows/ntdll_test.exe exception exception.c:3849: exception: 00012345 flags:0 addr:00007FFFFEAA0010 context: Rip:00007FFFFEAA0010 exception.c:3960: Test marked todo: Frame handler called exception.c:3962: Test marked todo: UnhandledExceptionFilter wasn't called exception.c:3849: exception: 80000003 flags:0 addr:00007FFFFEAA0010 context: Rip:00007FFFFEAA0010 exception.c:3960: Test marked todo: Frame handler called exception.c:3962: Test marked todo: UnhandledExceptionFilter wasn't called exception.c:3849: exception: c0000008 flags:0 addr:00007FFFFEAA0010 context: Rip:00007FFFFEAA0010 exception.c:3960: Test marked todo: Frame handler called exception.c:3962: Test marked todo: UnhandledExceptionFilter wasn't called entering test_continue() 0154:err:seh:call_stack_handlers invalid frame 00007FFFFE0FDE78 (00007FFFFE102000-00007FFFFE300000) 0154:err:seh:call_stack_handlers invalid frame 00007FFFFE0FCB28 (00007FFFFE102000-00007FFFFE300000) 0154:err:seh:NtRaiseException Exception frame is not in stack limits => unable to dispatch exception.
and without it
exception.c:3849: exception: 00012345 flags:0 addr:00007FFFFEAA0010 context: Rip:00007FFFFEAA0010 exception.c:3960: Test marked todo: Frame handler called exception.c:3962: Test marked todo: UnhandledExceptionFilter wasn't called exception.c:3849: exception: 80000003 flags:0 addr:00007FFFFEAA0010 context: Rip:00007FFFFEAA0010 exception.c:3960: Test marked todo: Frame handler called exception.c:3962: Test marked todo: UnhandledExceptionFilter wasn't called exception.c:3849: exception: c0000008 flags:0 addr:00007FFFFEAA0010 context: Rip:00007FFFFEAA0010 exception.c:3960: Test marked todo: Frame handler called exception.c:3962: Test marked todo: UnhandledExceptionFilter wasn't called entering test_continue() leaving test_continue() [...]
Maybe it's some compiler flag? I'm on Arch Linux with mingw-w64-gcc 13.1.0 and it builds with
x86_64-w64-mingw32-gcc -c -o dlls/ntdll/tests/x86_64-windows/exception.o ../dlls/ntdll/tests/exception.c -Idlls/ntdll/tests -I../dlls/ntdll/tests \ -Iinclude -I../include -I../include/msvcrt -D_MSVCR_VER=0 -D__WINESRC__ -D__WINE_PE_BUILD -Wall \ -fno-strict-aliasing -Wdeclaration-after-statement -Wempty-body -Wignored-qualifiers -Winit-self \ -Wno-packed-not-aligned -Wshift-overflow=2 -Wstrict-prototypes -Wtype-limits \ -Wunused-but-set-parameter -Wvla -Wwrite-strings -Wpointer-arith -Wlogical-op -Wabsolute-value \ -Wenum-conversion -Wformat-overflow -Wnonnull -mcx16 -mcmodel=small -gdwarf-4 -g -O2
You're right. My test was flawed. sorry.
This is actually a wine bug. `__wine_syscall_dispatcher` does execute `cld` but only for NT syscalls with 7 or mlre arguments.
Jinoh Kang (@iamahuman) commented about dlls/ntdll/tests/exception.c:
0x0f, 0x28, 0xf0, /* movaps %xmm0, %xmm6 */
0x0f, 0x28, 0xf8, /* movaps %xmm0, %xmm7 */
0x44, 0x0f, 0x28, 0xc0, /* movaps %xmm0, %xmm8 */
0x44, 0x0f, 0x28, 0xc8, /* movaps %xmm0, %xmm9 */
0x44, 0x0f, 0x28, 0xd0, /* movaps %xmm0, %xmm10 */
0x44, 0x0f, 0x28, 0xd8, /* movaps %xmm0, %xmm11 */
0x44, 0x0f, 0x28, 0xe0, /* movaps %xmm0, %xmm12 */
0x44, 0x0f, 0x28, 0xe8, /* movaps %xmm0, %xmm13 */
0x44, 0x0f, 0x28, 0xf0, /* movaps %xmm0, %xmm14 */
0x44, 0x0f, 0x28, 0xf8, /* movaps %xmm0, %xmm15 */
/* FIXME: overwrite debug, x87 FPU and AVX registers to test those */
/* load args */
0x48, 0x8b, 0x4c, 0x24, 0x50, /* mov 8*10(%rsp), %rcx; context */
0x48, 0x8b, 0x54, 0x24, 0x58, /* mov 8*11(%rsp), %rdx; alertable */
Ditto.
```suggestion:-1+0 0x48, 0x8b, 0x4c, 0x24, 0x70, /* mov 8*14(%rsp), %rcx; context */ 0x48, 0x8b, 0x54, 0x24, 0x78, /* mov 8*15(%rsp), %rdx; alertable */ ```
Jinoh Kang (@iamahuman) commented about dlls/ntdll/tests/exception.c:
0x55, /* push %rbp; 8*7(rsp) */
0x56, /* push %rsi; 8*6(rsp) */
0x57, /* push %rdi; 8*5(rsp) */
0x41, 0x54, /* push %r12; 8*4(rsp) */
0x41, 0x55, /* push %r13; 8*3(rsp) */
0x41, 0x56, /* push %r14; 8*2(rsp) */
0x41, 0x57, /* push %r15; 8*1(rsp) */
0x48, 0x83, 0xec, 0x08, /* sub $0x8, %rsp; reserve space for rsp */
0x48, 0x89, 0x24, 0x24, /* mov %rsp, (%rsp); for stack validation */
/* save args */
0x48, 0x89, 0x4c, 0x24, 0x50, /* mov %rcx, 8*10(%rsp) */
0x48, 0x89, 0x54, 0x24, 0x58, /* mov %rdx, 8*11(%rsp) */
0x4c, 0x89, 0x44, 0x24, 0x60, /* mov %r8, 8*12(%rsp) */
0x4c, 0x89, 0x4c, 0x24, 0x68, /* mov %r9, 8*13(%rsp) */
We still need to reserve outgoing register parameter save area for our callees (RtlCaptureContext, NtContinue).[^note] All non-leaf functions are required by x64 MS ABI to reserve home area for callees.
```suggestion:-19+0 /* ret at 8*13(rsp) */
/* need to preserve these */ 0x53, /* push %rbx; 8*12(rsp) */ 0x55, /* push %rbp; 8*11(rsp) */ 0x56, /* push %rsi; 8*10(rsp) */ 0x57, /* push %rdi; 8*9(rsp) */ 0x41, 0x54, /* push %r12; 8*8(rsp) */ 0x41, 0x55, /* push %r13; 8*7(rsp) */ 0x41, 0x56, /* push %r14; 8*6(rsp) */ 0x41, 0x57, /* push %r15; 8*5(rsp) */
0x48, 0x83, 0xec, 0x28, /* sub $0x28, %rsp; reserve space for rsp and outgoing reg params */ 0x48, 0x89, 0x64, 0x24, 0x20, /* mov %rsp, 8*4(%rsp); for stack validation */
/* save args */ 0x48, 0x89, 0x4c, 0x24, 0x70, /* mov %rcx, 8*14(%rsp) */ 0x48, 0x89, 0x54, 0x24, 0x78, /* mov %rdx, 8*15(%rsp) */ 0x4c, 0x89, 0x84, 0x24, 0x80, 0x00, 0x00, 0x00, /* mov %r8, 8*16(%rsp) */ 0x4c, 0x89, 0x8c, 0x24, 0x88, 0x00, 0x00, 0x00, /* mov %r9, 8*17(%rsp) */ ```
[^note]: Yes, neither functions rarely ever need to modify its home area, but this is never guaranteed by future Windows versions.
Jinoh Kang (@iamahuman) commented about dlls/ntdll/tests/exception.c:
/* invoke NtContinue... */
0xff, 0x94, 0x24, 0xd0, 0x00, 0x00, 0x00, /* call *8*12+0x70(%rsp) */
/* validate stack pointer */
0x48, 0x8b, 0x0c, 0x24, /* 1: mov (%rsp), %rcx */
0x48, 0x39, 0xe1, /* cmp %rsp, %rcx */
0x74, 0x02, /* je 2f; jump over ud2 */
0x0f, 0x0b, /* ud2; stack pointer invalid, let's crash */
/* invoke capture context */
0x48, 0x8b, 0x4c, 0x24, 0x50, /* 2: mov 8*10(%rsp), %rcx; context */
0x48, 0x81, 0xc1, 0xd0, 0x04, 0x00, 0x00, /* add $0x4d0, %rcx; +sizeof(CONTEXT) to get context->after */
0xff, 0x54, 0x24, 0x68, /* call *8*13(%rsp) */
/* free stack */
0x48, 0x83, 0xc4, 0x08, /* add $0x8, %rsp */
Ditto.
```suggestion:-15+0 /* invoke NtContinue... */ 0xff, 0x94, 0x24, 0xf0, 0x00, 0x00, 0x00, /* call *8*16+0x70(%rsp) */
/* validate stack pointer */ 0x48, 0x3b, 0x64, 0x24, 0x20, /* 1: cmp 0x20(%rsp), %rsp */ 0x74, 0x02, /* je 2f; jump over ud2 */ 0x0f, 0x0b, /* ud2; stack pointer invalid, let's crash */
/* invoke capture context */ 0x48, 0x8b, 0x4c, 0x24, 0x70, /* 2: mov 8*14(%rsp), %rcx; context */ 0x48, 0x81, 0xc1, 0xd0, 0x04, 0x00, 0x00, /* add $0x4d0, %rcx; +sizeof(CONTEXT) to get context->after */ 0xff, 0x94, 0x24, 0x88, 0x00, 0x00, 0x00, /* call *8*17(%rsp) */
/* free stack */ 0x48, 0x83, 0xc4, 0x28, /* add $0x28, %rsp */ ```
While we're at it, I've consolidated mov-cmp sequence into just one cmp.