在Visual Studio中,我想仅通过序数从dll导出函数。在源代码中,我将函数定义为:
int my_function() { return 101; } // without declspec(dllexport)
在.def文件中:
LIBRARY MyDll
EXPORTS
my_function @ 1 NONAME // NONAME, export directory will not contain function name
在主程序中,我使用它:
#pragma comment(lib, "MyDll.lib")
declspec(dllimport) int my_function();
int main(int argc, char* argv[])
{
int a = my_function();
return 0;
}
代码编译和链接很好。记录NONAME
属性仅按序数导出函数。
MyDll的导出目录NumberOfNames
设置为零,因此dll本身不包含名称信息。 exe文件按顺序值导入函数,因此exe也不包含名称信息。
我尝试了不同的配置(调试,发布),程序链接仍然很好。也许lib文件包含函数名和序数之间的某种映射?我读到lib文件包含函数thunks,所以我们可以在lib文件中有这样的东西:
my_function @ 1:
jmp IAT[0]
my_another_function @ 2:
jmp IAT[1]
and-file exe导入表:
OriginalFirstThunk FirstThunk
0x80000001 (@ 1) 0x80000001 (@ 1) // ordinal 1 will go through IAT[0]
0x80000002 (@ 2) 0x80000002 (@ 2) // ordinal 2 will go through IAT[1]
内存exe导入表:
OriginalFirstThunk FirstThunk
0x80000001 (@ 1) IAT[0]
0x80000002 (@ 2) IAT[1]
如果是这样,那么为了隐藏功能名称,我们应该只提供dll文件,这意味着用户需要使用LoadLibrary
加载dll并使用GetProcessAddress
?我在这里缺少什么?
答案 0 :(得分:0)
来自MSDN上的Exporting Functions from a DLL by Ordinal Rather Than by Name:
如果要优化DLL的文件大小,请在每个导出的函数上使用NONAME属性。使用NONAME属性,序数存储在DLL的导出表中,而不是函数名称中。如果您要导出许多功能,这可以节省很多。
换句话说,NONAME只影响DLL,而不影响导入库。所以你观察到的行为是按预期的。
可选关键字PRIVATE可防止entryname包含在LINK生成的导入库中。
因此,如果你同时使用PRIVATE和NONAME,你应该得到你想要的结果。然而,这首先打破了提供导入库的目的,至少就该特定功能而言。如果你想要一些可以通过导入库访问的函数,以及一些只能通过GetProcAddress访问的函数,这可能会很有用。
您可能更愿意为最终用户可用于链接的功能提供别名,例如,
LIBRARY MyDll
EXPORTS
function1=my_function @ 1 NONAME
function2=my_other_function @ 2 NONAME
这应该把假名" function1"和"功能2"进入导入库,以便最终用户可以使用这些名称链接到函数,同时仍然隐藏秘密名称" my_function"和" my_other_function"在导入库和DLL中。 (不是我理解为什么名字首先需要保密,而是YMMV。)
免责声明:我自己没有尝试过,这个答案完全基于文档。