如果我声明这样的函数:

#ifdef TEST_EXPORTS
#define TEST_API __declspec(dllexport)
#else
#define TEST_API __declspec(dllimport)
#endif

TESTAPI int __stdcall myadd(int a, int b);

DLL中的符号是_myadd@8,对我来说非常有意义(就是在阅读了几个小时的其他问题之后)。

但是Windows库似乎做了一些不同的事情。它们还使用__stdcall(伪装为WINAPI),但是DLL中的符号没有名称修饰。如果以上方法在Windows libs中的何处,则该符号将为myadd

我的猜测是,他们使用def文件为符号添加别名。但是,当我链接到这些DLL之一时,为什么我的链接器知道这一点?

Windows头文件使用WINAPI声明了这些函数,因此,如果我调用它们,则链接器应查找修饰后的名称,因为它是__stdcall函数。但是,链接器不知何故知道删除名称修饰。

我试图通过编写一个小的DLL并删除带有def文件的名称修饰来复制此内容。正如预期的那样,由于链接器仍在寻找修饰的名称,因此出现链接器错误。我已经在纯C语言中做到了这一点,以确保c++名称修饰不会影响它。

编辑:澄清一下,MSVC 14.0/VS2015,32位

最佳答案

这里有一些鲜为人知的魔术在起作用。让我们来看一些WIN32 API函数,例如RegQueryValueExW。像这样在winreg.h文件中定义它:

WINADVAPI LSTATUS APIENTRY RegQueryValueExW(...);

其中WIADVAPI__declspec(dllimport),而APIENTRY__stdcall命名约定的绰号。还要注意, header 中的所有函数都声明为extern "C"。因此,无论如何,此函数应使用名称修饰,并且其DLL导出应为_RegQueryValueExW@24。但是,当我们使用advapi32.dll命令查看dumpbin /exports导出时,我们看到一个未修饰的名称:

c - 使用__stdcall的DLL,不带名称修饰: why does it even work?-LMLPHP

现在,让我们使用advapi32.lib命令仔细检查dumpbin /headers advapi32.lib文件:

c - 使用__stdcall的DLL,不带名称修饰: why does it even work?-LMLPHP

请注意undecorate说明符,该说明符允许将修饰的名称链接到未修饰的导出。您可以使用def节的EXPORTS节包含未经修饰的名称来为您的dll实现相同的结果。有关更多信息,请参见this文章和this answer

另外,上面编写的所有内容仅对x86应用程序有效。 x64位环境中的C函数链接到without name decoration:

关于c - 使用__stdcall的DLL,不带名称修饰: why does it even work?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/38710243/

10-11 22:43