必须保留.dynsym和.dynstr以确保动态链接正常,.symtab、.strtab和.debug_*等可安全剥离;strip -g仅删调试信息,strip -s则彻底清除符号表,共享库推荐strip -d更安全。

直接裁剪就能显著减小体积,但必须分清哪些能删、哪些删了就运行不了——.dynsym 和 .dynstr 绝对不能动,否则动态链接器会报 undefined symbol 或直接拒绝加载。
先确认文件里到底有哪些“可删内容”
别盲目执行 strip,先用 readelf -S 看清 ELF 段构成。重点关注三类:
-
.symtab和.strtab:完整符号表,调试和链接时用,运行时完全不需要 -
.debug_*(如.debug_info、.debug_line):DWARF 调试信息,gdb 依赖它做源码级调试 -
.comment、.note.GNU-stack、.note.gnu.build-id:元信息,体积小,一般可保留
执行 readelf -S ./myapp | grep -E '\.(symtab|strtab|debug_|note|comment)' 快速定位。你会发现一个带 -g 编译的二进制,.debug_* 总体积常比 .text 大几倍。
strip -g 和 strip -s 的本质区别
strip -g 只删 .debug_* 段,保留 .symtab;strip -s(即 --strip-all)则连 .symtab 和 .strtab 一并清除。两者影响完全不同:
- 用
strip -g后,nm ./myapp仍能列出函数名,gdb却无法list源码或print局部变量 - 用
strip -s后,nm直接报错 “no symbols”,但objdump -T仍能看到.dynsym中的导出符号,程序照常运行 - 对共享库(
.so),优先用strip -d(--strip-unneeded),它只删链接时不需要的符号,比-s更安全
交叉编译环境下的 strip 必须配对使用
在嵌入式开发中,如果你用 arm-linux-gcc 编译,就必须用对应工具链的 arm-linux-strip,而非主机上的原生 strip。否则会因 BFD(Binary File Descriptor)格式不匹配导致失败,错误类似:
strip: ./libfoo.so: File format not recognized
常见交叉 strip 命令名包括:
arm-linux-stripaarch64-linux-gnu-stripmips-linux-gnu-stripriscv64-unknown-elf-strip
不确定时,用 file ./myapp 查看目标架构,再用 arm-linux-strip --help | head -n5 验证是否支持该格式。
想留调试能力?用 --only-keep-debug + objcopy 拆分
生产环境发出去的二进制要小,但内部又得保留调试能力——这时候不能只靠 strip,得配合 objcopy 把调试信息抽出来单独存档:
arm-linux-strip --only-keep-debug ./myapp -o ./myapp.debug arm-linux-strip ./myapp arm-linux-objcopy --add-section .debug=./myapp.debug --set-section-flags .debug=readonly,debug ./myapp
注意最后一步是把 .debug 段加回去,但仅用于归档;真正发布的 ./myapp 仍是 stripped 版。出问题时,把 ./myapp.debug 和 stripped 二进制一起丢给 gdb 就能还原调试体验。
最容易被忽略的一点:--only-keep-debug 不会保留 .symtab,所以生成的 .debug 文件本身不含符号表——若需完整调试,得在 strip 前先用 objcopy --only-keep-debug 备份原始带符号的版本,而不是对已 strip 过的文件操作。


















