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

标签 c winapi dll linker

如果我这样声明一个函数:

#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 库中,符号将是 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。然而,当我们使用 dumpbin/exports 命令查看 advapi32.dll 导出时,我们看到一个未修饰的名称:

advapi exports

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

enter image description here

注意 undecorate 说明符,它允许将修饰名称链接到未修饰的导出。您可以使用包含未修饰名称的 EXPORTS 部分的 def 文件为您的 dll 实现相同的结果。参见 this文章和this answer获取更多信息。

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

The form of decoration for a C function depends on the calling convention used in its declaration, as shown in the following table. This is also the decoration format that is used when C++ code is declared to have extern "C" linkage. The default calling convention is __cdecl. Note that in a 64-bit environment, functions are not decorated.

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

相关文章:

c - 验证签名/证书的最佳方法是什么?

c++ - 不使用 SetWindowText 更改任务栏文本

c++ - 减少我的 boost lib 文件夹

c - NVAPI 设备 ID 与 CUDA 设备 ID 有何关系?

c - 如何从 mongodb C 驱动程序结果中过滤掉 "_id"

c# - 局部敏感哈希实现?

c++ - 使用视觉样式设置 WinAPI 工具栏的背景色?

c - 为什么在不需要时费心使用 float / double 文字?

c# - 如何在 MessageBox 上显示 FARPROC 内存地址

c# - 无法加载文件或程序集 'System.Web.Mvc' 或其依赖项之一。 2个项目。一次只有一个会工作