The internal representations of both __cdecl and __stdcall functions have decorations. In MSVC (Microsoft Visual C++) and MinGW (Minimalistic GNU for Windows) GCC, __cdecl function will be prefixed an underscore, and __stdcall functions will have the beginning underscore as well as be appended by the at-sign (@) followed by the number of bytes in the argument list. So, double __cdecl sin(double) will be decorated as _sin, and double __stdcall sin(double) will be decorated as _sin@8.
But things are not that simple. The decorations could change when they
appear in DLLs or when they are produced by different compilers. The following
table lists the names as are produced by MSVC, MinGW, Digital Mars C/C++
Compiler (DMC), Borland C++ Compiler/C++ Builder (BCC):
Calling Convention | Internal* | MSVC DLL (w/ DEF) | MSVC DLL (dllexport) | DMC DLL | MinGW DLL | BCC DLL |
__stdcall | _Function@n | Function | _Function@n | _Function@n | Function@n | Function |
__cdecl | _Function | Function | Function | Function | Function | _Function |
* For all but BCC, which has the same naming convention for symbols in code and exported name in DLL.
What a mess (especially when you notice that, for MSVC, whether a
name is exported by a DEF file or by the
__declspec(dllexport)
This DEF file defines three exports for a testdll.dll: the first one is a __cdecl function, the second one a __stdcall function, and the third one an alias of the first function. The three functions are also assigned ordinals. A function can be called by its name or its ordinal.LIBRARY testdll.dll EXPORTS cdeclFunction @1 _stdcallFunction@8 @2 aliasName = cdeclFunction @3
will becomecl /LD testdll.obj testdll.def
link /out:testdll.dll /dll /implib:testdll.lib /def:testdll.def testdll.obj
Another thing to notice when we use the above line: LINK will export both TestFunction (or any alias name) and _TestFunction@4 from the DLL, but only _TestFunction@4 (the internal name) will be output to the import library: in no case will a program linked with the import library call the function by TestFunction!TestFunction = _TestFunction@4
Nota bene: 1) it seems LIB does not accept aliased forms (it will simply ignore the part after the equal-sign); 2) it assumes all functions in the DEF file __cdecl. The second point lies in the fact that the import library it produces will map each symbol in the DLL to an internal name with an underscore prefixed, i.e., the linker using the import library will try to resolve an undefined symbol _Function to the symbol Function in the DLL. It takes no special care of the __stdcall calling convention. With some techniques we could use LIB to produce import libraries for __stdcall functions, but the caller could only call them by ordinal, not by name. The details are left as an exerciselib /def:DEF_file
Either gcc or ld can accept a DEF file directly on the command line. When we have the following line in the EXPORTS section,--add-stdcall-alias Export symbols with and without @nn --kill-at Remove @nn from exported symbols --out-implib <file> Generate import library --output-def <file> Generate a .DEF file for the built DLL
both symbols will be exported to the DLL. This behaviour is different from dllwrap, which we shall talk of immediately.TestFunction = TestFunction@4
and dllwrap will transparently call gcc, ld, and dlltool to fulfil its task. If dllwrap is asked to produce an import library (dllwrap --def DEF_file -o DLL_file OBJ_files [--output-lib LIB_file]
it will export TestFunction but not TestFunction@4, and only TestFunction is output to the import library (somehow similar to LIB).TestFunction = TestFunction@4
dlltool works like LIB, but it has its special feature: the-l --output-lib <outname> Generate an interface library. -D --dllname <name> Name of input dll to put into interface lib. -d --input-def <deffile> Name of .def file to be read in. -U --add-underscore Add underscores to symbols in interface library. -k --kill-at Kill @<n> from exported names.
The resulting DLL will have exported names like _MyFunction@8, as is shown in the `MSVC DLL (no DEF)' column above. To create symbols with no decoration, we must use a DEF file. The following is an automatic way to create a DEF file from the DLL if __declspec(dllexport) is used to indicate which functions to export:cl /LD OBJ_files
Once you have the object files and the DEF file, creating the DLL and the import library can be done in one step:link /out:DLL_file /dll OBJ_files pexports DLL_file | sed "s/^_\([[:alnum:]_]\+\)@[[:digit:]]\+/\1/" > DEF_file
And you are free to use the DLL and the import library now as you wish.link /out:DLL_file /dll /def:DEF_file /implib:LIB_file OBJ_files
If we want to use a DEF file to control which functions to export, we can start by (assuming __declspec(dllexport) is used to indicate which functions to export)gcc -shared -o DLL_file OBJ_files -Wl,--output-def,DEF_file gcc -shared -o DLL_file OBJ_files -Wl,--kill-at dlltool -d DEF_file --dllname DLL_file --output-lib LIB_file --kill-at
to produce a DEF file with exports like "Function = Function@n @Ordinal". After editing it to our will, the following commands will finish the job:gcc -shared -o DLL_file OBJ_files -Wl,--kill-at,--output-def,DEF_file
And the import library is now at your hand to use.dllwrap --def DEF_file -o DLL_file OBJ_files sed "s/[[:alnum:]_]\+ *= *//" DEF_file > New_DEF_file dlltool -d New_DEF_file --dllname DLL_file --output-lib LIB_file --kill-at
I am not sure whether I have stated clearly, but I have listed all my findings when I struggled to find out how to use the DLL tools properly and how to deal with __stdcall functions in DLLs. Hope you find it useful.
ACKNOWLEDGEMENT: The MinGW mailing list provided much useful information; Luke Dunstan provided important suggestions and corrections.
2002-8-20, written by Wu Yongwei
2003-3-6, last revised by Wu Yongwei