2011-10-17 75 views
3

描述:C++彙編靜態變量和共享對象

一個。類X包含一個靜態私有數據成員ptr和靜態公共函數成員getptr()/ setptr()。
在X.cpp中,ptr被設置爲NULL。

b。 libXYZ.so(共享對象)包含類X的對象(即libXYZ.so包含X.o)。

c。 libVWX.so(共享對象)包含X類的對象(即libVWX.so包含X.o)。 d)。可執行A.EXE包含X.cpp作爲翻譯單元部分,最後連接到libXYZ.so,libVWX.so

PS:
1.有參與任何類的沒有用戶的命名空間。
2.庫和可執行文件還包含許多其他類。
3.沒有dlopen()已經完成。所有的庫在編譯時使用-L和-l標誌進行鏈接。

問題陳述:

  1. 當編譯,並與其他庫(即libXYZ.so和libVWX.so)連接a.exe的,我期待一個鏈接錯誤(衝突/相同的次數符號多次),但沒有得到一個。

  2. 當在執行程序 - 行爲是SUSE Linux的10和HP-UX 11 IA64奇怪。
    在Linux中,當執行流被推送到不同庫中的所有對象時,效果僅在X的一個副本中註冊。
    在HPUX中,當執行流被推送到不同庫中的所有對象時,效果爲在3個不同的充X(2屬於每個庫和1用於可執行)

PS副本註冊:在運行節目期間我的意思是,該流程也傳遞thourgh屬於A.EXE,libXYZ.so多個對象和libVWX.so),其與靜態指針交互屬於X.

問:

  • 期待鏈接錯誤不正確?由於兩個編譯器默默地通過了編譯,可能會有一個標準規則來處理這種類型的場景,而我錯過了。如果是這樣,請讓我知道一樣。
  • 如何(在HPUX GCC在Linux和ACC)編譯器決定X的多少副本保留在最終的可執行文件,並在這樣的情況下是指他們。
  • gcc和aCC是否支持任何標誌,這會在這種情況下警告/停止編譯給用戶?

感謝您的幫助提前。

回答

0

該函數是「公共靜態」,所以我假設它是OOP-意思是「靜態」(不需要實例) ,而不是C的靜態含義(文件靜態;本地編譯單元)。因此這些功能是外部的。

現在在Linux中,您有明確的權利來覆蓋庫符號,無論是使用其他庫還是可執行文件。庫中的所有外部符號都使用全局偏移量表來解析,即使庫實際上定義了它自己。儘管可執行文件中定義的函數通常不會像這樣解析,但鏈接器注意到符號將從庫中到達符號表,並將引用放置在可執行文件定義的引用中。因此,如果您生成了可執行文件,庫會看到在可執行文件中定義的符號。

這是一個顯式的功能,可以讓您執行諸如替換內存分配函數或打包文件系統操作等功能。HP-UX可能沒有此功能,因此每個庫最終都會調用它自己的實現,而其他任何具有未定義符號的對象都會看到其中一個。

+0

你的答案看起來是最合乎邏輯的。所以已經授予你積分。唯一值得一提的問題是 - 有沒有辦法在鏈接時發現這些問題 - 鏈接器會在哪裏發出錯誤?如果您知道,請讓我知道。 –

+0

@kumar_m_kiran:不幸的是它是系統特定的。 ELF鏈接器將聲明兩個.o文件中的符號之間的衝突,除非這些符號很弱(在C++內聯方法和模板實例較弱或者可以使用__attribute__),並且不會聲明與庫中的符號(按設計)衝突。另一方面,Windows將聲明與任何符號的衝突,除非用選項覆蓋,甚至共享庫仍然會調用它們自己的定義,否則這是致命的。 –

1

我不太確定我是否完全理解了這種情況。但是,在Linux下加載動態對象(以及其他的 Unices)的默認行爲是使庫中的所有符號可用,並且僅使用 第一次遇到。因此,如果您同時包含和libVWX.so 包含符號X::ourData,它不是錯誤;如果你將它們加載到 那個訂單中,libVWX.so將使用, 而不是它自己的X::ourData。從邏輯上講,這很像頭文件中的模板定義 :編譯器偶然選擇一個,如果任何定義與所有其他定義不同,則爲 未定義的行爲。通過將標誌RTLD_LOCAL傳遞給dlopen可以覆蓋此行爲 。

至於你的問題:

  • 的連接僅僅是實現(當系統加載庫隱含您獲取)的dlopen的默認行爲。因此,沒有錯誤(但是,如果任何定義不相同,那麼未定義行爲的邏輯等價物就不相同)。

  • 編譯器沒有決定。當加載.so時會作出決定,具體取決於您在致電dlopen時是否指定了RTLD_GLOBALRTLD_LOCAL。當運行時隱式地調用dlopen來解決依賴關係時,如果在加載主可執行文件時發生這種情況,它將使用RTLD_GLOBAL,以及當依賴項來自庫時曾用於加載庫的內容。 (這意味着,當然,前提是RTLD_GLOBAL將傳播,直到調用dlopen明確。)

+0

感謝您的初始響應,但是,「因此,如果您同時使用libXYZ.so和libVWX.so .....」並不能解釋爲什麼Linux和HPUX中的行爲不同。在Linux中,它符合你的解釋。但在HP中,看起來像mySO :: X :: ourData用於設置X的值。 –

+0

@kumar_m_kiran我不熟悉HP-UX,所以我不能說。 Posix確實說過,如果RTLD_GLOBAL和RTLD_LOCAL都沒有給出,那麼缺省值就是實現定義的。我描述的行爲與我所知道的兩個平臺的行爲相對應:Linux和Solaris。 –

0

有beetween「外部的」符號的差(這是在C++缺省值)和「共享libary外部」。默認情況下,符號只是「extern」,這意味着一個「鏈接單元」的範圍,例如一個可執行文件或一個庫。 所以預期的行爲將是:沒有編譯器錯誤,並且每個模塊都有自己的副本。 這會導致內聯編譯等問題......等等...... 要聲明符號「共享庫extern」,您必須使用「.def」文件或編譯器聲明。 例如在visual C++中,這將是「_ declspec(dllexport)」和「 _declspec(dllimport)」。 我不知道gcc目前的聲明,但我確信有人會這樣做:-)

+0

在Windows中,它就像那樣(編譯器錯誤部分除外;除非用'/ force'覆蓋,否則它是鏈接器錯誤)。但是Linux(ELF)的行爲有所不同。它默認導出符號(如果需要,可以顯式隱藏它們),並且總是導入它所導出的所有符號(當然也可以被顯式覆蓋),所以如果多個對象定義相同的符號,它們總是最終使用相同的符號定義。 –