From: khan AT xraylith DOT wisc DOT edu (Mumit Khan) Subject: Analysis of non-cygwin app loading cygwin DLL problem 28 Oct 1998 16:09:18 -0800 Message-ID: <9810282342.AA29302.cygnus.cygwin32.developers@modi.xraylith.wisc.edu> To: cygwin32-developers AT cygnus DOT com Here's some analysis of the problem I had reported earlier on not being able to load a cygwin DLL correctly from a non-cygwin main app (such as mingw or msvc or borland). This is applicable in both cases of using a DLL -- linking against an import library or loading it dynamically using LoadLibrary/GetProcAddress API. Here're the 3 common scenarios: # Main App DLL Result === ======== ========= ======== 1 cygwin cygwin OK 2 cygwin non-cygwin OK 3 non-cygwin cygwin CRASH! The last one is standing in the way of using EGCS/Cygwin as a viable replacement for MSVC for various applications, such as for JAVA JNI (and with that I conclude the marketing portion of this message ;-). I'll assume the use of DECLARE_CYGWIN_DLL(DllMain) here, and so the entry point, _cygwin32_dll_entry AT 12, is the key here. Please see for the body of _cygwin32_dll_entry AT 12 if you're not familiar with it. In all 3 cases, the entry point is the first step in the DLL initialization, which then in turn calls cygwin32_attach_dll to get things rolling. Here's what happens during DLL initialization in cases 1 and 3 (Case 2 is irrelevant for the purposes of this bug): Case 1. We start at _cygwin32_dll_entry AT 12: -> _cygwin32_dll_entry AT 12 [ case DLL_PROCESS_ATTACH ] -> cygwin32_attach_dll [ HANDLE, User DLL Main ] -> cygwin_crt0_common -> dll_dllcrt0 [ HANDLE, per_process * ] -> the_.recordDll [ HANDLE, per_process * ] Case 3. Ditto. -> _cygwin32_dll_entry AT 12 [ case DLL_PROCESS_ATTACH ] -> cygwin32_attach_dll [ HANDLE, User DLL Main ] -> cygwin_crt0_common -> dll_dllcrt0 [ HANDLE, per_process * ] [ >>>>> POSSIBLE FIX WILL KICK-START CYGWIN DLL HERE <<<<<< ] -> the_.recordDll [ HANDLE, per_process * ] They look the same so far, so where's the problem? Let's take a look inside ``DllList::recordDll (HANDLE, per_process *)'' int DllList::recordDll (HANDLE, per_process *) { // ... if (_initCalled) // main module is already initialized { if (!initOneDll (p)) ret = -1; } // ... } The variable _initCalled is 1 for Case 1 -- which means that the user and process info are already initialized for Case 1 (makes sense since the main program is also dependent on Cygwin DLL and dcrt0 did the right thing by calling ``DllList::initAll()''), *BUT*, it's 0 for Case 3 -- which means that various stuff that's done in DllList::initAll() is now MISSING here. Looking in more detail, things such as the reentrant data, application heap, signals, threads stuff, etc are also not initialized in Case 3 either, and that points me towards what dll_dcrt0_1 does when a Cygwin app is kicked from crt0. So, basically we need something similar to dll_crt0_1 that is called from dll_dllcrt0 to initialize the various state information in Cygwin when a Cygwin DLL is loaded for the first time by a non-cygwin app. My pitiful attempts to figure out what needs to be initialized by copying various portions of dll_crt0_1 into dll_dllcrt0 have failed miserably so far; I'm hoping others familiar with winsup internals will know the fix right away. Regards, Mumit