2011-05-23 111 views
3

我有一个类定义在一个h文件中,并在一个cpp中实现,这是一个lib的一部分(我们将其称为libdef)。Linux C++编译器(和链接器)如何决定将typeinfo放在哪里?

我有两个其他库有cpp文件,包括这个h文件。其中一个对这个类执行dynamic_cast()(我们称它为libdyn),另一个为这个类做了新的操作(我们称它为libnew)。

看来,在这些库中的一个有所属类别的类型,但不是在其他:

[email protected]> ld --cref libdef.so | grep -E "typeinfo for MyClass" 
ld: warning: cannot find entry symbol _start; not setting start address 
typeinfo for MyClass libdef.so 

[email protected]> ld --cref libnew.so | grep -E "typeinfo for MyClass" 
ld: warning: cannot find entry symbol _start; not setting start address 
typeinfo for MyClass libdef.so 

[email protected]> ld --cref libdyn.so | grep -E "typeinfo for MyClass" 
ld: warning: cannot find entry symbol _start; not setting start address 
typeinfo for MyClass libdyn.so 

正如你可以看到两个libdef和libnew使用来自libdef的所属类别,但libdyn使用它自己所属类别。这是为什么?编译器/链接器如何决定是将typeinfo放入一个库还是从另一个库引用?

我应该注意libnew和libdyn都是用-llibdef构建的。

[email protected]> icpc -V 
Intel(R) C++ Intel(R) 64 Compiler XE for applications running on Intel(R) 64, Version 12.0.0.084 Build 20101006 
Copyright (C) 1985-2010 Intel Corporation. All rights reserved. 

[email protected]> ld -V 
GNU ld version 2.17.50.0.6-14.el5 20061020 
Supported emulations: 
elf_x86_64 
elf_i386 
i386linux 

经过一些检查后,它取决于lib的cpp文件是否“查看”虚拟方法定义。

此代码将不会导致所属类别库中的元件是:

class SomeClass { public: SomeClass(); virtual void func(); }; 

此代码将在库中产生一个所属类别符号:

class SomeClass { public: SomeClass() {} virtual void func() {} }; 

当存在时,所属类别符号将有模糊的联系。

+0

您似乎认为每种类型只有一个typeinfo对象...标准不能保证这一点,它只能保证如果有多个,它们会比较相等。 – 2011-05-23 13:27:30

+0

@Ben问题是,如果有多个,它们在Linux中并不相等(因为使用了地址比较)。如果您只是在gcc告诉您使用库时才会发生这种情况,但我们仍然遇到问题,并且正在尝试为我们的产品寻找一些解决方法。 – selalerer 2011-05-23 17:22:50

+0

通过“比较等于”,我不是说地址比较。我的意思是'operator =',它是为'typeinfo'类型的对象定义的。这是标准保证将用于比较typeinfo实例的唯一机制。 – 2011-05-23 20:32:03

回答

3

G ++可能会在每个需要它的对象文件中将该类的类型信息定义为弱的 符号。其中libdef中的对象 需要它,因为它是由构造函数安装的vtable 的一部分。并且 libdyn中的一个目标文件需要它,因为dynamic_cast。如果所有的 libnew确实是一个新的,但是,它可能不需要它 (除非构造函数是内联的)。无论如何,如果它真的是 是一个弱符号,则只有其中一个定义将 合并到最终的可执行文件中;哪一个是 未指定(但我怀疑它是第一个链接器 遇到—,这与您所看到的相对应)。

其中大部分时间都不重要。(唯一的例外是,如果 你打电话dlopenRTLD_LOCAL。做到这一点, dynamic_cast很可能会失败,如果它在.so 以外的一个与对象的构造函数执行)

+0

你可能是对的,但没有办法让它从另一个lib引用它,而不是使用它自己的typeinfo? – selalerer 2011-05-23 13:19:03

+1

不是我所知道的。弱引用背后的全部存在理由是*每个*使用都会引发一个定义(在'.o'文件中),并且链接器为所有意图选择一个 - 随机选择一个目的。 ODR的动机之一是允许这种实现技术。如果你的类定义中的任何东西都会导致typeinfo不同,那么你有未定义的行为。 – 2011-05-23 14:03:14

0

我认为这将是编译器的实现细节。

通常(因为虚拟表本身是一个实现细节),virtual table存储一个指向type info的指针,我认为typeinfo存储在哪里是编译器的实现细节。最有可能的是,它将typeinfo存储在so中,该类声明该类。

+0

该声明位于所有3个库中包含在翻译单元中的标题中。如果他们中都有类型信息,那么这将是有道理的,但让我困惑的是一个人拥有它,另一个没有。 – selalerer 2011-05-23 13:05:54

0

我不知道你的编译器和链接器的实现细节,但也许它足够聪明,不要将typeinfo包含在不需要的地方?

2

正如其他人所说,这取决于C++的实现。但是here是g ++如何执行它的描述。

简而言之,在可能的情况下,g ++在定义类的第一个非内联虚拟成员的翻译单元中定义类vtable和type_info。

+0

我想知道链接中的描述是否是最新的。 (我知道URL是4.6,但它可能是文本本身更旧,并且没有更新。)没有提到弱绑定,这是g ++用于模板实例化之类的技术。 (如果您按照该页面上的模板链接进行操作,会导致一个页面讨论Borland模型和CFront模型,这是一个非常明确的信号,表明它不是最新的。) – 2011-05-23 14:09:36

+0

@James:从我可以告诉的使用nm ,最近版本的g ++对vtables和type_info使用弱绑定和“关键方法”技术。 – aschepler 2011-05-23 16:58:19

+0

@ashepler我不确定他们为typeinfo做了什么---我对弱绑定的评论只是猜测。我知道在模板实例化中使用弱符号,然而,在这里也使用它们似乎是合理的。 – 2011-05-24 08:15:15