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

abl*_*igh 1 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
Run Code Online (Sandbox Code Playgroud)

这工作正常,因为:

centos$ objdump -T /usr/lib64/libssl.so.10 | fgrep SSL_new
00000000000447d0 g    DF .text  0000000000000390  libssl.so.10 SSL_new
Run Code Online (Sandbox Code Playgroud)

但是,在 CloudLinux 上:

cloudlinux$ objdump -T /usr/lib64/libssl.so.10 | fgrep SSL_new
00000033a623a120 g    DF .text  0000000000000390  Base        SSL_new
Run Code Online (Sandbox Code Playgroud)

请注意 SSL 符号的版本已从 更改libssl.so.10Base

这意味着当我运行二进制文件时,我得到:

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)
Run Code Online (Sandbox Code Playgroud)

我知道这“只是一个警告”,但我想摆脱它。

我想要的是我的二进制文件在 cloudlinux 和 centos 上运行而没有警告。据我所知,openssl 库的 ABI 至少在我使用的位上是相同的。现在我无法更改共享库,因为myprog它旨在在任何 cloudlinux 或 centos 库上运行。我会接受一个在安装时修复符号的解决方案(以某种方式),例如使用objcopy.

一种方法是引入一个弱符号,SSL_new@libssl.so.10它是 的别名SSL_new@Base。显然,这适用于 ssl 库中的每个符号(因此包装器不合适)。但我不能得到-Wl,--defsym=x=y采取的值x,并y@在符号。

另一种可能有效的方法是简单地从二进制文件中删除符号版本信息(即libssl.so.10从每个 ssl 符号中删除版本,并依赖DT_NEEDED名称中的版本信息)。这似乎是一个简单的请求,但我也不知道该怎么做。有objcopy什么咒语吗?

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

#define OSLB(SYMNAME) __asm__(".symver " #SYMNAME "," #SYMNAME "@Base");
OSLB (SSL_new);
Run Code Online (Sandbox Code Playgroud)

但是,在链接抱怨这SSL_new@Base是一个未定义的符号时失败了(在 Centos 上是这样,因为 Centos.so没有那个符号)。

有没有办法解决这个问题?

Emp*_*ian 6

另一种可行的方法是简单地从二进制文件中删除符号版本控制信息(即从每个 ssl 符号中删除 libssl.so.10 版本,并依赖于 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
Run Code Online (Sandbox Code Playgroud)

现在对这个存根库链接你的程序,它会不会要求任何版本的符号。

然后,运行时链接程序将满足这未定义,无版本SSL_newSSL_new@libssl.so.10在CentOS,并与SSL_new@Base上CloudLinux。