将整个标准库链接到每个C/ c++文件空间是否有效?



拥有整个标准库或任何其他库已经编译并准备链接以形成可执行文件是一个很好的特性,它使编译更快,但据我所知,整个库是链接的,即使只使用其中的几个函数。

因此,例如在我的机器上,下面的代码在编译为目标代码时是1.6 kB,但是当我将其链接到标准库时,它几乎变成了17 kB。

#include <stdio.h>
int main(void)
{
printf("Hello worldn");
}

是否有其他的方法来重新编译标准库(或任何其他库)的部分,这是为了使程序更节省空间所必需的?

对不起,如果这个问题已经问过了,我谷歌了一下,但没有找到任何答案。

如果我们转储生成的ELF可执行文件的内容,我们将看到没有C运行时库的部分因为GLIBC库是动态地链接在中。(例如来自libc.so.6).

$ gcc -Os -s a.c
$ ls -la a.out
-rwxrwxrwx 1 user user 14408 Feb 18 12:56 a.out
$ ldd a.out
linux-vdso.so.1 (0x00007ffd157f8000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007feb0a33f000)
/lib64/ld-linux-x86-64.so.2 (0x00007feb0a518000)
$ objdump -T a.out
a.out:     file format elf64-x86-64
DYNAMIC SYMBOL TABLE:
0000000000000000  w   D  *UND*  0000000000000000              _ITM_deregisterTMCloneTable
0000000000000000      DF *UND*  0000000000000000  GLIBC_2.2.5 puts
0000000000000000      DF *UND*  0000000000000000  GLIBC_2.2.5 __libc_start_main
0000000000000000  w   D  *UND*  0000000000000000              __gmon_start__
0000000000000000  w   D  *UND*  0000000000000000              _ITM_registerTMCloneTable
0000000000000000  w   DF *UND*  0000000000000000  GLIBC_2.2.5 __cxa_finalize

我们还注意到GCC将没有占位符的printf优化为puts(对于文件大小而言,这无关紧要)。

查看"inside"对于ELF,我们可以转储它的部分:

$ readelf -SW a.out
There are 28 section headers, starting at offset 0x3148:
Section Headers:
[Nr] Name              Type            Address          Off    Size   ES Flg Lk Inf Al
[ 0]                   NULL            0000000000000000 000000 000000 00      0   0  0
[ 1] .interp           PROGBITS        00000000000002a8 0002a8 00001c 00   A  0   0  1
[ 2] .note.ABI-tag     NOTE            00000000000002c4 0002c4 000020 00   A  0   0  4
[ 3] .note.gnu.build-id NOTE            00000000000002e4 0002e4 000024 00   A  0   0  4
[ 4] .gnu.hash         GNU_HASH        0000000000000308 000308 000024 00   A  5   0  8
[ 5] .dynsym           DYNSYM          0000000000000330 000330 0000a8 18   A  6   1  8
[ 6] .dynstr           STRTAB          00000000000003d8 0003d8 000082 00   A  0   0  1
[ 7] .gnu.version      VERSYM          000000000000045a 00045a 00000e 02   A  5   0  2
[ 8] .gnu.version_r    VERNEED         0000000000000468 000468 000020 00   A  6   1  8
[ 9] .rela.dyn         RELA            0000000000000488 000488 0000c0 18   A  5   0  8
[10] .rela.plt         RELA            0000000000000548 000548 000018 18  AI  5  23  8
[11] .init             PROGBITS        0000000000001000 001000 000017 00  AX  0   0  4
[12] .plt              PROGBITS        0000000000001020 001020 000020 10  AX  0   0 16
[13] .plt.got          PROGBITS        0000000000001040 001040 000008 08  AX  0   0  8
[14] .text             PROGBITS        0000000000001050 001050 000171 00  AX  0   0 16
[15] .fini             PROGBITS        00000000000011c4 0011c4 000009 00  AX  0   0  4
[16] .rodata           PROGBITS        0000000000002000 002000 000010 00   A  0   0  4
[17] .eh_frame_hdr     PROGBITS        0000000000002010 002010 00003c 00   A  0   0  4
[18] .eh_frame         PROGBITS        0000000000002050 002050 000100 00   A  0   0  8
[19] .init_array       INIT_ARRAY      0000000000003de8 002de8 000008 08  WA  0   0  8
[20] .fini_array       FINI_ARRAY      0000000000003df0 002df0 000008 08  WA  0   0  8
[21] .dynamic          DYNAMIC         0000000000003df8 002df8 0001e0 10  WA  6   0  8
[22] .got              PROGBITS        0000000000003fd8 002fd8 000028 08  WA  0   0  8
[23] .got.plt          PROGBITS        0000000000004000 003000 000020 08  WA  0   0  8
[24] .data             PROGBITS        0000000000004020 003020 000010 00  WA  0   0  8
[25] .bss              NOBITS          0000000000004030 003030 000008 00  WA  0   0  1
[26] .comment          PROGBITS        0000000000000000 003030 00001c 01  MS  0   0  1
[27] .shstrtab         STRTAB          0000000000000000 00304c 0000f7 00      0   0  1
Key to Flags:
W (write), A (alloc), X (execute), M (merge), S (strings), I (info),
L (link order), O (extra OS processing required), G (group), T (TLS),
C (compressed), x (unknown), o (OS specific), E (exclude),
l (large), p (processor specific)

所以~14 kB几乎是目前最小的ELF可执行文件大小,因为PIC, relro, eh_frame和其他由GNU链接器生成的部分。

您可以通过关闭relro(这会降低一点安全性)来减小大小。

$ gcc -Os -s -z norelro -Wl,--gc-sections a.c
$ $ ls -la a.out
-rwxrwxrwx 1 user user 10960 Feb 18 13:06 a.out

相关内容

  • 没有找到相关文章

最新更新