Module: wine Branch: master Commit: 434702fdc94480648c0a2036f682ef3dc1f8d48c URL: https://gitlab.winehq.org/wine/wine/-/commit/434702fdc94480648c0a2036f682ef3...
Author: Jacek Caban jacek@codeweavers.com Date: Thu May 16 13:03:22 2024 +0200
ntdll: Use assembly wrapper for unixlib calls on ARM64EC.
Instead of using indirect C calls, which need to go through the call dispatcher.
---
dlls/ntdll/ntdll.spec | 1 + dlls/ntdll/signal_arm64ec.c | 17 ++++++++++++++++- dlls/ntdll/unix/loader.c | 13 ++++++++++++- dlls/winecrt0/unix_lib.c | 25 +++++++++++++++++++++++++ include/wine/unixlib.h | 8 ++++++++ 5 files changed, 62 insertions(+), 2 deletions(-)
diff --git a/dlls/ntdll/ntdll.spec b/dlls/ntdll/ntdll.spec index d32c95c49ad..2d2ec919c5c 100644 --- a/dlls/ntdll/ntdll.spec +++ b/dlls/ntdll/ntdll.spec @@ -1723,6 +1723,7 @@ @ stdcall __wine_ctrl_routine(ptr) @ extern -private __wine_syscall_dispatcher @ extern -private __wine_unix_call_dispatcher +@ extern -private -arch=arm64ec __wine_unix_call_dispatcher_arm64ec @ extern -private __wine_unixlib_handle
# Debugging diff --git a/dlls/ntdll/signal_arm64ec.c b/dlls/ntdll/signal_arm64ec.c index 8caf4218ab9..a79996f8b48 100644 --- a/dlls/ntdll/signal_arm64ec.c +++ b/dlls/ntdll/signal_arm64ec.c @@ -2227,6 +2227,22 @@ ULONG WINAPI RtlWalkFrameChain( void **buffer, ULONG count, ULONG flags ) }
+/************************************************************************* + * __wine_unix_call_arm64ec + */ +NTSTATUS __attribute__((naked)) __wine_unix_call_arm64ec( unixlib_handle_t handle, unsigned int code, void *args ) +{ + asm( ".seh_proc "#__wine_unix_call_arm64ec"\n\t" + ".seh_endprologue\n\t" + "adrp x16, __wine_unix_call_dispatcher_arm64ec\n\t" + "ldr x16, [x16, #:lo12:__wine_unix_call_dispatcher_arm64ec]\n\t" + "br x16\n\t" + ".seh_endproc" ); +} + +NTSTATUS (WINAPI *__wine_unix_call_dispatcher_arm64ec)( unixlib_handle_t, unsigned int, void * ) = __wine_unix_call_arm64ec; + + static int code_match( BYTE *code, const BYTE *seq, size_t len ) { for ( ; len; len--, code++, seq++) if (*seq && *code != *seq) return 0; @@ -2262,7 +2278,6 @@ void *check_call( void **target, void *exit_thunk, void *dest )
for (;;) { - if (dest == __wine_unix_call_dispatcher) return dest; if (RtlIsEcCode( (ULONG_PTR)dest )) return dest; if (code_match( dest, jmp_sequence, sizeof(jmp_sequence) )) { diff --git a/dlls/ntdll/unix/loader.c b/dlls/ntdll/unix/loader.c index 06959fa95df..9d866fa70f5 100644 --- a/dlls/ntdll/unix/loader.c +++ b/dlls/ntdll/unix/loader.c @@ -1517,6 +1517,7 @@ static void load_ntdll_functions( HMODULE module ) { void **p__wine_syscall_dispatcher; void **p__wine_unix_call_dispatcher; + void **p__wine_unix_call_dispatcher_arm64ec = NULL; unixlib_handle_t *p__wine_unixlib_handle; const IMAGE_EXPORT_DIRECTORY *exports;
@@ -1539,9 +1540,19 @@ static void load_ntdll_functions( HMODULE module ) GET_FUNC( __wine_syscall_dispatcher ); GET_FUNC( __wine_unix_call_dispatcher ); GET_FUNC( __wine_unixlib_handle ); + if (is_arm64ec()) + { + GET_FUNC( __wine_unix_call_dispatcher_arm64ec ); + } *p__wine_syscall_dispatcher = __wine_syscall_dispatcher; - *p__wine_unix_call_dispatcher = __wine_unix_call_dispatcher; *p__wine_unixlib_handle = (UINT_PTR)unix_call_funcs; + if (p__wine_unix_call_dispatcher_arm64ec) + { + /* redirect __wine_unix_call_dispatcher to __wine_unix_call_dispatcher_arm64ec */ + *p__wine_unix_call_dispatcher = *p__wine_unix_call_dispatcher_arm64ec; + *p__wine_unix_call_dispatcher_arm64ec = __wine_unix_call_dispatcher; + } + else *p__wine_unix_call_dispatcher = __wine_unix_call_dispatcher; #undef GET_FUNC }
diff --git a/dlls/winecrt0/unix_lib.c b/dlls/winecrt0/unix_lib.c index fd5087cbe48..ebf6594e770 100644 --- a/dlls/winecrt0/unix_lib.c +++ b/dlls/winecrt0/unix_lib.c @@ -64,6 +64,31 @@ static NTSTATUS WINAPI unix_call_init( unixlib_handle_t handle, unsigned int cod unixlib_handle_t __wine_unixlib_handle = 0; NTSTATUS (WINAPI *__wine_unix_call_dispatcher)( unixlib_handle_t, unsigned int, void * ) = unix_call_init;
+#ifdef __arm64ec__ + +static NTSTATUS WINAPI unix_call_init_arm64ec( unixlib_handle_t handle, unsigned int code, void *args ); + +static __attribute__((used)) NTSTATUS (WINAPI *__wine_unix_call_dispatcher_arm64ec)( unixlib_handle_t, unsigned int, void * ) = unix_call_init_arm64ec; + +static NTSTATUS WINAPI unix_call_init_arm64ec( unixlib_handle_t handle, unsigned int code, void *args ) +{ + InterlockedExchangePointer( (void **)&__wine_unix_call_dispatcher_arm64ec, + get_dispatcher( "__wine_unix_call_dispatcher_arm64ec" )); + return __wine_unix_call_arm64ec( handle, code, args ); +} + +NTSTATUS __attribute__((naked)) __wine_unix_call_arm64ec( unixlib_handle_t handle, unsigned int code, void *args ) +{ + asm( ".seh_proc "#__wine_unix_call_arm64ec"\n\t" + ".seh_endprologue\n\t" + "adrp x16, __wine_unix_call_dispatcher_arm64ec\n\t" + "ldr x16, [x16, #:lo12:__wine_unix_call_dispatcher_arm64ec]\n\t" + "br x16\n\t" + ".seh_endproc" ); +} + +#endif + NTSTATUS WINAPI __wine_init_unix_call(void) { return NtQueryVirtualMemory( GetCurrentProcess(), image_base(), MemoryWineUnixFuncs, diff --git a/include/wine/unixlib.h b/include/wine/unixlib.h index 17ec93110f2..9a342fada73 100644 --- a/include/wine/unixlib.h +++ b/include/wine/unixlib.h @@ -262,10 +262,18 @@ extern unixlib_handle_t __wine_unixlib_handle; extern NTSTATUS (WINAPI *__wine_unix_call_dispatcher)( unixlib_handle_t, unsigned int, void * ); extern NTSTATUS WINAPI __wine_init_unix_call(void);
+#ifdef __arm64ec__ +NTSTATUS __wine_unix_call_arm64ec( unixlib_handle_t handle, unsigned int code, void *args ); +static inline NTSTATUS __wine_unix_call( unixlib_handle_t handle, unsigned int code, void *args ) +{ + return __wine_unix_call_arm64ec( handle, code, args ); +} +#else static inline NTSTATUS __wine_unix_call( unixlib_handle_t handle, unsigned int code, void *args ) { return __wine_unix_call_dispatcher( handle, code, args ); } +#endif
#define WINE_UNIX_CALL(code,args) __wine_unix_call( __wine_unixlib_handle, (code), (args) )