1) 在 Ubuntu 10.04 上,使用 OpenSSL 0.9.8:

1) 在 Ubuntu 10.04 上,使用 OpenSSL 0.9.8:

我正在嘗試編譯一個程式prog並將其連結到 OpenSSL 的 1.0.2 beta,從原始碼建置並安裝在/usr/local/ssl-1.0.2.在使用 0.9.8 的舊系統上,這可以順利完成。在安裝了 1.0.1 的較新的系統上,這需要更多的工作。我想知道為什麼。

1) 在 Ubuntu 10.04 上,使用 OpenSSL 0.9.8:

以下是我針對 1.0.2 進行編譯和連結的步驟。

$ ./config shared --openssldir=/usr/local/ssl-1.0.2 && make && make install
$ ldconfig
$ ldconfig -p | grep libcrypto

=> 僅顯示 0.9.8 文件,因此我添加了 1.0.2 文件的路徑...

$ ldconfig /usr/local/ssl-1.0.2/lib
$ ldconfig -p | grep libcrypto

=>

 libcrypto.so.1.0.0 (libc6) => /usr/local/ssl-1.0.2/lib/libcrypto.so.1.0.0
 libcrypto.so.0.9.8 (libc6, hwcap: 0x0008000000008000) => /lib/i686/cmov/libcrypto.so.0.9.8
 libcrypto.so.0.9.8 (libc6, hwcap: 0x0004000000000000) => /lib/i586/libcrypto.so.0.9.8
 libcrypto.so.0.9.8 (libc6, hwcap: 0x0002000000000000) => /lib/i486/libcrypto.so.0.9.8
 libcrypto.so.0.9.8 (libc6) => /lib/libcrypto.so.0.9.8
 libcrypto.so.0.9.8 (libc6) => /usr/lib/libcrypto.so.0.9.8
 libcrypto.so (libc6) => /usr/local/ssl-1.0.2/lib/libcrypto.so

這樣我就可以編譯prog...

$ gcc -o prog ... -L/usr/local/ssl-1.0.2/lib -lcrypto
$ ldd prog

=>

    libcrypto.so.1.0.0 => /usr/local/ssl-1.0.2/lib/libcrypto.so.1.0.0 (0x0083b000)

...並且它與 1.0.2 正確連結。

2) 在 Debian Wheezy 上,使用 OpenSSL 1.0.1:

同樣的步驟,不同的結果。

$ ./config shared --openssldir=/usr/local/ssl-1.0.2 && make && make install
$ ldconfig
$ ldconfig -p | grep libcrypto

=>

 libcrypto.so.1.0.0 (libc6, hwcap: 0x0008000000008000) => /usr/lib/i386-linux-gnu/i686/cmov/libcrypto.so.1.0.0
 libcrypto.so.1.0.0 (libc6, hwcap: 0x0004000000000000) => /usr/lib/i386-linux-gnu/i586/libcrypto.so.1.0.0
 libcrypto.so.1.0.0 (libc6) => /usr/lib/i386-linux-gnu/libcrypto.so.1.0.0

同樣,我添加了 1.0.2 的路徑...

$ ldconfig /usr/local/ssl-1.0.2/lib
$ ldconfig -p | grep libcrypto

=>

 libcrypto.so.1.0.0 (libc6, hwcap: 0x0008000000008000) => /usr/lib/i386-linux-gnu/i686/cmov/libcrypto.so.1.0.0
 libcrypto.so.1.0.0 (libc6, hwcap: 0x0004000000000000) => /usr/lib/i386-linux-gnu/i586/libcrypto.so.1.0.0
 libcrypto.so.1.0.0 (libc6) => /usr/local/ssl-1.0.2/lib/libcrypto.so.1.0.0
 libcrypto.so.1.0.0 (libc6) => /usr/lib/i386-linux-gnu/libcrypto.so.1.0.0
 libcrypto.so (libc6) => /usr/local/ssl-1.0.2/lib/libcrypto.so

然後我嘗試編譯...

$ gcc -o prog ... -L/usr/local/ssl-1.0.2/lib -lcrypto
$ ldd prog

=>

    libcrypto.so.1.0.0 => /usr/lib/i386-linux-gnu/i686/cmov/libcrypto.so.1.0.0 (0xb7591000)

但這裡它與 1.0.2 沒有連結。編譯時庫路徑是正確的(用 , 指定-Lgcc否則會失敗,因為 中使用的某些函數prog特定於 1.0.2),但運行時庫路徑則不然。

3) 如何讓它在 Wheezy 上運行

有或沒有跑步ldconfig /usr/local/ssl-1.0.2/lib

$ gcc -o prog ... -Wl,--rpath=/usr/local/ssl-1.0.2/lib -L/usr/local/ssl-1.0.2/lib -lcrypto
$ ldd prog

=>

    libcrypto.so.1.0.0 => /usr/local/ssl-1.0.2/lib/libcrypto.so.1.0.0 (0xb7592000)

或者,export LD_LIBRARY_PATH=/usr/local/ssl-1.0.2/lib在運行之前運行gcc

我想知道什麼

按照 mr.spuratic 的建議使用LD_DEBUG=libs ./prog,我發現在 中找到了路徑/etc/ld.so.cache。我打開該文件,發現 .so 的查找順序與 .so 的輸出相對應ldconfig -p

