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

Jac*_*cko 3 c++ glibc g++

我管理一个复杂的C++ 项目

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

我只是想验证一下:二进制文件所需的glibc版本是否完全取决于使用哪个版本的g++来编译它?

在本例中,二进制文件是使用 g++ 11 构建的,并在另一个未安装 g++ 11 的系统上运行。

Emp*_*ian 5

我只是想验证一下:二进制文件所需的glibc版本是否完全取决于使用哪个版本的g++来编译它?

一点也不。运行时所需的 GLIBC 版本由几个因素决定:

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

在本例中,二进制文件是使用 g++ 11 构建的

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

请参阅此答案以了解符号版本控制如何发挥作用。

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

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

更新:

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

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

现在假设最终用户链接a.out在 GLIBC-MM where 上NN <= MM(根据注释这是实际a.out情况),然后在系统上运行 GLIBC-JJ, where 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;
}
Run Code Online (Sandbox Code Playgroud)

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

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