Stdcall and DLL tools of MSVC and MinGW
2012-02-26 15:58
204 查看
Stdcall and DLL tools of MSVC and MinGW
The __stdcall calling convention has been there for a very long time. When the older calling conventionslike __pascal fell into oblivion, __stdcallbecame
the standard calling conventions 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 |
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 beforereturning, 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 at http://www.bcbdev.com/articles.htm 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
First, I will talk about the DEF file format and the relevant tools used with MSVC and MinGW. Many intricacies lie here.DEF file format
We care about only two sections of the DEF file: the LIBRARY section and the EXPORTS section. The LIBRARY section specifies the internal name of the DLL; and the EXPORTS section specifies the function or dataitems to export. A short example follows:
LIBRARY testdll.dll EXPORTS cdeclFunction @1 _stdcallFunction@8 @2 aliasName = cdeclFunction @3
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.
CL
CL can accept a DEF file on the command line, and it simply passes the file name to LINK.E.g.,
cl /LD testdll.obj testdll.def
will become
link /out:testdll.dll /dll /implib:testdll.lib /def:testdll.def testdll.obj
LINK
LINK is our most important tool when treating DLL and DEF files with MSVC. The command line mentioned in CL alreadyshows the options commonly used when creating a DLL with a DEF file. The main point is: if we do not use a DEF file when creating a DLL, the exported name of a __stdcall function
will be_Function@n; but if we use a DEF file, the exported name could be either Function or _Function@n;
if both names appear, only the undecorated form is used. But it is possible to get both forms of exports (similar to the --add-stdcall-alias option of GNU ld and dllwrap),
when we have the following line in the EXPORTS section (notice that the order cannot be reversed):
TestFunction = _TestFunction@4
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 byTestFunction!
LIB
If we have the DLL from somebody else (no source available), and we have the DEF file, the easiest way to create an import library is to use the LIB tool.The following syntax is often enough (check MSDN for more details):
lib /def:DEF_file
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 exercise :-).
gcc
Here we use gcc to call ld.The reason why we do not use ld directly is that using gcc is
generally more convenient. The -shared option is specially designed to produce DLLs. We could also use the -Wl option
to pass special link options.
ld
GNU ld has many options regarding DLLs, but we shall only focus on four (help information follows):--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
Either gcc or ld can
accept a DEF file directly on the command line. When we have the following line in the EXPORTS section,
TestFunction = TestFunction@4
both symbols will be exported to the DLL. This behaviour is different from dllwrap, which we shall
talk of immediately.
dllwrap
GNU dllwrap could produce a DLL by a DEF file. We generally use dllwrap inthe following syntax,
dllwrap --def DEF_file -o DLL_file OBJ_files [--output-lib LIB_file]
and dllwrap will transparently call gcc, ld,
and dlltool to fulfil its task. If dllwrap is
asked to produce an import library (--output-lib), it will letdlltool do
it. Unlike LINK or ld, when dllwrap encounters
a line in the EXPORTS section like
TestFunction = TestFunction@4
it will export TestFunction but not TestFunction@4, and only TestFunction is
output to the import library (somehow similar to LIB).
dlltool
GNU dlltool may be used to create the files needed to build and use dynamic link libraries (DLLs).The following options are of interest to us currently:
-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.
dlltool works like LIB, but it has its special
feature: the -U 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
This is a stand-alone open-source tool to produce a DEF file from a given DLL. It is not distributed with MSVC or MinGW, and you may choose to downloadhere ifyou do not find it elsewhere.
The __stdcall DLL and the import library
Having learnt so much about the tools, now we are ready to do what we wanted. We still need sed (searchon the Internet if you do not already have this useful tool), and a knowledge of regular expression is required to understand thoroughly how it works.
Microsoft Visual C++
The simplest way to produce a DLL is to use the /LD command-line option of CL:cl /LD OBJ_files
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:
link /out:DLL_file /dll OBJ_files pexports DLL_file | sed "s/^_\([[:alnum:]_]\+\)@[[:digit:]]\+/\1/" > DEF_file
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 /def:DEF_file /implib:LIB_file OBJ_files
And you are free to use the DLL and the import library now as you wish.
MinGW GCC
If we do not need to control which functions to export except by __declspec(dllexport), we can type: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
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,--kill-at,--output-def,DEF_file
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:
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
And the import library is now at your hand to use.
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
Return to Main
相关文章推荐
- Stdcall and DLL tools of MSVC and MinGW
- MSVC和MinGW的DLL工具(Stdcall and DLL tools of MSVC and MinGW)(转帖)
- [转]Stdcall and DLL tools of MSVC and MinGW
- [Windows]_[初级]_[MSVC and MinGW DLLs]
- Debugging Tools for Windows - List of Tools and Documentation
- MSVC vs. MinGW 之dll玩转攻略手记
- MSVC vs. MinGW 之 (lib,dll,def,obj,exe) vs (a,dll,def,o,exe) 玩转攻略手记_Kaien Space
- The list of vision-based SLAM / Visual Odometry open source projects, libraries, dataset, tools, and
- Development environment and tools of device driver(一)
- The Design and Implementation of Two-dimensional Vector Graphics Interactive Tools Based on “Smart Handle”
- [Windows]_[初级]_[MSVC and MinGW DLLs]
- PLSQL Tools for query primary key and foreign key of a table
- MSVC vs. MinGW 之 (lib,dll,def,obj,exe) vs (a,dll,def,o,exe) 玩转攻略手记
- 命令行编译程序 MSVC vs. MinGW 之 (lib,dll,def,obj,exe) vs (a,dll,def,o,exe)
- msvc and mingw call eachother
- cmake:让mingw(gcc)生成MSVC可用的dll(.lib)
- MSVC and MinGW DLLs
- MSVC vs. MinGW 之 (lib,dll,def,obj,exe) vs (a,dll,def,o,exe) 攻略
- TACAS(International Conference on Tools and Algorithms for the Construction and Analysis of Systems)到底是什么档次的会议?
- MSVC vs. MinGW 之dll玩转攻略手记【转