我在一个h文件中定义了一个类,并在一个lib中实现了一个cpp(我们将其称为libdef)。
我有两个其他库有cpp文件,包括这个h文件。 其中一个对这个类执行了dynamic_cast()(我们称之为libdyn),另一个对这个类做了新的操作(我们称之为libnew)。
看来在这些库中有一个types为typeinfo,而另一个没有:
user@machine> 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 user@machine> 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 user@machine> 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中的typeinfo,但libdyn使用它自己的typeinfo。 这是为什么? 编译器/链接器如何决定是将typeinfo放在一个库中还是从另一个库中引用呢?
我应该注意到,libnew和libdyn都是用-llibdef构build的。
user@machine> 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. user@machine> ld -V GNU ld version 2.17.50.0.6-14.el5 20061020 Supported emulations: elf_x86_64 elf_i386 i386linux
在做了一些检查之后,这取决于lib的cpp文件是否“看见”虚拟方法定义。
这段代码不会导致库中的typeinfo符号:
class SomeClass { public: SomeClass(); virtual void func(); };
这段代码会在库中产生一个typeinfo符号:
class SomeClass { public: SomeClass() {} virtual void func() {} };
当存在时,typeinfo符号将具有模糊的联系。
G ++可能将类的类型信息定义为弱符号,在每个需要它的对象文件中。 libdef
一个目标文件需要它,因为它是构造vtable
安装的vtable
的一部分。 而libdyn
一个目标文件需要它,因为dynamic_cast
。 如果所有libnew
都是新的,那么它可能不需要它(除非构造函数是内联的)。 无论如何,如果它确实是一个虚弱的象征,那么只有其中一个定义会被纳入最终的或可执行的; 哪一个是未指定的(但我怀疑它是链接器遇到的第一个 – 对应于你所看到的)。
大部分时间都不重要。 (例外情况是,如果您使用RTLD_LOCAL
调用dlopen
,则执行此操作;如果dynamic_cast
在.so
以外的其他.so
执行,则可能会失败)。
正如其他人所提到的,这取决于C ++的实现。 但是这里是对g ++如何做的描述。
简而言之,在可能的情况下,g ++在定义类的第一个非内联虚拟成员的翻译单元中定义类vtable和type_info。
我认为这将是一个编译器的实现细节。
通常(因为虚拟表本身就是一个实现细节), virtual table
存储了一个指向type info
的指针,我认为typeinfo存储的地方是编译器的实现细节。 大多数情况下,它将类型信息存储在声明该类的声明中。
我不知道你的编译器和链接器的实现细节,但也许它足够聪明,不包括typeinfo不需要的地方?