-Wl,–gc-sections

GCC 链接器选项中的一个重要优化参数,用于 移除未使用的代码段和数据段,可以显著减小生成的可执行文件体积

1. 核心作用

  • 垃圾回收(Garbage Collection):自动移除未被引用的代码段(.text.*)和数据段(.data.*.rodata.*等)
  • 减小体积:典型情况下可减少 10%-30% 的文件大小
  • 提升缓存命中率:移除无用代码后,程序更紧凑,CPU缓存利用率更高

2. 工作原理

  1. 编译阶段:需配合 -ffunction-sections -fdata-sections 使用

    gcc -ffunction-sections -fdata-sections -c file.c -o file.o
    • -ffunction-sections:将每个函数放在独立段(如 .text.func1
    • -fdata-sections:将全局变量放在独立段(如 .data.var1
  2. 链接阶段

    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. 注意事项

  1. 必须配合 -ffunction-sections 使用 否则整个 .text 段会被视为一个整体,无法部分移除

  2. 可能误删的情况 如果代码通过动态方式(如函数指针数组)引用函数,需在链接脚本中显式保留:

    KEEP(*(.text.special_func))
  3. 调试影响 移除的代码将无法调试,开发阶段可暂时禁用:

    gcc -g3 -Wl,--no-gc-sections ...
  4. 与静态库的交互 静态库(.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:检查是否满足以下条件:

  1. 编译时加了 -ffunction-sections -fdata-sections
  2. 确实存在未引用的代码/数据
  3. 没有使用 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,可以显著优化程序资源占用,特别适合资源受限的嵌入式系统和性能敏感应用