Article: Q50695
Product(s): See article
Version(s): 5.10
Operating System(s): OS/2
Keyword(s): ENDUSER | CRTLIB DLL | mspl13_c
Last Modified: 14-MAR-1990
A design limitation in the C 5.10 library support of Dynamic Link
Libraries (DLL) prevents statically linked, multi-threaded (MT)
.EXE files from calling MT DLL routines. For the present, you
must create your MT EXE files with the C run-time DLL (i.e.,
CRTLIB.LIB).
A specific illustration of this would be the following (assume that
you have the following files):
TheExe.exe: Contains a call to FOOPER, which is defined in TheDLL.dll
TheDLL.dll: Contains the function FOOPER
TheDLL.dll is a multi-threaded DLL, which is linked with CRTLIB.LIB
(the multi-threaded DLL version of the C run time).
In general, the file TheExe.exe can be linked with either LLIBCMT.LIB
or CRTLIB.LIB (depending upon whether you desire a statically or
dynamically linked C run-time). The following are examples of both
link statements:
1. Statically linked with LLIBCMT.LIB:
link TheExe.obj,,,Doscalls.lib Llibcmt.lib/nod, TheExe.def;
2. Dynamically linked with CRTLIB.LIB:
link TheExe.obj Crtexe.obj,,,Doscalls.lib Crtlib.lib/nod,TheExe.def;
However, since this example requires that TheExe.exe call FOO, which
resides in TheDLL.dll, you must link with CRTLIB.LIB as detailed in #2
above.
The common symptom of linking your .EXE with LLIBCMT.LIB and calling a
multi-threaded DLL routine is a General Protection violation (GP
fault) upon entry into the DLL routine. The generated assembly for
this entry is listed below:
pop cx
pop dx
mov bp, sp
push ds
push 154F
pop ds
jb 02A0
mov es, word ptr [005E] <-- es loaded with trash (0)
mov ax, word ptr es:[0006] <-- GP fault.
This is an assumption that is not valid. The loading of ES assumes
that the C run-time DLL data area is already initialized. However, it
was not.
The reason why this initialization did not take place is explained in
the following scenarios:
Note: CRT refers to C run-time.
1. There are multiple C start-up initializations that must occur at
process creation time:
a. TheEXE.EXE -- Has its own start up (__astart).
b. TheDLL.DLL -- Program's DLL must be initialized (C_INIT).
c. C run-time DLL -- CRT's DLL DGROUP must be initialized
(__CRT_INIT).
2. The way these initializations happen are as follows:
a. TheEXE.EXE -- Start up occurs "normally" when __astart gets
control.
b. TheDLL.DLL -- The user DLL has a starting address specified
internally so that OS/2 executes C_INIT each time a new process
connects to it.
c. C run-time DLL -- The CRT DLL initialization needs information
from the EXE start up (e.g. arguments, etc.). Thus, the current
scheme is that the EXE start up (__astart code) explicitly calls
the CRT DLL start-up code (__CRT_INIT).
3. The problem: In this supplied scenario, the problem is that the EXE
is not built with the CRT DLL model; thus, CRTEXE.OBJ is not linked
into the user's program. It is the CRTEXE.OBJ module that makes the
explicit call to __CRT_INIT to init the CRT DLL. Since this init
code never gets called, the CRT's DGROUP is not initialized; later,
when we load a value out of the CRT's DGROUP into ES,
mov es, word ptr [005E] <-- es loaded with trash (0)
mov ax, word ptr es:[0006] <-- GP fault.
the value is invalid and you get the GP fault.
Note: A program is multi-threaded when it is compiled with the
appropriate include files and linked with the libraries that support
multiple threads. A program does not have to call _beginthread() or
DosCreateThread to be multi-threaded.
If a program is compiled and linked as such, then the above problem is
applicable regardless of the number of threads in the program. This
means that a program with no calls to DosCreateThread and/or
_beginthread() will lie within the scope of this problem if it is
built as a multi-threaded executable.