delorie.com/archives/browse.cgi   search  
Mail Archives: cygwin-developers/1998/10/28/16:09:18

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 
<cygwin32/cygwin_dll.h> 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

- Raw text -


  webmaster     delorie software   privacy  
  Copyright 2019   by DJ Delorie     Updated Jul 2019