如何在没有不必要的库函数的情况下制作静态可执行文件?

How to make static executable without unnecessary libraries functions?

比如我们有一个代码:

#include <stdio.h>

int main()
{
    printf("Hello, Stack Overflow!\n");
    
    return 0;
}

我们想要获得静态链接的可执行文件:

$ gcc -o main main.c -static

一切顺利,但有一个细微差别:

$ du -h main
768K    main

这么简单的程序是不是太过分了?让我们来看看可执行文件中使用的符号列表:

$ nm main
00000000004010f4 T abort
00000000004aec70 B __abort_msg
0000000000444be0 t add_alias2.part.0
000000000047e240 t add_fdes
000000000040163a t add_fdes.cold
0000000000444c70 t add_module.constprop.0
0000000000463570 t add_name_to_object.isra.0
0000000000462e30 t add_path.constprop.0.isra.0
00000000004adb28 d adds.1
000000000044fb70 T __add_to_environ
0000000000474210 t add_to_global_resize
00000000004741f0 t add_to_global_resize_failure.isra.0
0000000000474080 t add_to_global_update
0000000000409f50 t adjust_wide_data
00000000004af150 V __after_morecore_hook
0000000000405bd0 t alias_compare
0000000000481358 r aliasfile.0
00000000004166d0 W aligned_alloc
00000000004af178 b aligned_heap_area
0000000000461b40 T __alloc_dir
00000000004117b0 t alloc_perturb
00000000004af9c8 b any_objects_registered
0000000000486c40 r archfname
00000000004af520 b archive_stat
00000000004af500 b archloaded
00000000004af5c8 b archmapped
0000000000413780 t arena_get2.part.0
0000000000413ea0 t arena_get_retry
000000000045f8a0 T __argz_add_sep
000000000045f8a0 W argz_add_sep
000000000045f7c0 T __argz_create_sep
000000000045f7c0 W argz_create_sep
0000000000408c30 T ___asprintf
0000000000408c30 T __asprintf
0000000000408c30 W asprintf
0000000000402cd0 T __assert_fail
0000000000402b70 T __assert_fail_base
00000000004010e0 t __assert_fail_base.cold
000000000047fca0 t base_of_encoded_value
0000000000401658 t base_of_encoded_value.cold
0000000000417e60 i bcmp
0000000000495330 r blanks
00000000004953a0 r blanks
0000000000462250 T __brk
0000000000462250 W brk
00000000004ae230 B __bss_start
00000000004609d0 T __btowc
00000000004609d0 W btowc
00000000004afa00 b buf
...

在我的例子中 nm main | wc 给出了 1726 行,其中几乎与 libc 这样的库有关。那么,我们如何才能消除静态链接文件中未使用的代码呢?

已经有一个 similar question,但其中的说明仅适用于项目中使用的函数,不适用于库函数。

So, how we can eliminate unused code in statically linked files?

GLIBC 未针对静态链接进行优化。如果你想要小型静态链接的二进制文件,请使用其他一些 libc,例如饮食库。查看 this comparison 个可用选项。

虽然可以说您的示例程序 使用了 printf,因此链接所有相关的支持代码是合理的,但对于这个程序:

int main() { return 0; }

然而该程序(当静态链接时)在我的系统上的权重为 765KiB 使用 Debian GLIBC 2.31-13:

$ gcc tt.c -static
$ ls -l a.out
-rwxr-x--- 1 user user 782648 Aug 19 08:28 a.out