Skip to content

极致优化可执行文件大小

指令

shell
gcc file.c -Os -flto -ffunction-sections -fdata-sections \
    -fomit-frame-pointer -fno-inline -ffast-math \
    -fmerge-all-strings -s -DNDEBUG \
    -fno-asynchronous-unwind-tables -fno-unwind-tables \
    -Wl,--build-id=none -Wl,--nmagic -fno-stack-check \
    -fno-stack-protector -fno-rtti -fno-exceptions \
    -Wl,-z,norelro -fuse-ld=gold -m32 -fno-plt \
    -Wl,--gc-sections -Wl,--as-needed

含义

这些参数组合通过移除调试信息、禁用安全检查、优化代码生成和链接过程,能够显著减小最终二进制文件的大小,但可能会牺牲执行速度、调试能力和安全性,因此主要用于对体积有严格限制的特殊场景。

编译阶段参数(影响代码生成)

  • -Os:告诉编译器优先优化代码大小(而非执行速度),这是最核心的大小优化选项
  • -flto:启用链接时优化(Link-Time Optimization),允许编译器在链接阶段跨文件进行优化
  • -ffunction-sections:将每个函数放入单独的代码段,便于链接器后续移除未使用的函数
  • -fdata-sections:将每个全局变量放入单独的数据段,便于链接器移除未使用的数据
  • -fomit-frame-pointer:省略栈帧指针,减少生成的指令数量(可能影响调试)
  • -fno-inline:禁用函数内联(与-Os可能冲突,通常-Os会适度内联)
  • -ffast-math:启用快速数学运算,牺牲部分精度换取更小更快的代码
  • -fmerge-all-strings:合并所有相同的字符串常量,减少重复存储
  • -s:移除可执行文件中的符号表和调试信息
  • -DNDEBUG:定义NDEBUG宏,禁用assert()等调试相关代码
  • -fno-asynchronous-unwind-tables:禁用异步 unwind 表(用于异常处理)
  • -fno-unwind-tables:禁用 unwind 表(用于栈展开)
  • -fno-stack-check:禁用栈检查(安全性降低,代码更小)
  • -fno-stack-protector:禁用栈保护机制(安全性降低,代码更小)
  • -fno-rtti:禁用C++运行时类型信息(仅C++有效)
  • -fno-exceptions:禁用C++异常处理(仅C++有效)
  • -fno-plt:禁用过程链接表(PLT),减少间接调用开销和代码大小
  • -m32:生成32位架构的代码(通常比64位代码更小)

链接阶段参数(通过-Wl,传递给链接器)

  • --build-id=none:不生成构建ID,减少额外信息
  • --nmagic:生成"纯"可执行文件,不使用分页对齐,减小文件大小
  • -z,norelro:禁用RELRO(重定位只读)保护,牺牲安全性换取更小体积
  • --gc-sections:启用垃圾回收,移除未使用的代码段和数据段
  • --as-needed:仅链接真正需要的库,减少不必要的依赖

其他参数

  • -fuse-ld=gold:使用gold链接器(比传统ld链接器更快,且有时能生成更小的代码)

尘埃虽微,积之成集;问题虽小,记之为鉴。 雾中低语,心之所向;思绪飘渺,皆可成章。