在 Ubuntu(Linux 的 Windows 子系统)上找不到“GLIBC_2.25”

Som*_*One 11 glibc

我在Ubuntu 16.04适用于 Linux 的 Windows 子系统)上出现以下错误

/lib/x86_64-linux-gnu/libc.so.6: version 'GLIBC_2.25' not found
Run Code Online (Sandbox Code Playgroud)

我已经试过了:

apt-get update
apt-get install libc6
Run Code Online (Sandbox Code Playgroud)

看来,系统有最新的 libc6,因为它输出

libc6 is already the newest version (2.23-0ubuntu10)
Run Code Online (Sandbox Code Playgroud)

但是我想运行的程序失败了。

我如何解决它?

0xC*_*22L 13

现在这个答案可能会有点晚了,但让我尝试向您提供一些有关您在这里遇到的问题的技术背景以及解决它的可能方法。

首先,所评论的是真实的。glibc 是 C 运行时,是 Ubuntu 系统的核心。然而,其他发行版选择其他运行时,程序也可以选择静态链接更自由许可的运行时(例如 musl-libc)。但后一种方法也有其局限性。

根据经验,您可以运行在您的系统上构建的软件。对于某些 BSD 或 Gentoo Linux 等系统来说,这完全没问题,但对于 Debian 和 Ubuntu 等预打包发行版来说,这开始成为一个问题。

系统调用

您的内核提供了许多系统调用。其中的某个子集是标准化的,有些是特定于您的系统的,即本例中的 GNU/Linux。

大多数系统调用(例如“打开文件”)在 C 运行时中有直接的对应项,但 C 运行时通常会在顶部提供其他内容(例如动态链接的设施...)。

C运行时

glibc 是一个所谓的共享对象。其他系统称其为动态库或动态链接库。尽管实现和功能不同,但目标基本相同。

术语“共享对象”是指对象代码(“库函数”)在系统中的进程之间共享。

另一个优点是,仅需要更新这个库,而不需要更新与特定版本的库静态链接的每个应用程序。

专有软件(即不是FLOSS 的软件)存在许可问题,因为 glibc 许可证给不愿意披露其专有源代码的人带来了某些“问题”。现在这显然不是您的代码的问题,因为您可以继续构建您自己的.

缺少符号

您遇到的错误:

/lib/x86_64-linux-gnu/libc.so.6: version 'GLIBC_2.25' not found
Run Code Online (Sandbox Code Playgroud)

我经常与那些抱怨 Windows 上的“DLL 地狱”的人开玩笑。Linux 也并没有更好,传统的链接器几乎无法控制链接的符号。

好吧,让我们动手吧。确保您已经binutils安装了 ( apt install binutils),并且我假设您已经安装了标准 Bash shell 并且可以在 中找到它/bin/bash

我们将从以下调用开始(代替readelf,objdump也可以,但它有自己的命令行参数):

readelf --dyn-syms /bin/bash|grep -P '\WUND\W'
Run Code Online (Sandbox Code Playgroud)

它的作用是列出 Bash 二进制文件中的所有动态符号,然后将输出限制为那些未定义的项目 ( UND)。这将为我们提供 Bash 使用 glibc 的函数列表。GLIBC_2.2.5我们可以通过附加删除所有引用该版本的条目来进一步完善这一点grep -v 'GLIBC_2\.2\.5'

$ readelf --dyn-syms /bin/bash|grep -P '\WUND\W'|grep -v 'GLIBC_2\.2\.5'
     0: 0000000000000000     0 NOTYPE  LOCAL  DEFAULT  UND 
     2: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND __ctype_toupper_loc@GLIBC_2.3 (3)
     3: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND tgetflag@NCURSES_TINFO_5.0.19991023 (4)
     6: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND __snprintf_chk@GLIBC_2.3.4 (5)
    14: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND __vfprintf_chk@GLIBC_2.3.4 (5)
    20: 0000000000000000     0 NOTYPE  WEAK   DEFAULT  UND _ITM_deregisterTMCloneTab
    22: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND tgetent@NCURSES_TINFO_5.0.19991023 (4)
    25: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND tputs@NCURSES_TINFO_5.0.19991023 (4)
    37: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND faccessat@GLIBC_2.4 (6)
    50: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND tgoto@NCURSES_TINFO_5.0.19991023 (4)
    60: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND eaccess@GLIBC_2.4 (6)
    63: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND __stack_chk_fail@GLIBC_2.4 (6)
    72: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND __fdelt_chk@GLIBC_2.15 (7)
    80: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND tgetnum@NCURSES_TINFO_5.0.19991023 (4)
    98: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND tgetstr@NCURSES_TINFO_5.0.19991023 (4)
   101: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND __asprintf_chk@GLIBC_2.8 (8)
   104: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND __memmove_chk@GLIBC_2.3.4 (5)
   106: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND __memcpy_chk@GLIBC_2.3.4 (5)
   108: 0000000000000000     0 NOTYPE  WEAK   DEFAULT  UND __gmon_start__
   114: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND memcpy@GLIBC_2.14 (9)
   138: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND regexec@GLIBC_2.3.4 (5)
   145: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND __vsnprintf_chk@GLIBC_2.3.4 (5)
   147: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND __strncpy_chk@GLIBC_2.3.4 (5)
   153: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND __strcpy_chk@GLIBC_2.3.4 (5)
   157: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND __printf_chk@GLIBC_2.3.4 (5)
   160: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND __longjmp_chk@GLIBC_2.11 (11)
   195: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND __fprintf_chk@GLIBC_2.3.4 (5)
   198: 0000000000000000     0 NOTYPE  WEAK   DEFAULT  UND _ITM_registerTMCloneTable
   215: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND __ctype_tolower_loc@GLIBC_2.3 (3)
   216: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND __ctype_b_loc@GLIBC_2.3 (3)
   219: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND __sprintf_chk@GLIBC_2.3.4 (5)
