2011-05-23 108 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