我有一个简单的程序叫做main
:
#include <iostream>
#include "random.h"
int main()
{
std::cout << "The program has started\n";
return get_another_random_number();
}
该get_another_random_number()
函数在新版本的共享库中,但只安装了旧版本。程序开始运行,但稍后在查找失败时崩溃;例如
$ ./main
The program has started
./main: symbol lookup error: ./main: undefined symbol: _Z25get_another_random_numberv
例如,如果librandom.so.1.3.1
包含一个名为 的函数get_another_random_number()
,但main
在仅librandom.so.1.2.5
安装的服务器上执行,则会发生这种情况。这些库仅在其次要版本上有所不同,因为该1.3
版本与库的版本向后兼容1.2
,但1.2
缺少额外的功能。
在我自己的示例中,如果我运行,readelf -d main | grep NEEDED
我会得到:
0x0000000000000001 (NEEDED) Shared library: [librandom.so.1]
0x0000000000000001 (NEEDED) Shared library: [libstdc++.so.6]
0x0000000000000001 (NEEDED) Shared library: [libm.so.6]
0x0000000000000001 (NEEDED) Shared library: [libgcc_s.so.1]
0x0000000000000001 (NEEDED) Shared library: [libc.so.6]
因此,所有内容都仅与主要版本号相关联。
对于我的共享库,我将其放入/usr/lib/
并添加了符号链接:
lrwxrwxrwx 1 root root 23 Feb 7 14:25 /usr/lib/librandom.so -> /usr/lib/librandom.so.1
lrwxrwxrwx 1 root root 27 Feb 7 14:13 /usr/lib/librandom.so.1 -> /usr/lib/librandom.so.1.2.5
-rw-r--r-- 1 root root 7696 Feb 7 14:00 /usr/lib/librandom.so.1.2.5
在库维护者、应用程序开发者和系统管理员之间;谁负责避免这个程序崩溃?
- 是不是在安装过程
main
中应该产生一个错误,指出当前安装的库的次要版本太低? - 程序是否应该调用库中的特殊函数来识别版本并检查次要版本是否足够?
- 库加载器是否应该在程序开始运行之前检查所有符号?
- 我是否误解了版本编号或错过了检查次要版本的设置?
您没有误解版本编号,这确实是通常需要进行符号查找的领域。
至于这是谁的责任,我想说的是,在现代系统上,它属于构建应用程序的人,而不是库:如果您将应用程序链接到
ld -z now
(至少在 GNU binutils 上),动态链接器将在启动时解析所有符号如果缺少任何符号,则提前失败(因此您无需添加自己的手动检查)。您可以在程序链接后通过导出LD_BIND_NOW=1
到环境来启用此行为(任何非空值都有效,这不是 Linux 特定的)。这类问题通常由包管理系统处理:它们保留描述符号版本要求的大量元数据,并生成适当的版本依赖项。图书馆作者也可以帮助改善这种情况,但这可能需要付出很多努力;查看 GNU libc 的特殊版本符号(
GLIBC_...
经常出现在错误消息中的符号)以及对版本符号的一般彻底处理。