在关于跨 dll 边界检测到全局变量的错误链接的问题之后,事实证明我需要修改 PostgreSQL 项目使用的 .DEF 文件生成器工具,以便它正确地DATA
为全局变量的 .DEF 条目发出标签。
问题
我似乎无法找到一种方法,使用 Microsoft 的工具来获取区分全局变量和函数的符号表列表,其中包括未在其定义站点初始化的全局变量。
想法?
断流方法
该工具循环dumpbin /symbols
输出以生成 .DEF 文件。与nm
我习惯的不同,dumpbin /symbols
似乎不会为每个符号发出一个条目来指示符号类型 - 函数、初始化变量、未初始化变量。它只显示符号是否在本地定义。
每个dumpbin
输出行后跟.c
文件中的相应定义,我们首先有一个初始化的全局:
00B 00000000 SECT3 notype External | _DefaultXactIsoLevel
int DefaultXactIsoLevel = XACT_READ_COMMITTED;
与具有非静态链接的函数:
022 00000030 SECT5 notype () External | _IsAbortedTransactionBlockState
bool IsAbortedTransactionBlockState(void) {...}
...并且为了获得额外的乐趣,未初始化的全局变量似乎显示为UNDEF
,就像对来自其他编译单元的符号的引用一样,例如:
007 00000004 UNDEF notype External | _XactIsoLevel
int XactIsoLevel;
即使这是在编译期间在标头中预先声明的(为了便于阅读而扩展了项目特定的宏):
extern __declspec(dllexport) int XactIsoLevel;
所以......看起来dumpbin
输出不包含足够的信息来生成正确的.DEF
文件。
现在gendefs.pl
正在愉快地吐出一个.DEF
文件,该文件省略了未初始化的全局变量,并将其他所有内容声明为代码(通过未能指定CONSTANT
或DATA
在 .DEF 中)。对于如此破碎的东西,它工作得非常好。
修复它
为了生成正确的 .DEF 文件,我需要一种方法来确定哪些符号是变量。
我查看了 usingcl.exe
的/Fm
选项,但它只是链接器选项的传递/MAP
,当您只是生成一个目标文件而不是链接它时什么都不做。
我可以使用生成更多有用信息的符号转储工具,例如 gcc's nm.exe
,但这会增加额外的工具依赖性并且看起来很脆弱。
在这一点上,我不能简单地用PGDLLIMPORT
(项目使用的__declspec(dllimport)
/__declspec(dllexport)
宏)注释每个导出的函数并停止使用 DEF 文件。
即使我可以,我也需要找到一种PGDLLIMPORT
在暴露变量上省略时会导致明显链接器错误的方法。
所以。Windows 链接器/编译器专家。有任何想法吗?