确定 DLL 的符号名称

Determining symbol names of the DLL

本文关键字:符号 DLL 确定      更新时间:2023-10-16

我使用过"CPPLoadLibrary"示例(来自Microsoft多合一框架(好的,有两种方法可以从示例 DLL 导出符号。

  1. 使用 从 DLL 导出符号。DEF 文件模块定义 (.DEF( 文件是包含一个或多个模块的文本文件描述 DLL 的各种属性的语句。创建一个 .DEF 文件和在生成 DLL 时使用 .def 文件。使用这种方法,我们可以导出DLL 中的函数按序号而不是按名称。
  2. 使用 __declspec 从 DLL 导出符号(dllexport(__declspec(dllexport(将导出指令添加到目标文件中,因此我们这样做不需要使用 .def 文件。这种便利在尝试导出修饰C++函数名称。

所以我们有以下代码。

typedef int     (_cdecl* LPFNGETSTRINGLENGTH1)      (PCWSTR);
typedef int     (CALLBACK* LPFNGETSTRINGLENGTH2)    (PCWSTR);
LPFNGETSTRINGLENGTH1 lpfnGetStringLength1 = (LPFNGETSTRINGLENGTH1) 
    GetProcAddress(hModule, "GetStringLength1");
LPFNGETSTRINGLENGTH2 lpfnGetStringLength2 = (LPFNGETSTRINGLENGTH2) 
    GetProcAddress(hModule, "_GetStringLength2@4");

所以我的问题是如何确定符号的名称才能调用 GetProcAddress?在第一种情况下,它非常简单,我们从 中获取该符号名称。DEF 文件。但是"_GetStringLength2@4"呢什么是下划线?"@4"代表什么?谢谢。

如果不使用 .DEF 文件,导出名称根据其调用约定进行修饰,以支持导出重载函数。 请参阅为什么我无法获取我导出的函数的 GetProcAddress?:

装饰方案因建筑而异

,因建筑而异,因称呼惯例而异。因此,例如,如果函数是从 PPC DLL 导出的,则必须执行GetProcAddress(hinst, "..SomeFunction"),但如果将其从 80386 DLL 导出为 extern "C" __stdcall ,则需要GetProcAddress(hinst, "_SomeFunction@8"),但如果它是__fastcall则需要GetProcAddress(hinst, "@SomeFunction@8")

更重要的是,C++装饰因编译器供应商而异。如果使用 Microsoft C++ 编译器编译,则导出C++函数可能需要 GetProcAddress(hinst, "?SomeFunction@@YGXHH@Z"),但如果使用 Borland C++编译器编译,则可能需要其他一些修饰字符串。

因此,如果您希望人们能够GetProcAddress函数,并且希望您的代码可移植到多个平台,或者如果您希望他们能够从 C/C++ 以外的语言使用 DLL 或使用不同于 Microsoft Visual Studio 的C++编译器,则必须通过函数的未修饰名称导出函数。

有关各种名称修饰方案的说明,请参阅调用约定的历史,第 3 部分。 在这种情况下,该函数使用 __stdcall 调用约定,因此它通过在下划线前面加上一个@符号以及它所采用的参数的字节数来修饰。 它需要一个字大小的参数,总共 4 个字节,所以它被装饰为 _GetStringLength2@4 .

若要回答实际问题,请使用编译器的 TDUMP 或类似工具,或任何其他可以显示可执行文件导出表的工具,以便查看实际导出的名称。