[PATCH v3] Cygwin: autoload: fix ws2_32 chained init on AArch64
Chandru Kumaresan
chandru.kumaresan@multicorewareinc.com
Fri Jun 26 09:03:03 GMT 2026
Hi Jon,
> I've applied this patch.
Thanks!!
>Just so I'm doing my due diligence, I'd like you confirm that you are
>submitting this under an open source license as per [1], and you and
>your colleagues at multicoreware are authorized to do so.
We have been contributing to Cygwin for about a year, all modifying
existing files rather than creating new ones. We will confirm and get
back to you shortly.
>* Looking at the git history, the comment on the problem the
>no_resolve_on_fork flag is working around has disappeared, but the
>functionality is still there. Is it still needed?
The no_resolve_on_fork removal addresses your question about whether
that flag is still needed -- it was always 0 at every call site, so
the patch drops it entirely.
>* Since it's just data, it seems to me that the initializations of the
>various instances of struct dll_info could actually all be written in C.
The LoadLibrary elision question and the "write dll_info inits in C"
note are out of scope for this patch; happy to look at those separately.
Inline patch
---
winsup/cygwin/autoload.cc | 84 +++++++++++++++++++++++++--------------
1 file changed, 54 insertions(+), 30 deletions(-)
diff --git a/winsup/cygwin/autoload.cc b/winsup/cygwin/autoload.cc
index 7054511b6..c425191b9 100644
--- a/winsup/cygwin/autoload.cc
+++ b/winsup/cygwin/autoload.cc
@@ -85,13 +85,13 @@ bool NO_COPY wsock_started;
The macro WORD64 stands in for .quad/.xword, and .balign (which means
"align to N bytes" on all targets, unlike .align) is used for
alignment. */
-#define LoadDLLprime(dllname, init_also, no_resolve_on_fork) __asm__ ("\n\
+#define LoadDLLprime(dllname, init_also) __asm__ ("\n\
.ifndef " #dllname "_primed \n\
.section .data_cygwin_nocopy,\"w\" \n\
.balign 8 \n\
." #dllname "_info: \n\
" WORD64 " _std_dll_init \n\
- " WORD64 " " #no_resolve_on_fork " \n\
+ " WORD64 " 0 \n\
.long -1 \n\
.balign 8 \n\
" WORD64 " " #init_also " \n\
@@ -108,12 +108,12 @@ bool NO_COPY wsock_started;
#define LoadDLLfuncEx(name, dllname, notimp) \
LoadDLLfuncEx2(name, dllname, notimp, 0)
#define LoadDLLfuncEx2(name, dllname, notimp, err) \
- LoadDLLfuncEx3(name, dllname, notimp, err, 0)
+ LoadDLLfuncEx3(name, dllname, notimp, err)
/* Main DLL setup stuff. */
#if defined(__x86_64__)
-#define LoadDLLfuncEx3(name, dllname, notimp, err, no_resolve_on_fork) \
- LoadDLLprime (dllname, dll_func_load, no_resolve_on_fork) \
+#define LoadDLLfuncEx3(name, dllname, notimp, err) \
+ LoadDLLprime (dllname, dll_func_load) \
__asm__ (" \n\
.section ." #dllname "_autoload_text,\"wx\" \n\
.global " #name " \n\
@@ -138,8 +138,8 @@ _win32_" #name ": \n\
.text \n\
");
#elif defined(__aarch64__)
-#define LoadDLLfuncEx3(name, dllname, notimp, err, no_resolve_on_fork) \
- LoadDLLprime (dllname, dll_func_load, no_resolve_on_fork) \
+#define LoadDLLfuncEx3(name, dllname, notimp, err) \
+ LoadDLLprime (dllname, dll_func_load) \
__asm__ ( "\n\
.section ." #dllname "_autoload_text,\"wx\" \n\
.global " #name " \n\
@@ -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
@@ -438,7 +442,7 @@ std_dll_init (struct func_info *func)
yield ();
}
while (InterlockedIncrement (&dll->here));
- else if ((uintptr_t) dll->handle <= 1)
+ else if (!dll->handle)
{
fenv_t fpuenv;
fegetenv (&fpuenv);
@@ -461,7 +465,7 @@ std_dll_init (struct func_info *func)
if (i < RETRY_COUNT)
yield ();
}
- if ((uintptr_t) dll->handle <= 1)
+ if (!dll->handle)
{
if ((func->decoration & 1))
dll->handle = INVALID_HANDLE_VALUE;
@@ -481,9 +485,29 @@ std_dll_init (struct func_info *func)
/* Initialization function for winsock stuff. */
-#if defined(__x86_64__) || defined(__aarch64__)
+#if defined(__x86_64__)
/* See above comment preceeding 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 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 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 so the 'ret' below tail-chains there\n\
+ add x30, x30, #:lo12:dll_chain // -> dll_chain, which tail-calls x1 (dll_func_load)\n\
+ ret \n\
+ .seh_endproc \n\
+");
#else
#error unimplemented for this target
#endif
@@ -534,7 +558,7 @@ wsock_init (struct func_info *func)
return ret.ll;
}
-LoadDLLprime (ws2_32, _wsock_init, 0)
+LoadDLLprime (ws2_32, _wsock_init)
LoadDLLfunc (CheckTokenMembership, advapi32)
LoadDLLfunc (CreateProcessAsUserW, advapi32)
@@ -711,25 +735,25 @@ LoadDLLfuncEx2 (CreateProfile, userenv, 1, 1)
LoadDLLfunc (DestroyEnvironmentBlock, userenv)
LoadDLLfunc (LoadUserProfileW, userenv)
-LoadDLLfuncEx3 (waveInAddBuffer, winmm, 1, 0, 1)
-LoadDLLfuncEx3 (waveInClose, winmm, 1, 0, 1)
-LoadDLLfuncEx3 (waveInGetNumDevs, winmm, 1, 0, 1)
-LoadDLLfuncEx3 (waveInOpen, winmm, 1, 0, 1)
-LoadDLLfuncEx3 (waveInPrepareHeader, winmm, 1, 0, 1)
-LoadDLLfuncEx3 (waveInReset, winmm, 1, 0, 1)
-LoadDLLfuncEx3 (waveInStart, winmm, 1, 0, 1)
-LoadDLLfuncEx3 (waveInUnprepareHeader, winmm, 1, 0, 1)
-LoadDLLfuncEx3 (waveOutClose, winmm, 1, 0, 1)
-LoadDLLfuncEx3 (waveOutGetNumDevs, winmm, 1, 0, 1)
-LoadDLLfuncEx3 (waveOutGetVolume, winmm, 1, 0, 1)
-LoadDLLfuncEx3 (waveOutOpen, winmm, 1, 0, 1)
-LoadDLLfuncEx3 (waveOutPrepareHeader, winmm, 1, 0, 1)
-LoadDLLfuncEx3 (waveOutReset, winmm, 1, 0, 1)
-LoadDLLfuncEx3 (waveOutSetVolume, winmm, 1, 0, 1)
-LoadDLLfuncEx3 (waveOutUnprepareHeader, winmm, 1, 0, 1)
-LoadDLLfuncEx3 (waveOutWrite, winmm, 1, 0, 1)
-LoadDLLfuncEx3 (waveOutMessage, winmm, 1, 0, 1)
-LoadDLLfuncEx3 (waveOutGetDevCapsA, winmm, 1, 0, 1)
+LoadDLLfuncEx3 (waveInAddBuffer, winmm, 1, 0)
+LoadDLLfuncEx3 (waveInClose, winmm, 1, 0)
+LoadDLLfuncEx3 (waveInGetNumDevs, winmm, 1, 0)
+LoadDLLfuncEx3 (waveInOpen, winmm, 1, 0)
+LoadDLLfuncEx3 (waveInPrepareHeader, winmm, 1, 0)
+LoadDLLfuncEx3 (waveInReset, winmm, 1, 0)
+LoadDLLfuncEx3 (waveInStart, winmm, 1, 0)
+LoadDLLfuncEx3 (waveInUnprepareHeader, winmm, 1, 0)
+LoadDLLfuncEx3 (waveOutClose, winmm, 1, 0)
+LoadDLLfuncEx3 (waveOutGetNumDevs, winmm, 1, 0)
+LoadDLLfuncEx3 (waveOutGetVolume, winmm, 1, 0)
+LoadDLLfuncEx3 (waveOutOpen, winmm, 1, 0)
+LoadDLLfuncEx3 (waveOutPrepareHeader, winmm, 1, 0)
+LoadDLLfuncEx3 (waveOutReset, winmm, 1, 0)
+LoadDLLfuncEx3 (waveOutSetVolume, winmm, 1, 0)
+LoadDLLfuncEx3 (waveOutUnprepareHeader, winmm, 1, 0)
+LoadDLLfuncEx3 (waveOutWrite, winmm, 1, 0)
+LoadDLLfuncEx3 (waveOutMessage, winmm, 1, 0)
+LoadDLLfuncEx3 (waveOutGetDevCapsA, winmm, 1, 0)
LoadDLLfunc (accept, ws2_32)
LoadDLLfunc (bind, ws2_32)
--
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: 9290 bytes
Desc: Cygwin-autoload-fix-ws2_32-chained-init-on-AArch64.patch
URL: <https://cygwin.com/pipermail/cygwin-patches/attachments/20260626/224c1e2a/attachment-0001.obj>
More information about the Cygwin-patches
mailing list