c - 在跨 dll 边界访问导出的全局变量时检测缺少的 __declspec(dllimport)

标签 c windows winapi dll linker

我正在为 PostgreSQL 项目的 Windows 支持中的一个有趣的新问题寻找解决方案。

当插件 DLL 被加载到带有 LoadLibrary 的主可执行文件中时调用他们期望动态链接器解析对 postgres.exe 公开的函数和全局变量 的引用.

很容易忘记输入 __declspec(dllimport)注释,或者更确切地说,PGDLLIMPORTextern 上扩展到它的宏这是通过 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/

相关文章:

C18 : Will the compiler "know" a function call will never return?

windows - 从我的应用程序打开由我的服务创建的事件对象

c++ - 如何可靠地检查一个 Windows 进程是否是 C++ 中另一个进程的父进程?

windows - 从 Windows 服务调用 MSIGetProductInfo 返回垃圾值

html - 通过html链接将参数传递给程序

delphi - 如何显示一个像弹出菜单一样的窗口?

c - 弃用/废弃某些 Linux 时间 API 的原因是什么?

c - 子进程退出时父进程应该如何关闭管道文件描述符

c - 如何在 linux C 中保持非事件的 TCP 连接?

python - 在 For 循环中从 Windows 批处理文件中的数组访问项目