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



Attachment: Cygwin-autoload-fix-ws2_32-chained-init-on-AArch64.patch
Description: Cygwin-autoload-fix-ws2_32-chained-init-on-AArch64.patch

Reply via email to