【问题标题】:What factors determine which version of glibc is required for binary built with g++?哪些因素决定了使用 g++ 构建的二进制文件需要哪个版本的 glibc?
【发布时间】:2021-07-30 13:26:10
【问题描述】:

我管理一个复杂的C++ project

我收到现场报告说,在一个系统上构建的二进制文件无法在另一个系统上运行 系统因为glibc版本不匹配。

我只是想验证一下:二进制所需的glibc版本是否完全由使用哪个版本的g++编译决定?

在这种情况下,二进制文件是使用 g++ 11 构建的,并在另一个没有安装 g++ 11 的系统上运行。

【问题讨论】:

  • 粗略地说,二进制所需的 glibc 版本取决于 gcc 安装 配置 使用的 glibc 版本。 glibc 是向后兼容的,而不是向前兼容的——为较新的 glibc 构建的二进制文件不会与较旧的 glibc 版本一起运行,但将与您构建的后续(更新的)glibc 版本一起运行。 [比这更复杂,因为 glibc 使用 gcc 提供的功能,并且这些功能在 gcc 版本之间有所不同(例如,添加了新功能,删除了旧功能)]。

标签: c++ g++ glibc


【解决方案1】:

我只是想验证一下:二进制所需的glibc版本是否完全由使用哪个版本的g++编译决定?

根本没有。运行时所需的 GLIBC 版本由几个因素决定:

  1. 链接时使用的 GLIBC 版本。
  2. GLIBC 的特性实际使用(这又取决于编译器版本,可能还有编译标志)。
  3. 所使用的任何功能的 ABI 是否发生变化。

在这种情况下,二进制文件是用 g++ 11 构建的

您可以在带有 GLIBC-2.15 的系统和带有 GLIBC-2.31 的系统上安装 g++-11。对于非平凡的源,生成的二进制文件在运行时可能对 GLIBC 有不同的要求。

请参阅 this answer 以了解符号版本控制如何发挥作用。

TL;DR:如果您想构建可移植到不同 Linux 发行版的可执行文件或共享库,请选择您愿意支持的最旧版本的 GLIBC,并在系统上构建使用那个版本(你不必为此拥有一台物理机器——一个虚拟机或一个 docker 容器工作查找)。

由于向后兼容性保证,您的二进制文件可以在具有相同或更新版本 GLIBC 的所有系统上运行。

更新:

假设您在 GLIBC-NN 上构建 libfoo.a,最终用户在 GLIBC-MM 上链接 a.out,其中 MM < NN

这是一种非常危险的做法:程序可能会默默地损坏其数据,并且很难找到这种损坏的根本原因。

现在假设最终用户在 GLIBC-MM 上链接 a.out NN <= MM(这是根据 cmets 的实际情况),然后在具有 GLIBC-JJ 的系统上运行 a.out ,其中JJ < NN

在这种情况下,我“无声”损坏的可能性被最小化,但没有完全消除。

考虑以下假设示例(foo() 是您提供的libfoo.a 的一部分):

struct passwd *foo()
{
   struct passwd *pw = getpwuid(42);
   if (pw->field_a == 123)              // 1
     pw->field_a = 1234;                // 2
   return pw;
}

现在假设在 GLIBC-NN 中 field_a 作为 struct passwd 的一部分存在,但在 GLIBC-JJ 中不存在。在这种情况下,在上面的点1,程序可能会读取超过分配缓冲区的结尾,而在点2 它可能会写入超过结尾。

注意:上面的程序已经违反了“应用程序不得修改返回值指向的结构”的要求,因此无论如何都有未定义的行为;这只是 GLIBC 不匹配导致的错误的一个示例可能

【讨论】:

  • 感谢@Employed Russian 的出色回答。如果我构建一个静态库而不是动态库会发生什么?报告此问题的用户切换到静态构建,不再遇到这些版本问题。
  • @jacko 在这种情况下会发生什么是未定义的。二进制文件可能会正常工作。它也有可能以神秘的方式崩溃,或者破坏它输出的数据。通常,您不希望处于您提供的库最终导致客户数据损坏的位置。
  • 谢谢!更清楚一点 - 静态我的意思只是构建一个静态 *.a 库,而不是与 GLIBC 的静态链接。
  • @Jacko 是的,我明白了。您正在针对 GLIBC-newer 构建档案 libfoo.a,然后客户使用它使用 libfoo.a 和 GLIBC-older 链接 a.out。这可能会导致所有类型的问题(正如我之前所说的)。
  • 谢谢!实际上,用户将静态 libfoo.a 链接到具有 GLIBC-newer 的系统上的二进制 binfoo,然后在具有 GLIBC-older 的系统上运行 binfoo。这还有风险吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-10-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-10-01
相关资源
最近更新 更多