2014-01-09 41 views
1

我試圖編譯和鏈接一個程序(我們稱之爲myprog),它與共享庫鏈接(在這種情況下,libcryto & libssl,但實際的庫不是相關)。我正在將其構建在Centos 5.5上,但希望使用相同的二進制文件運行在類似發行版(例如CloudLinux)的其他RHEL上。兩個版本都具有相同的庫(SO_NAME)(即DT_NEEDED版本對應)。重寫共享庫undef symbol編譯對象的版本

我的問題是這樣的。當我編譯在CentOS我看到:

centos$ objdump -T myprog | fgrep SSL_new 
0000000000000000  DF *UND* 0000000000000000 libssl.so.10 SSL_new 

的正常工作,因爲:

centos$ objdump -T /usr/lib64/libssl.so.10 | fgrep SSL_new 
00000000000447d0 g DF .text 0000000000000390 libssl.so.10 SSL_new 

然而,在CloudLinux:

cloudlinux$ objdump -T /usr/lib64/libssl.so.10 | fgrep SSL_new 
00000033a623a120 g DF .text 0000000000000390 Base  SSL_new 

注意SSL符號的版本已經從libssl.so.10改變到Base

這意味着,當我運行的二進制我得到:

cloudlinux$ ./myprog 
./myprog: /usr/lib64/libcrypto.so.10: no version information available (required by ./myprog) 
./myprog: /usr/lib64/libssl.so.10: no version information available (required by ./myprog) 

我理解,這是「只是一個警告」,但我想擺脫它。

我想要的是我的二進制文件在cloudlinux和centos上運行,沒有警告。據我所知,openssl庫的ABI至少在我使用的位中是相同的。現在我無法更改共享庫,因爲myprog可以在任何cloudlinux或centos庫上運行。我會接受一個解決方案,它在安裝時確定符號(以某種方式),例如與objcopy

一種方法就像是爲[email protected]引入弱符號,這是[email protected]的別名。顯然,這將是每個單一的符號在ssl庫(所以包裝不適合)。但我不能讓-Wl,--defsym=x=yx採取的價值觀和y@符號英寸

另一種做法可能的工作無非是從二進制中刪除符號版本信息(即從每個SSL的去除libssl.so.10版本符號,並依靠DT_NEEDED名稱中的版本)。這似乎是一個簡單的請求,但我看不出如何去做。有一些objcopy咒語嗎?

更糟糕的情況是,在Centos上構建一個可以在CloudLinux上工作的(單獨的)版本可以。我試着這樣做:

#define OSLB(SYMNAME) __asm__(".symver " #SYMNAME "," #SYMNAME "@Base"); 
OSLB (SSL_new); 

然而,失敗的鏈接抱怨[email protected]是一個未定義的符號(這是在CentOS,因爲CentOS的.so不具有符號)。

有沒有辦法解決這個問題?

回答

2

另一種方法可能工作很簡單,就是請從二進制符號版本信息(即刪除libssl.so.10版本來自每個ssl符號,並依賴於DT_NEEDED名稱內的版本)。這似乎是一個簡單的請求,但我看不出如何去做。有一些objcopy咒語嗎?

刪除版本信息後鏈路是不可行的 - 這些字符串輸入到哈希表,並重建這些哈希表太複雜的事情做objcopy

你想要做的是創建一個存根libssl.so.10DT_SONAME設置爲libssl.so.10,它定義了你從它需要的所有符號,但沒有任何版本信息。例如,如果你只需要SSL_new符號,這將做到:

echo "void SSL_new() { }" > t.c && 
gcc -fPIC -shared -o libssl.so -Wl,--soname='libssl.so.10' t.c 

現在鏈接程序通過這個存根庫,它將要求任何版本的符號。

然後,運行時鏈接程序將在CentOS上滿足這個未定義的未版本化的SSL_new,[email protected]以及在CloudLinux上的[email protected]

+0

這似乎是前進的方向。我必須通過一個.o文件建立共享庫,才能使其工作:'gcc -c -Wall -Werror -fPIC -o dummy.o dummy.c && gcc -shared -o dummy.so -Wl, - soname ='libssl.so.1.0.0'dummy.o && gcc -o objtest objtest.c -l:./ dummy.so'。這種方法的優點是:(a)生成的二進制文件可以在任何地方生成未版本化的符號;(b)不需要擔心函數原型;(c)C文件dummy.c可以自動生成從.so文件的objdump -T小Perl。 – abligh

+0

@abligh「我必須通過一個.o文件構建共享庫,才能使其工作」 - 它*應該*在沒有分割編譯/鏈接步驟的情況下工作。我很好奇爲什麼它沒有。 –

+0

不知道,但objdump產生的結果'不是一個動態二進制'或一些類似的錯誤。 – abligh

1

我能夠擺脫這些警告的這種方式(在Debian /凱旋門而非CentOS的/雲的Linux,但它應該爲你工作太):

  1. 刪除所有的libssl-devel包來避免混淆

  2. 編譯的libssl從源頭

    ./config --prefix=/usr/local --openssldir=/usr/local/openssl shared

  3. 建立你的抗T軟件帽子。

對於我來說,這些版本的參考文獻,然後消失,其運行沒有任何警告:

Version References: 
    required from libcrypto.so.1.0.0: 
    0x066a2b20 0x00 10 OPENSSL_1.0.0 
    required from libssl.so.1.0.0: 
    0x066a2b20 0x00 05 OPENSSL_1.0.0 
+0

不幸的是,這是非常不理想的,因爲我試圖自動構建這個,所以我有一個在兩個系統上工作的單個二進制文件(或者更糟糕的情況下,每個工作的二進制文件)。如果我這樣做,我需要刪除-devel軟件包並在兩個版本之間重新插入另一個軟件包,並且仍然會有兩個二進制文件。 – abligh

+0

我不明白你的意思。以上僅在構建機器上需要。您最終應該在兩個實際系統上運行一個二進制文件。 –

+0

我認爲你正在看錯的東西。您在文章中提到的版本引用是DT_NEEDED版本,這已經是正確的了。我的問題是每符號版本。我在說的是,每符號版本控制將在由您剛剛構建的libssl-devel軟件包的ld行控制的版本映射中進行設置。試試objdump -T就可以了。我想我可以嘗試下載libssl-devel並對其進行修改,使其沒有符號版本控制,用它構建並查看是否有幫助,但是看起來很重要的是從ELF文件中刪除一個標記。 – abligh