【问题标题】:Compiling with -static-libgcc -static-libstdc++ still results in dynamic dependency on libc.so使用 -static-libgcc -static-libstdc++ 编译仍然会导致对 libc.so 的动态依赖
【发布时间】:2014-12-05 22:11:56
【问题描述】:

我正在尝试制作一个尽可能便携的可执行文件。删除一些依赖项后,我在另一个系统上运行二进制文件时遇到了以下问题:

/lib/x86_64-linux-gnu/libm.so.6: version `GLIBC_2.15' not found (required by foob)
/lib/x86_64-linux-gnu/libc.so.6: version `GLIBC_2.15' not found (required by foob)
/lib/x86_64-linux-gnu/libc.so.6: version `GLIBC_2.14' not found (required by foob)

我希望我的二进制文件不要求用户升级他们的 libc 版本,所以我也想删除这个依赖项。

生成上述二进制文件的链接器标志已经包含-static-libgcc -static-libstdc++。为什么二进制文件仍然需要共享 libc.so.6

我也尝试添加 -static 标志,但是当我尝试运行 that 二进制时,结果非常奇怪:

$ ls -l foob
-rwxr-xr-x 1 claudiu claudiu 13278191 Oct 10 13:03 foob
$ ./foob
bash: ./foob: No such file or directory

怎么办?

编辑:

$ file foob
foob: ELF 64-bit LSB  executable, x86-64, version 1 (GNU/Linux), dynamically linked (uses shared libs), for GNU/Linux 2.6.24, BuildID[sha1]=5adee9a598b9261a29f1c7b0ffdadcfc72197cd7, not stripped
$ strace -f ./foob
execve("./foob", ["./foob"], [/* 64 vars */]) = -1 ENOENT (No such file or directory)
write(2, "strace: exec: No such file or di"..., 40strace: exec: No such file or directory
) = 40
exit_group(1)                           = ?
+++ exited with 1 +++

有趣的是,如果我ldd的版本没有-static,它比-static的版本少了两个条目,即:

libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007f4f420c1000)
libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f4f41636000)

【问题讨论】:

  • 你能显示那个静态二进制文件的 strace -f -v 吗?那么“文件foob”呢?您可能希望包含您正在使用的特定源和目标(Linux?)发行版+架构。
  • 按照建议,运行file foob。确保它是 64 位可执行文件。
  • 我刚刚编译了一个带有only -static 标志的简单程序:“gcc -o ts --std=c99 --static test.c”。工作正常。
  • 运行strace -f ./foob,这样我们就可以看到“没有这样的文件或目录”是什么意思。
  • @ChrisStratton,我在多个 linux 系统上从来没有遇到过-static 的问题。我可能不得不安装一些静态库,但就是这样。

标签: c++ c gcc glibc static-linking


【解决方案1】:

GNU libc 不是为静态链接而设计的。重要功能,例如gethostbynameiconv 在静态二进制文件中会出现故障或根本无法工作。可以说更糟糕的是,在某些情况下,静态二进制文件会尝试动态打开并使用libc.so.6,尽管静态链接的全部意义在于避免这种依赖关系。

您应该针对uClibcmusl libc 编译您的程序。

(至少 15 年都是如此。)

【讨论】:

  • 嗨@zwol,你能帮我理解为什么最好链接到uClibc或musl libc吗?如果一个人的目标是静态链接 libc 以完成为共享库而不是目标应用程序定制 libc(例如,内存分配行为),那么人们还会遵循这个建议吗?见stackoverflow.com/questions/35072500/…
  • @sholsapp 这取决于相关共享库使用了哪些 C 库函数。如果不详细了解您的共享库的功能、它需要 C 库的功能以及您为什么要首先做这个相当奇特的事情,我无法给您任何更具体的答案。
  • 我刚刚尝试了以下命令,其警告消息确认:gcc-4.8 --static ... netcat.c 警告:在静态链接应用程序中使用 'gethostbyaddr' 需要在运行时从用于链接的 glibc 版本
【解决方案2】:

首先请注意,libc 的静态链接可能不会提高程序的可移植性,因为 libc 可能依赖于系统的其他部分,例如内核版本。

如果您想尝试完整的静态链接,只需使用 -static 就可以了。前提是安装了所有使用的库的静态版本。

您可以使用以下方法检查您的程序是否仅链接静态库:

ldd binary_name

编辑:

为调试此问题提供有用信息的另一种方法是将 --verbose 添加到链接器标志中。

【讨论】:

  • 最后一个错误真的很奇怪。 -static 正是他想做的事情。并且 -static-libgcc -static-libstdc++ 可以省略,但这不应该改变任何东西。
  • 众所周知,静态链接在典型的现代桌面 linux 上并不完全可用。
  • @ChrisStratton:仅当您使用 glibc 时!
  • 当然,但那是张贴者正在使用的。你会在现代桌面 linux 上使用什么else
  • Musl 这些天,例如 Chris Stratton。 voidlinux 使用它。这很有趣——我不认为它在功能方面具有竞争力,但更多的竞争是 IMO 的一件好事。另请注意,“部分”静态链接很好;我保留了一个静态版本的busybox,但你可以静态编译make、sed、grep、coreutils等……这些都可以工作。有些人甚至使用 GCC 进行管理;我还没有。如果你设法以某种方式破坏了一个库,它会很有用(并且有一些方法可以意外地做到这一点)。
猜你喜欢
  • 2012-10-21
  • 2015-10-04
  • 2020-06-17
  • 2014-01-07
  • 1970-01-01
  • 2015-06-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多