【问题标题】:Duplicate definitions of _aenvptr and _wenvptr_aenvptr 和 _wenvptr 的重复定义
【发布时间】:2014-03-18 17:26:15
【问题描述】:

我正在编写一个在 Windows 上运行的链接器,它接受了 PE 格式目标文件的大多数功能,但是我遇到了 libcmt 中 _aenvptr 和 _wenvptr 的重复定义的问题。

根据我在 PE 文档、使用 Microsoft 编译器和 dumpbin 的试验和错误以及这里偶尔出现的问题之间能够弄清楚的情况,规则是:

int x;

作为一个全局变量转换为没有节的 IMAGE_SYM_CLASS_EXTERNAL。如果这种情况出现在多个目标文件中,这很好,并且会采用最大的一个并将其用作 BSS 定义。

int x = 0;

作为全局变量转换为带有 BSS 部分的 IMAGE_SYM_CLASS_EXTERNAL。如果这发生在多个目标文件中,则这是一个重复符号错误。

问题在于 libcmt 以后一种形式提供了 _aenvptr 和 _wenvptr 的多个定义。 Microsoft 链接器对此很满意,但据我所知,它对我创建的小型测试库中的等效案例并不满意。

_aenvptr 和 _wenvptr 不是 COMDAT,它们也没有任何辅助符号记录或我能找到的任何其他奇怪的东西。

我错过了什么?

【问题讨论】:

    标签: c windows visual-c++ linker portable-executable


    【解决方案1】:

    这些符号在两个对象中定义,是的:在 crt0.obj 和 dllcrt0.obj 中都有定义。这些对象分别包含 EXE 和 DLL 的启动代码。

    这里的诀窍是永远不应该出现两个对象都链接到一个模块中的情况。链接器不会将库中的所有对象拉入链接;相反,它只引入满足依赖关系所需的任何对象。不会将 crt0.obj 和 dllcrt0.obj 链接到单个模块中;它们的用途是相互排斥的。

    基本上,一个库中可以有多个相同外部符号的定义,只要 [1] 每个定义都在不同的对象中,并且 [2] 在链接中实际使用这些对象中的一个即可。

    【讨论】:

    • 棘手的部分是,要解析符号,您需要知道将使用哪些对象,但要找到将使用哪些对象,您需要解析符号,这似乎将其变成了约束满意度问题;我对二进制链接的语义如此基本的东西感到惊讶。实际使用的算法是否记录在任何地方?
    • 我不太明白。如果链接直接需要的符号在多个对象中定义,那么这将是一个问题。在这种情况下,_aenvptr_wenvptr 没有公开记录;它们是内部实现细节,永远不应该被链接直接要求。只能通过公共入口点之一将它们拖到链接中——无论是 CRT 主入口还是 DllMain。
    • 我不知道这方面的任何正式文件;我所知道的关于链接器的一切,我都必须在 CRT 中调试链接错误。
    • 啊,我尝试用printf("%p",_aenvptr) 编写一个小测试程序,它成功了,这意味着链接器必须先解析入口点符号,然后再解析_aenvptr,因为以其他顺序解析会不清楚将哪个对象拖入链接 - 你是说这是一个意外,它没有记录语义?
    猜你喜欢
    • 1970-01-01
    • 2016-07-16
    • 2014-11-16
    • 1970-01-01
    • 2017-09-19
    • 1970-01-01
    • 2017-09-11
    • 2015-11-17
    • 2021-08-29
    相关资源
    最近更新 更多