如何减小生成的二进制文件的大小?

fel*_*021 14 linux gcc strip compiler-optimization

我知道有一个选项"-Os"来"优化尺寸",但它几乎没有影响,甚至在某些场合增加尺寸:(

strip(或"-s"选项)删除调试符号表,工作正常; 但它只能减少尺寸的小比例.

还有其他方法可以继续吗?

Dam*_*mon 15

除了明显的(-Os -s)之外,将函数对齐到不会崩溃的最小可能值(我不知道ARM对齐要求)可能会挤出每个函数的几个字节.
-Os 应该已经禁用了对齐功能,但是这可能仍然默认为4或8之类的值.如果ARM可以将例如1对齐,则可能会节省一些字节.

-ffast-math(或磨损性较小-fno-math-errno)不会设置errno并避免一些检查,这会减少代码大小.如果像大多数人一样,你还没有读过errno,那就是一个选择.

正确使用__restrict(或restrict)并const删除冗余负载,使代码更快更小(更正确).正确标记纯函数,这样可以调用函数调用.

启用LTO可能会有帮助,如果不可用,(编译所有的源文件转换成二进制一气呵成gcc foo.c bar.c baz.c -o program,而不是编译foo.c,bar.cbaz.c第一个目标文件,然后连接)将有类似的效果.它使得优化器一次可见一切,可能使其更好地工作.

-fdelete-null-pointer-checks可能是一个选项(请注意,这通常是使用任何"O"启用,但不是嵌入式目标).

将静态全局变量(希望没有那么多,但仍然存在)放入结构体中可以消除很多开销它们的开销.我在编写第一个OpenGL加载器时学到了这一点.在struct中使用所有函数指针并初始化struct会= {}生成一次调用memset,而初始化指针时,"normal way"会生成一百KB的代码,只是为了将每一个单独设置为零.

避免使用像devil那样的非平凡构造函数静态局部变量(POD类型没问题).Gcc将初始化非平凡构造函数静态本地线程安全,除非你编译-fno-threadsafe-statics,在很多额外代码中链接(即使你根本不使用线程).

使用libowfat而不是普通的crt可以大大减少二进制文件的大小.


Seb*_*ach 7

您也可以使用 -nostartfiles和/或-nodefaultlibs两者的组合-nostdlib.如果您不想要标准的启动文件,则必须编写自己的_start函数.另见 ompf上的这个帖子:

(引用佩林)

# man syscalls
# cat phat.cc
extern "C" void _start() {
        asm("int $0x80" :: "a"(1), "b"(42));
}
# g++ -fno-exceptions -Os -c phat.cc
# objdump -d phat.o

phat.o:     file format elf64-x86-64

Disassembly of section .text:

0000000000000000 <_start>:
   0:   53                      push   %rbx
   1:   b8 01 00 00 00          mov    $0x1,%eax
   6:   bb 2a 00 00 00          mov    $0x2a,%ebx
   b:   cd 80                   int    $0x80
   d:   5b                      pop    %rbx
   e:   c3                      retq
# ld -nostdlib -nostartfiles phat.o -o phat
# sstrip phat
# ls -l phat
-rwxr-xr-x 1 tbp src 294 2007-04-11 22:47 phat
# ./phat; echo $?
42
Run Code Online (Sandbox Code Playgroud)

摘要:上面的代码段产生了一个294字节的二进制文件,每个字节为8位.


小智 7

使用(1) 时,您需要确保使用所有相关选项。由于某种原因,--strip-all并不总是剥夺一切。删除不必要的部分可能会有所帮助。

但最终,减少二进制文件大小的最佳方法是从程序中删除代码和静态数据。让它做得更少,或者选择导致更少指令的编程结构。例如,您可以在运行时构建数据结构,或者按需从文件加载它们,而不是静态初始化的数组。


小智 5

假设还允许另一个工具;-)

然后考虑UPX:使用运行时解压缩的二进制终极包装器.

快乐的编码.

  • 请注意,这可能会增加RAM消耗,尤其是在共享库上使用时. (2认同)

Chr*_*rle 5

如果你想从二进制文件中挤出最后一滴空间,你可能需要学习组装.对于一个非常有趣(和有趣)的介绍,请看这个链接:

关于为Linux创建真正的Teensy ELF可执行文件的旋风教程