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"

这会将跟踪选项传递给链接器。如果在 make 过程中只得到简洁的“CC”和“LD”行输出,则-t可能需要在 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

也许该路径已经在第一台服务器中,但不在第二台服务器中?

相关内容