我有一个简单的程序,名为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
会产生错误,指出当前安装的库的次要版本太低? - 程序是否应该调用库中的特殊函数来识别版本并检查次要版本是否足够?
- 库加载器是否应该在程序开始运行之前检查所有符号?
- 我是否误解了版本编号或错过了检查次要版本的设置?
答案1
您没有误解版本编号,这确实是符号查找通常需要的一个领域。
至于这是谁的责任,我想说的是,在现代系统上,它属于构建应用程序的人,而不是库:如果您将应用程序链接到ld -z now
(至少在 GNU binutils 上),则动态链接器将在启动时解析所有符号如果缺少任何符号,则会提前失败(因此您不需要添加自己的手动检查)。您可以在程序通过导出LD_BIND_NOW=1
到环境进行链接后启用此行为(任何非空值都可以,这不是特定于 Linux 的)。
此类问题通常由包管理系统处理:它们保留描述符号版本要求的大量元数据,并生成适当的版本依赖项。库作者也可以帮助改善这种情况,但这可能需要付出很大的努力;请参阅 GNU libc 的特殊版本符号(GLIBC_...
经常出现在错误消息中的符号)以及对版本化符号的全面处理。