所以實際的問題是:

  • 為什麼 1.0.2 檔案在 1) 中位於 ldconfig 清單的頂部,但在 2) 中卻沒有?純粹的隨機性?由於 1.0.1 和 1.0.2 檔案具有相同後綴而造成混淆? (“1.0.0”)

或者,換句話說,

  • 為什麼 3) 中新增的標誌在 1) 中不需要?

答案1

針對非預設套件進行編譯/連結時需要注意三件事:

  • 標頭(通常CFLAGS
  • 編譯時庫路徑(通常LDFLAGS
  • 運行時庫路徑(路徑通過LDFLAGS, LD_RUN_PATH,LD_LIBRARY_PATHld.so.conf)

你還沒有說prog是什麼,所以我不知道它的配置可能有多好(或者如果它使用autoconf?),我見過很多只可靠地執行前兩個步驟。

CFLAGS在連結階段,庫路徑順序是相關的,假設您使用的是 GNU 工具鏈(gcc 和 binutils),您可能可以透過先前的設定configure(或直接設定Makefile)來了解發生了什麼:

export CFLAGS="-Wl,-t"

這會將-t追蹤選項傳遞給連結器。如果在 make 過程中只得到簡潔的「CC」和「LD」行輸出,則可能需要在 make 指令中新增V=1或。VERBOSE=1

在運行時,您可以ld.so透過仔細設定來查看嘗試的內容LD_DEBUG,例如

LD_DEBUG=libs ./myprog

files(或嘗試或的值symbols以獲取更多詳細資訊)

要在建置時正確指定所有三個參數,您應該能夠執行以下操作:

  • export CFLAGS="-I/usr/local/ssl-1.0.2/include"
  • export LDFLAGS="-L/usr/local/ssl-1.0.2/lib -R/usr/local/ssl-1.0.2/lib"

然後重新配置/重新編譯。

您使用的是--openssldir而不是更傳統的--prefix(我推薦後者,並且make install_sw如果您不需要默認安裝為您提供的 1000 個左右的手冊頁和符號鏈接,也可以使用)。這可能是問題的一部分。由於某種原因,您顯示的 .so 庫已知沒有ld.so版本後綴(例如.so.1.0.2),正確的“ make install”應該為您設定它(透過link-sharedmain 中的目標Makefile)。

-R選項指示連結器在特定 OpenSSL 函式庫的可執行輸出中嵌入 RPATH,以便它不需要依賴執行時間連結器 ( ld.so) 通常提供的預設值。您可以使用以下命令修改現有的二進位文件chrpath反而。

這或多或少相當於導出LD_LIBRARY_PATH=/usr/local/ssl-1.0.2/lib。您可以在此處閱讀有關 RPATH 和相關 RUNPATH 的更多資訊:http://blog.tremily.us/posts/rpath/

作為最後的手段,您可以建立不帶「共享」或「不共享」的OpenSSL,這將為您提供不會出現此問題的靜態庫(但很可能會出現其他問題,例如在ELF .so 中使用,導致PIC /PIE問題)


根據更新的詳細信息,我認為問題在於 1.0.1 和 1.0.2beta 都將 .so 版本後綴(SONAME)設為 1.0.0。在第一個只有 0.9.8 的系統上,這不會造成任何問題;第二個版本為 1.0.1 和 1.0.2 的版本均為 1.0.0,根據順序,這是「首場比賽獲勝」ld.so.{conf,d}。請記住,ld編譯時連結器是與執行時間連結器不同的程序ld.so,並且可以具有不同的行為(通常會導致符號錯誤或更糟,如您所見)。

$ cd /usr/local/src/openssl/openssl/1.0.2beta1
$ readelf -a libssl.so | grep SONAME
0x0000000e (SONAME)                     Library soname: [libssl.so.1.0.0]

$ cat verchk.c
int main(int argc, char *argv[]) {
    printf("build: %s\n",OPENSSL_VERSION_TEXT);
    printf("run  : %s\n",SSLeay_version(SSLEAY_VERSION));
    return 0;
}

$ gcc -Wall  -I/usr/local/src/openssl/openssl-1.0.2-beta1/include \
    -Wl,-rpath /usr/local/src/openssl/openssl-1.0.2-beta1/ \
    -o verchk /usr/local/src/openssl/openssl-1.0.2-beta1/libcrypto.so verchk.c

$ ./verchk
build: OpenSSL 1.0.2-beta1 24 Feb 2014
run  : OpenSSL 1.0.2-beta1 24 Feb 2014

$ grep SHLIB_M...R= Makefile
SHLIB_MAJOR=1
SHLIB_MINOR=0.0

更新 OpenSSL-1.1 進行了一些 API 層級更改,上述程式碼將無法使用 v1.1 標頭和較舊的程式庫進行編譯 ( undefined reference to `OpenSSL_version')。

SSLeay_version()現已棄用,並且(取決於OPENSSL_API_COMPAT)可能會被#define-d 為正確的 API 函數OpenSSL_version()

答案2

新庫的路徑是否位於其中的文件之一/etc/ld.so.conf.d?下次運行:-

#ldconfig -v

重建緩存。如果你動作很快,你應該會在列印出來的長列表中看到新的庫(或透過管道將其傳遞到grepor less

也許該路徑已經在第一台伺服器中,但不在第二台伺服器中?

相關內容