Whisky:突破macOS与Windows壁垒的一站式终极方案
2026/6/9 1:21:49
本文档基于 Linux 内核和 GNU 工具链环境,深度解析strip命令的技术原理,并提供完整的实战操作指南。
ELF (Executable and Linkable Format) 是 Linux 下的标准二进制文件格式。在编译链接过程中,为了支持调试和链接,文件中包含了大量辅助信息:
.symtab(Symbol Table): 完整的符号表,包含全局变量、函数名、静态符号、源文件路径等。.strtab(String Table): 存储.symtab中符号名称的字符串池。.debug_*(Debug Sections): 包含 DWARF 格式的调试信息(行号映射、变量类型、栈帧信息等),由-g选项生成。.dynsym(Dynamic Symbol Table): 仅包含运行时动态链接必需的符号(导出函数、外部引用)。strip的核心作用是移除 ELF 文件中“非运行时必需”的信息。
.dynsym。gdb无法映射源代码行号,无法查看局部变量,但不影响运行*。.dynsym和.dynstr不能被移除,否则动态链接器无法工作。strip不会直接提升程序的 CPU 执行效率。代码段(.text)和数据段(.data)保持不变。strip[选项][输入文件...]注:strip会直接修改输入文件,建议操作前备份。
| 参数 | 长参数 | 作用 | 适用场景 |
|---|---|---|---|
| -s | --strip-all | 移除所有符号表和重定位信息 | 发布最终可执行文件 (生产环境首选) |
| -g | --strip-debug | 仅移除.debug_*调试信息,保留.symtab | 需要保留部分符号用于初步排错 |
| -d | --strip-unneeded | 移除所有不需要的符号(对库文件特别有用) | 共享库 (.so) 发布 |
--only-keep-debug | 清空代码段,仅保留调试符号 | 生成分离的调试符号文件 (.debug) |
我们准备了一个简单的main.c程序,使用gcc -g编译生成带有完整调试信息的main_debug。
执行readelf -S main_debug | grep -E "debug|symtab":
[28] .debug_aranges PROGBITS 0000000000000000 0000303d [29] .debug_info PROGBITS 0000000000000000 0000306d [30] .debug_abbrev PROGBITS 0000000000000000 000030f9 [31] .debug_line PROGBITS 0000000000000000 0000313c [32] .debug_str PROGBITS 0000000000000000 0000318e [33] .debug_line_str PROGBITS 0000000000000000 00003267 [34] .symtab SYMTAB 0000000000000000 000032d8可以看到包含了大量的调试节区和完整符号表。
strip --strip-debug(仅移除调试信息)执行后查看节区:
[28] .symtab SYMTAB 0000000000000000 00003040结果:.debug_*节区全部消失,但.symtab被保留。此时用 GDB 调试可以看到函数名,但无法看源码行号。
strip --strip-all(移除所有)执行后查看节区:
(无输出)结果:所有.debug_*和.symtab都被移除。此时文件体积最小。
$ls-lh main_* -rw-rw-r--1t t 17K Dec1117:01 main_debug(原始带调试信息)-rw-rw-r--1t t 16K Dec1117:01 main_debug_only(去除调试信息)-rw-rw-r--1t t 15K Dec1117:01 main_all(去除所有符号)注:对于大型 C++ 项目,体积差异会非常巨大(通常能减小 5-10 倍)。
在生产环境中,我们希望发布的程序体积小,但出问题时又能调试。
解决方案:分离调试符号。
objcopy --only-keep-debug main_separated main.debugstrip --strip-debug --strip-unneeded main_separatedobjcopy --add-gnu-debuglink=main.debug main_separated效果:发布main_separated给用户,自己保留main.debug。当用户发回core dump时,使用gdb main_separated core -s main.debug即可完美调试。
strip --strip-all。strip --strip-unneeded。这会保留动态链接所需的符号,移除未导出的局部符号和调试信息。切勿对库文件随意使用--strip-all,这可能会移除重定位信息导致库无法加载。.o文件的集合,strip 会移除重定位信息,导致链接时报错。建议在链接成最终程序后再 strip。gcc -svsstripgcc -s: 在链接阶段直接剔除符号表。strip: 编译后处理。-g -O2编译,生成带调试信息的全量版本。objcopy提取调试符号到符号服务器或归档存储。strip处理发布包中的二进制文件。Build ID到源代码版本的映射关系。graph TD subgraph Original[原始 ELF 文件] Header1[ELF Header] Text1[.text / .data] DynSym1[.dynsym (动态符号)] SymTab1[.symtab (完整符号)] Debug1[.debug_* (调试信息)] end subgraph Stripped[Strip --strip-all 后] Header2[ELF Header] Text2[.text / .data] DynSym2[.dynsym (动态符号)] end Header1 --> Header2 Text1 --> Text2 DynSym1 --> DynSym2 SymTab1 -- 移除 --> X1[❌] Debug1 -- 移除 --> X2[❌] style Original fill:#f9f,stroke:#333 style Stripped fill:#bfb,stroke:#333 style SymTab1 fill:#ff9999 style Debug1 fill:#ff9999