为什么不鼓励静态链接 glibc?

2022-01-11 00:00:00 c linker c++ static-linking glibc

大多数在线资源表明您可以静态链接 glibc,但不鼓励这样做;例如centos 软件包回购:

Most of the sources online state that you can statically link glibc, but discourage from doing so; e.g. centos package repo:

The glibc-static package contains the C library static libraries
for -static linking.  You don't need these, unless you link statically,
which is highly discouraged.

这些消息来源很少(或从不)说明为什么这是一个坏主意.

These sources rarely (or never) say why that would be a bad idea.

推荐答案

其他答案给出的理由是正确的,但不是最重要的原因.

The reasons given in other answers are correct, but they are not the most important reason.

glibc 不应该被静态链接的最重要原因是它在内部大量使用了 dlopen,加载 NSS (名称服务切换) 模块和 iconv 转换.模块本身引用 C 库函数.如果主程序与 C 库动态链接,那没问题.但如果主程序与 C 库静态链接,dlopen 必须去加载 C 库的第二个副本以满足模块的加载要求.

The most important reason why glibc should not be statically linked, is that it makes extensive internal use of dlopen, to load NSS (Name Service Switch) modules and iconv conversions. The modules themselves refer to C library functions. If the main program is dynamically linked with the C library, that's no problem. But if the main program is statically linked with the C library, dlopen has to go load a second copy of the C library to satisfy the modules' load requirements.

这意味着您的静态链接"程序仍然需要在文件系统上存在 libc.so.6 的副本,加上 NSS 或 iconv 或任何模块本身,以及模块的其他动态库可能需要,比如ld-linux.so.2libresolv.so.2等.这不是人们在静态链接程序时通常想要的.

This means your "statically linked" program still needs a copy of libc.so.6 to be present on the file system, plus the NSS or iconv or whatever modules themselves, plus other dynamic libraries that the modules might need, like ld-linux.so.2, libresolv.so.2, etc. This is not what people usually want when they statically link programs.

这也意味着静态链接的程序在其地址空间中有两个 C 库副本,它们可能会争夺使用谁的 stdout 缓冲区,谁可以调用 sbrk 带有非零参数,诸如此类.glibc 内部有一堆防御性逻辑试图让这项工作发挥作用,但从来没有保证能够工作.

It also means the statically linked program has two copies of the C library in its address space, and they might fight over whose stdout buffer is to be used, who gets to call sbrk with a nonzero argument, that sort of thing. There is a bunch of defensive logic inside glibc to try to make this work, but it's never been guaranteed to work.

您可能认为您的程序不需要担心这一点,因为它从不调用 getaddrinfoiconv,但语言环境支持使用 iconv 内部,这意味着 任何 stdio.h 函数 都可能触发对 dlopen 的调用,而您无法控制它,用户的环境变量设置.

You might think your program doesn't need to worry about this because it doesn't ever call getaddrinfo or iconv, but locale support uses iconv internally, which means any stdio.h function might trigger a call to dlopen, and you don't control this, the user's environment variable settings do.

如果你的程序确实调用iconv,那么事情会变得更糟,尤其是当静态链接"的可执行文件构建在一个发行版上时,然后复制到另一个.iconv 模块有时位于不同发行版的不同位置,因此在 Red Hat 发行版上构建的可执行文件可能无法在 Debian 上正常运行,这与人们想从静态链接的可执行文件中得到什么.

And if your program does call iconv, for example, then things get even worse, especially when a "statically linked" executable is built on one distro, and then copied to another. The iconv modules are sometimes located in different places on different distros, so an executable that was built, say, on a Red Hat distro may fail to run properly on a Debian one, which is exactly the opposite of what people want from statically linked executables.

相关文章