Run Code Online (Sandbox Code Playgroud)

2.2.5 版本是第一个支持 x86-64 作为架构的版本,这就是我们对它不感兴趣的原因。第一个可用版本永远不会造成问题。

但是,如果您希望在“仅”有 glibc 2.14 的系统上使用此 Bash 二进制文件,它将无法工作,因为__fdelt_chk@GLIBC_2.15至少需要 2.15 版本。

插曲:符号版本控制

@GLIBC_2.3.4符号名称上的 (etc.) 后缀描述版本范围(另请参阅此处)。这使得 ELF 共享对象能够支持符号的多个版本。例如,函数foo()在库的 1.0 版本中可能采用 2 个参数,但在 2.x 版本范围中采用 3 个参数。动态链接到这些符号的软件包含符号版本这一事实意味着它将始终链接到函数的适当版本。

然而,缺点就是你所遇到的。如果使用的符号之一需要比您系统上可用的库版本更新的库版本,则在具有较新 glibc(或实际上也使用符号版本控制的任何其他库)的系统上链接的软件将无法在您(较旧的)系统上运行。

“克服”这个问题的经典方法始终是建立在一个足够老的系统上,就库版本而言提供足够低的共同点。这甚至允许您在某种程度上运行在一个发行版上构建的二进制文件,以便在一系列其他发行版上运行。缺点是这意味着旧的编译器、旧的工具链、旧的库(因为库不仅仅是 C 运行时)。

存在某些替代方案(见下文),但它们都要求您准确分析您想要什么。例如,静态链接到 musl-libc - 具有更自由的许可条款 - 如果您的程序提供插件接口并与插件交换缓冲区,则该链接将不起作用...在这种情况下,动态链接到相同的 C 运行时非常重要。此外,由于sbrk.

您的难题的可能解决方案

  • 在更现代的发行版本上的虚拟机内运行您的软件,该版本满足开箱即用的库依赖关系。因为虚拟机允许您运行您想要的任何内核,所以这甚至适用于需要非常现代的系统调用的软件。
  • 在 chroot 监狱或容器内运行您的软件(类似于上面的 VM 主题,但如果内部运行的代码使用主机内核上不可用的较新系统调用,您可能会遇到问题,LXD 4.0 尝试缓解此问题通过为这些系统调用提供存根)。
  • 使用 AppImage(不过,有人需要注意 AppImage 的存根尽可能向后兼容。
  • 使用快照包。

更多涉及的解决方案,或者如果您是开发人员

  • 与旧版本一起提供较新的 glibc 版本。由于这是一个守护进程,因此有机会启动它无论是 systemd 还是旧的 SysV init,您都应该能够将LD_LIBRARY_PATH其设置为指向更新的glibc
  • 如果您是上述软件的维护者,这种方法将提供一个可行的替代方案。它的作用是指示链接器选择同一符号的早期版本而不是最新版本(默认选择最新版本)。
    GitHub 上有一个名为wheybags/glibc_version_header的项目,它试图将其形式化并可能让您入门。
    • 这是上述方法的变体。
    • 这提供了有关如何自行调查此事的更多详细信息。
    • 展示了如何调查二进制文件所需的符号版本范围,答案进一步阐明了这个问题。
  • 曾经有一个名为 autopackage 的项目,它在附带的包装器apgcc中有效地使用了这种方法。您仍然可以在许多地方下载相应的文件来收集实施细节。
  • 到目前为止,最细致入微的解释是这个memcpyglibc 2.14 的新功能是 a GNU_IFUNC,这意味着一旦在运行时,将选择最有效的版本(例如针对特定处理器模型进行优化!)。这与简单地提供对函数(要重新定位)的直接引用的经典方法相反。这样做的主要结论是,在这种特殊情况下,您不能只修改符号名称,因为这种形式的“延迟加载”机制的 ABI 与所述符号的旧版本的 ABI 不同。
    • 这是同一用户的另一个解释。

如果您确实对链接器的内部工作原理感兴趣,您可以阅读一本有关该主题的书或参考 Ian Lance Taylor 的优秀文章系列,您可以在此处找到其中的概述

  • 没关系。有时长答案很有帮助,有时又是绝对必要的。取决于你是否想读它或者你是否认为它适合SO,这是一个有效的观点。我个人发现它很有帮助,因为我需要背景信息,但它们的格式也使我可以轻松跳过并跳转到“可能的解决方案”部分。与此同时,我永远不会点击 Quora 上的任何内容。个人经历就是这样/耸肩 (4认同)