我正在为 PostgreSQL 项目的 Windows 支持中的一个有趣的新问题寻找解决方案。
当插件 DLL 被加载到带有 LoadLibrary
的主可执行文件中时调用他们期望动态链接器解析对 postgres.exe
公开的函数和全局变量 的引用.
很容易忘记输入 __declspec(dllimport)
注释,或者更确切地说,PGDLLIMPORT
在 extern
上扩展到它的宏这是通过 DLL 访问的,因为几乎所有 PostgreSQL 开发和测试都发生在 Linux 和 OS X 上,这些东西都不适用。
该项目依靠自动化测试来检测何时出现 __declspec(dllimport)
缺少函数,因为这会导致链接器错误。直到昨天,假设对于全局变量也是如此,但事实并非如此;事实证明,动态链接默默地成功,产生了垃圾结果。
所以 - 我正在寻找有关如何检测和防止此类非法访问的建议,其中全局不是 __declspec(dllimport)
'ed.
在 Windows 上,PostgreSQL 的构建系统会生成 .def
,这让事情变得复杂了。只导出所有内容的文件。 (不是我做的,但我无法改变它,是的,我知道)。这意味着即使没有 PGDLLIMPORT
标记站点 __declspec(dllexport)
在构建主要可执行文件期间,仍会导出该符号。
想法?有没有办法让链接器在 extern
时抛出运行时错误? global 在另一个模块中定义,extern
不正确 __declspec(dllimport)
注释了吗?
如果项目停止生成 .def 文件,而是使用 PGDLLIMPORT
扩展为 __declspec(dllexport)
的注释编译 .exe 时,__declspec(dllimport)
在编译使用 exe 的 API 的插件时,当符号未正确注释时会产生链接器错误吗?有什么替代方案吗?
我目前正在寻找更多信息,我将编写一些测试程序来尝试测试想法,但我远不是 Windows 开发方面的专家,我正在寻找权威的“the正确的方法”,如果可能的话。
最佳答案
最好的方法是在链接器的.def
文件中明确说明您导出的是数据,而不是代码:
EXPORTS
i1 DATA
i2 DATA
或者根本不使用.def
。它优先并将导出的符号默认为 code
。
让我们看看当您将插件链接到这种格式错误的 .lib
文件时会发生什么。并假设您声明:
int __declspec(dllimport) i1;
extern int i2;
这意味着您的 .obj
文件将具有外部依赖项 __imp__i1
和 _i2
。而第一个将指向真正导入的符号,jmp
-stub
jmp [addr] ; FF 25 xx xx xx xx
将为第二个生成('因为它被认为是代码符号),这是为了修复两种调用之间的差异:
call [addr] ; FF 15 xx xx xx xx
call addr ; E8 xx xx xx xx
因此,您的i2
将实际指向jmp-stub 的代码段地址,因此它的值将是0x?????25ff
。
关于c - 在跨 dll 边界访问导出的全局变量时检测缺少的 __declspec(dllimport),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21568431/