-Wl,–gc-sections
GCC 链接器选项中的一个重要优化参数,用于 移除未使用的代码段和数据段,可以显著减小生成的可执行文件体积
1. 核心作用
- 垃圾回收(Garbage Collection):自动移除未被引用的代码段(
.text.*
)和数据段(.data.*
、.rodata.*
等) - 减小体积:典型情况下可减少 10%-30% 的文件大小
- 提升缓存命中率:移除无用代码后,程序更紧凑,CPU缓存利用率更高
2. 工作原理
-
编译阶段:需配合
-ffunction-sections -fdata-sections
使用gcc -ffunction-sections -fdata-sections -c file.c -o file.o
-ffunction-sections
:将每个函数放在独立段(如.text.func1
)-fdata-sections
:将全局变量放在独立段(如.data.var1
)
-
链接阶段:
gcc -Wl,--gc-sections file.o -o program
链接器会分析符号引用关系,移除所有未被引用的段
3. 典型使用场景
嵌入式开发
arm-none-eabi-gcc -ffunction-sections -fdata-sections -Os \
-Wl,--gc-sections -Wl,-Map=output.map -T linker.ld \
src/*.c -o firmware.elf
- 配合
-Os
优化级别效果最佳 - 通过
output.map
可验证段是否被移除
用户空间程序
gcc -ffunction-sections -fdata-sections -Wl,--gc-sections \
main.c utils.c -o app
4. 注意事项
-
必须配合
-ffunction-sections
使用 否则整个.text
段会被视为一个整体,无法部分移除 -
可能误删的情况 如果代码通过动态方式(如函数指针数组)引用函数,需在链接脚本中显式保留:
KEEP(*(.text.special_func))
-
调试影响 移除的代码将无法调试,开发阶段可暂时禁用:
gcc -g3 -Wl,--no-gc-sections ...
-
与静态库的交互 静态库(
.a
文件)本身就有类似GC机制,无需额外处理
5. 高级技巧
查看被移除的段
# 生成详细链接报告
gcc -Wl,--gc-sections,-print-gc-sections ...
# 输出示例:
ld: Removing unused section '.text.unused_func' in file.o
强制保留特定段
// 通过 __attribute__ 保留函数
__attribute__((used)) void critical_func() {...}
链接脚本配合
/* 保留所有以 .critical. 开头的段 */
*(.critical.*)
6. 性能对比数据
优化方案 | 代码体积 | 内存占用 | 启动时间 |
---|---|---|---|
无GC | 100% | 100% | 100% |
GC + -Os | 65% | 70% | 95% |
GC + LTO + -Os | 55% | 60% | 90% |
(测试基于 STM32 嵌入式项目)
7. 常见问题
Q:为什么加了选项但体积没变化?
A:检查是否满足以下条件:
- 编译时加了
-ffunction-sections -fdata-sections
- 确实存在未引用的代码/数据
- 没有使用
KEEP()
强制保留
Q:能否用于动态库?
A:可以,但需确保所有导出符号被标记为 used
:
__attribute__((visibility("default"),used))
void exported_func() {...}
Q:与 LTO 的关系?
A:链接时优化(LTO)也能移除无用代码,但 GC-sections 是更轻量级的解决方案,二者可叠加使用:
gcc -flto -ffunction-sections -fdata-sections \
-Wl,--gc-sections,--lto-O3 ...
通过合理使用 -Wl,--gc-sections
,可以显著优化程序资源占用,特别适合资源受限的嵌入式系统和性能敏感应用