我有简单的程序,只调用几个加密函数。我可以编译动态链接的它,它会生成约 15KB 的二进制文件:
gcc -s -o crypt crypt.c -lcrypto
当我尝试静态编译它时,它会生成一个巨大的二进制文件 ~4MB:
gcc -s -o crypt crypt.c /usr/lib/x86_64-linux-gnu/libcrypto.a
我曾经在以前的系统(Debian 10、gcc 8、libssl1.1)上编译相同的二进制文件,它生成约 55KB 的二进制文件。
现在我正在编译 Debian 12、gcc 12 和 libssl3 版本 3.0.9,它会生成上述巨大的二进制文件,大小约为 200 倍。
是否可能,它包含静态二进制文件中的所有函数,而不是仅我实际使用的函数?
或者二进制文件如此之大的其他原因?
(我需要在最小系统上运行我的二进制文件,该系统没有依赖库)
这是生成的二进制文件的
ldd
:
ldd crypt
linux-vdso.so.1 (0x00007ffd72bdd000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fd1680d0000)
/lib64/ld-linux-x86-64.so.2 (0x00007fd168662000)
我有简单的程序,只调用几个加密函数。我可以编译动态链接的它,它会生成约 15KB 的二进制文件:
gcc -s -o crypt crypt.c -lcrypto
libcrypto.a
中的模块(此问题与静态或动态链接无关)解决(递归)链接引用。当我尝试静态编译它时,它会生成一个巨大的二进制文件 ~4MB:
gcc -s -o crypt crypt.c /usr/lib/x86_64-linux-gnu/libcrypto.a
libcrypto.a
中的所有模块(不仅仅是解决引用的模块),并且这是独立于libcrypto.a
的内容完成的(这是其内容) .so
共享可执行文件或.o
普通静态链接可执行文件)比较
objdump -h crypt
的输出,您将看到以一种或另一种方式包含在二进制文件中的不同模块。
顺便说一下,可执行文件的大小并不能提供它在内存中的实际最终大小,因为链接到它的共享二进制文件将由运行时搜索的不同文件加载。如果你例如检查 C 运行时库的大小,您会看到巨大的大小,并且许多二进制文件似乎没有包含它。但是,一旦您的程序(使用它)加载到内存中,库的完整二进制文件就会加载到内存中(但对于链接到它的所有可执行文件,它的文本段只会加载一次,这使得很多节省系统内存)使程序文本的文本段在使用同一程序的所有进程之间共享的相同节省方法(例如
ls
)适用于程序使用的共享库...但它们不是以任何形式包含在可执行二进制文件中。
归档库(
.a
文件)的使用使得链接器可以根据是否需要解决依赖关系来决定是否必须包含库中包含的任何文件。但要使其发挥作用,链接必须使用 -l
选项引用库,而不是作为命令参数列表中的对象。不需要的文件的链接现在由链接器检查,这使得根据链接器的内部工作构建应该/不应该链接的目标文件库是一件好事。