Stdcall and DLL tools of MSVC and MinGW

The __stdcall calling convention has been there for a very long time. While older calling conventions like __pascal fell into oblivion, __stdcall became the standard calling convention of Win32 API functions. Unlike __cdecl (the native calling convention of C/C++), it is supported in C/C++, Visual Basic, Java, and other languages alike, which makes it the first choice when building a DLL for cross-language use.

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) attribute affects its naming decoration)! And although the ending decoration clearly shows how many bytes the called function pops up from stack before returning, it is not necessarily the most frequently used form. E.g., the Win32 API functions in the system DLLs have no decoration at all, as in the case ones uses a DEF file when exporting functions with MSVC. Many DLLs intended for multi-language usage also follow this practice and use no decoration with __stdcall functions (although the Java Native Interface, on Win32 platforms, will accept functions either undecorated or decorated in the Microsoft way, the latter being the preferred form). The remaining part of this article is thus devoted to the creation and use of such DLLs with MSVC and MinGW, as well as the introduction and comparison of related tools (there are good articles explaining the complexities of DLLs with Borland C++ Builder, so I need not bother to say anything more about it).

Tools working with DEF files

DEF file format

LIBRARY testdll.dll EXPORTS cdeclFunction @1 _stdcallFunction@8 @2 aliasName = cdeclFunction @3

CL

cl /LD testdll.obj testdll.def

link /out:testdll.dll /dll /implib:testdll.lib /def:testdll.def testdll.obj

LINK

_Function@n

Function

_Function@n

TestFunction = _TestFunction@4 _TestFunction@4 = _TestFunction@4

LIB

lib /def:DEF_file

_Function

Function

:-)

gcc

-shared

-Wl

ld

--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

TestFunction@4

TestFunction = TestFunction@4

dllwrap

dllwrap --def DEF_file -o DLL_file OBJ_files [--output-lib LIB_file]

( --output-lib ),

dlltool

-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 -U option makes the items in the DEF file map to symbols prefixed with an underscore in the DLL, and

option makes the items in the DEF file map to symbols prefixed with an underscore in the DLL, and the -k option makes the items in the DEF file map to symbols stripped of @n in the DLL.

pexports

The __stdcall DLL and the import library

Microsoft Visual C++

/LD

cl /LD OBJ_files

_MyFunction@8

(dllexport)

link /out:DLL_file /dll OBJ_files pexports DLL_file | sed "s/^_\([[:alnum:]_]\+\)@[[:digit:]]\+/\1/" > DEF_file

pexports DLL_file | sed "s/^_\([[:alnum:]_]\+\)\(@[[:digit:]]\+\)/\1\2/" > DEF_for_gcc

link /out:DLL_file /dll /def:DEF_file /implib:LIB_file OBJ_files

MinGW GCC

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

gcc -shared -o DLL_file OBJ_files -Wl,--kill-at,--output-def,DEF_file

Function = Function@n @Ordinal

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

2004-9-9, last updated by Wu Yongwei