惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

W
WeLiveSecurity
爱范儿
爱范儿
MyScale Blog
MyScale Blog
F
Fortinet All Blogs
Y
Y Combinator Blog
罗磊的独立博客
IT之家
IT之家
人人都是产品经理
人人都是产品经理
Latest news
Latest news
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
Vercel News
Vercel News
K
Kaspersky official blog
WordPress大学
WordPress大学
T
Tailwind CSS Blog
Stack Overflow Blog
Stack Overflow Blog
云风的 BLOG
云风的 BLOG
T
Threatpost
J
Java Code Geeks
美团技术团队
Spread Privacy
Spread Privacy
B
Blog RSS Feed
L
Lohrmann on Cybersecurity
AWS News Blog
AWS News Blog
S
Schneier on Security
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
Hugging Face - Blog
Hugging Face - Blog
NISL@THU
NISL@THU
V
Visual Studio Blog
博客园_首页
V
V2EX
Cyberwarzone
Cyberwarzone
The Hacker News
The Hacker News
Last Week in AI
Last Week in AI
G
GRAHAM CLULEY
A
About on SuperTechFans
N
News | PayPal Newsroom
G
Google Developers Blog
N
Netflix TechBlog - Medium
The Cloudflare Blog
www.infosecurity-magazine.com
www.infosecurity-magazine.com
有赞技术团队
有赞技术团队
L
LINUX DO - 最新话题
博客园 - 司徒正美
The Last Watchdog
The Last Watchdog
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
小众软件
小众软件
Forbes - Security
Forbes - Security
V
Vulnerabilities – Threatpost
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
Google DeepMind News
Google DeepMind News

博客园 - floerggyy

vs下调试多个c项目联调 C语言locale介绍 C语言宏定义总结 原码、反码、补码 Endian的由来及big-edian 和little-endian 转载 zip文件格式 C 语言 相关资源 精选 zlib usage 一段垃圾的代码(附malloc,calloc和realloc使用小结) 转载 关于gcc的dlltool和dllwrap工具 技术转载(鼠标点击X窗口关闭IE的同时清空session,最基本的就是处理用户重复登陆需要用到,我想这个的关键在于如何捕捉到关闭IE这个动作,之后再根据自身的需要使用session.invalidate()或者session.removeAttribute( "xxx ")) dotnet oracle摘自msdn 被遗忘了的生日 这处站点真NB!! 数学表达式逻辑表达式混合计算 Are you a vender or manager? did you fix these bugs hotmail 附件上传何以如此霸道
Stdcall and DLL tools of MSVC and MinGW
floerggyy · 2008-02-13 · via 博客园 - floerggyy

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 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 data items 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 left side of the "=" sign is an exported name and the right side the internal name). 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 already shows 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. However, we can force both forms of exports with the following lines in the EXPORTS section:

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

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     &nbbsp;                    Remove @nn from exported symbols
--out-implib <file>   &nnbsp;            Generate import library
--output-def <file>   &nnbsp;            Generate a .DEF file for the built DLL

Either gcc or ld can accept a DEF file directly on the command line. When a function (say,

TestFunction@4

) is marked as __declspec(dllexport), and we have the following line in the EXPORTS section,

TestFunction = TestFunction@4

both symbols will be exported to the DLL (LINK has similar behaviour too). 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 in the 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 let dlltool do it. Unlike LINK or ld, dllwrap will ignore the export specifications in an object file, and will not export a name unless it is specifically listed as an exported name in the EXPORTS section (unless one does not use a DEF file at all).

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>   &nnbsp;   Name of input dll to put into interface lib.
-d --input-def <deffile>  Name of  .def file to be read in.
-U --add-underscore   &nbspp;   Add underscores to symbols in interface library.
-k --kill-at     ;         Kill @<n> from exported names.

dlltool works like LIB, and similarly it will ignore the part after the equal-sign in a DEF file, but it has its special features that somehow compensate for this shortcoming:

  • 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 download here if you 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 (search on 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 (dllexport)' 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

At this step, you may also want to generate a DEF file to make the DLL usable with MinGW source.

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

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
2004-9-9, last updated by Wu Yongwei