重写编译对象的共享库undef符号版本

时间:2014-01-09 10:55:17

标签: linux linker libc binutils objcopy

我正在尝试编译和链接一个程序(让我们称之为myprog),该程序链接到共享库(在本例中为 libcryto& libssl ,但实际的库不相关)。我正在 Centos 5.5 上构建它,但希望在其他 RHEL 类似的发行版(例如CloudLinux)上运行相同的二进制文件。两者都具有相同库的版本,具有相同的SO_NAME(即DT_NEEDED版本对应)。

我的问题是这个。当我在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

一种方法就是为SSL_new@libssl.so.10引入弱符号,这是SSL_new@Base的别名。显然,这将适用于ssl库中的每个符号(因此包装器不合适)。但我无法-Wl,--defsym=x=yxy的值与@符号相对应。

可能有效的另一种方法是简单地从二进制文件中删除符号版本控制信息(即从每个ssl符号中删除libssl.so.10版本,并依赖DT_NEEDED名称中的版本控制) 。这似乎是一个简单的请求,但我也看不出如何做到这一点。是否有一些objcopy咒语?

更糟糕的是,在Centos上构建一个可以在CloudLinux上运行的(单独)版本会很好。我试着这样做:

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

然而,在链接上失败,抱怨SSL_new@Base是一个未定义的符号(在Centos上,因为Centos .so没有该符号)。

有什么方法吗?

2 个答案:

答案 0 :(得分:3)

  

另一种可行的方法是简单地从二进制文件中删除符号版本控制信息(即从每个ssl符号中删除libssl.so.10版本,并依赖于DT_NEEDED名称中的版本控制)。这似乎是一个简单的请求,但我也看不出如何做到这一点。是否有一些objcopy咒语?

删除版本信息后链接是不可行的 - 这些字符串被输入到哈希表中,重建这些哈希表与objcopy过于复杂。

您要做的是创建一个存根 libssl.so.10DT_SONAME设置为libssl.so.10,它定义了您需要的所有符号,但< em>没有任何版本信息。例如,如果您只需要SSL_new符号,则会执行此操作:

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

现在将您的程序链接到此存根库,需要任何版本化符号。

然后,运行时链接器将在CentOS上使用SSL_new和在CloudLinux上使用SSL_new@libssl.so.10来满足此未定义的无版本SSL_new@Base

答案 1 :(得分:1)

我能够以这种方式摆脱这些警告(使用Debian / Arch而不是CentOS / Cloud Linux,但它也适用于你):

  1. 删除所有libssl-devel包以避免混淆

  2. 从源代码编译libssl

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

  3. 针对该软件构建您的软件。

  4. 对我来说,这些版本引用随后消失了,并且在没有警告的情况下运行:

    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