哪些因素决定了用 g++ 构建的二进制文件需要哪个版本的 glibc?

What factors determine which version of glibc is required for binary built with g++?

我管理一个综合体C++ project

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

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

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

I just want to verify: is the version of glibc required by the binary completely determined by which version of g++ is used to compile it?

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

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

In this case, the binary is built with g++ 11

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

请参阅 了解符号版本控制的作用。

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

由于向后兼容性保证,您的二进制文件将适用于具有相同或更新版本 GLIBC 的所有系统。

更新:

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

这是一种非常危险的做法:程序可能会悄无声息地破坏其数据,找到这种破坏的根本原因将非常困难。

现在假设最终用户 links a.out 在 GLIBC-MM 上 NN <= MM (根据评论,这是 实际 的情况),然后在具有 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 点,它可能会 write 超过末尾。

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