[PATCH] Cygwin: autoload: fix ws2_32 chained init on AArch64
Chandru Kumaresan
chandru.kumaresan@multicorewareinc.com
Tue Jul 7 09:31:25 GMT 2026
Hi everyone,
On AArch64, the autoload INIT_WRAPPER passes func_info* via x30 ("mov
x0, x30"). This works for the first init stage (std_dll_init), reached
by the trampoline's "blr". It breaks for a chained second init, because
dll_chain reaches it via "br x1" without updating x30.
ws2_32 is the only DLL with such a chain (std_dll_init -> wsock_init ->
dll_func_load). wsock_init received garbage in x0, so WSAStartup was
never called; every ws2_32 call failed with WSANOTINITIALISED / EFAULT.
dll_chain also runs twice for ws2_32, pushing a 16-byte frame each time.
wsock_init consumes its arg from x30, not the stack, so the first frame
strands. dll_func_load then restores caller-save registers from a
shifted offset, corrupting the first call's arguments.
Fix: copy func_info into x30 in dll_chain before the tail-branch, and
give AArch64 a dedicated _wsock_init wrapper that drops the stranded
frame ("add sp, sp, #16") before chaining to dll_func_load.
Inline Patch
---
winsup/cygwin/autoload.cc | 28 ++++++++++++++++++++++++++--
1 file changed, 26 insertions(+), 2 deletions(-)
diff --git a/winsup/cygwin/autoload.cc b/winsup/cygwin/autoload.cc
index 7054511b6..8d0f2a59e 100644
--- a/winsup/cygwin/autoload.cc
+++ b/winsup/cygwin/autoload.cc
@@ -302,6 +302,10 @@ dll_func_load: \n\
.global dll_chain \n\
dll_chain: \n\
stp x0, xzr, [sp, #-16]! // x0 = func_info* (= ret.high); push for dll_func_load\n\
+ mov x30, x0 // also pass func_info in x30: a chained INIT_WRAPPER\n\
+ // (e.g. _wsock_init) reads its arg from x30, but is\n\
+ // reached here via 'br' which would otherwise leave\n\
+ // x30 stale. dll_func_load ignores x30 (reads [sp]).\n\
br x1 // x1 = dll->init (= ret.low); tail-call resolver\n\
");
#else
@@ -481,9 +485,29 @@ std_dll_init (struct func_info *func)
/* Initialization function for winsock stuff. */
-#if defined(__x86_64__) || defined(__aarch64__)
-/* See above comment preceeding std_dll_init. */
+#if defined(__x86_64__)
+/* See above comment preceding std_dll_init. */
INIT_WRAPPER (wsock_init)
+#elif defined(__aarch64__)
+__asm__("\n\
+ .text \n\
+ .p2align 2 \n\
+ .seh_proc _wsock_init \n\
+_wsock_init: \n\
+ stp x29, x30, [sp, #-16]! // save fp/lr, open our 16-byte frame\n\
+ .seh_save_fplr_x 16 \n\
+ .seh_endprologue \n\
+ mov x0, x30 // x0 = func_info (the wsock_init() argument)\n\
+ bl wsock_init // run WSAStartup; returns x0=func_info, x1=dll_func_load\n\
+ ldp x29, xzr, [sp], #16 // restore fp, discard saved lr, close our frame\n\
+ add sp, sp, #16 // drop the stranded dll_chain frame so the\n\
+ // downstream dll_func_load sees exactly one\n\
+ // dll_chain frame above the trampoline frame\n\
+ adrp x30, dll_chain // x30 = &dll_chain ...\n\
+ add x30, x30, #:lo12:dll_chain // ... so the 'ret' below tail-chains there\n\
+ ret // -> dll_chain, which tail-calls x1 (dll_func_load)\n\
+ .seh_endproc \n\
+");
#else
#error unimplemented for this target
#endif
--
2.49.0.windows.1
-------------- next part --------------
A non-text attachment was scrubbed...
Name: Cygwin-autoload-fix-ws2_32-chained-init-on-AArch64.patch
Type: application/octet-stream
Size: 4017 bytes
Desc: Cygwin-autoload-fix-ws2_32-chained-init-on-AArch64.patch
URL: <https://cygwin.com/pipermail/cygwin-patches/attachments/20260707/b153b2be/attachment-0001.obj>
More information about the Cygwin-patches
mailing list