注:本文为 "Linux strip" 相关合辑。
略作重排,未整理去重。
如有内容异常,请看原文。
一、strip 命令基础概述
1.1 命令用途
strip 是 UNIX / Linux 环境下的文件精简工具,作用为去除 XCOFF(扩展公共对象文件格式)对象文件、可执行文件、库文件中的调试信息、冗余标识符与辅助段信息,在不影响文件正常运行的前提下,缩减文件存储体积。
该命令与 compress 等压缩工具存在功能差异:strip 执行永久精简操作,处理后的文件不可恢复原始状态,无需解压即可直接运行;压缩工具处理后的文件必须完成解压操作后才可使用。strip 仅适用于已完成调试、测试定稿的程序模块与发布版本文件。
1.2 工作原理
strip 命令可对目标文件的冗余信息进行选择性剔除,默认清理范围包含行号信息、重定位信息、调试段、typchk 段、注释段、文件头及部分符号表。
针对不同文件类型的处理规则:
- 对象模块:根据指定参数精准剔除对应冗余信息。
- 归档 / 库文件 :直接清除归档内的全局符号表,可通过
ar -s命令恢复归档文件的符号表。
1.3 GCC 编译关联特性
GCC 编译流程可实现与 strip 等效的精简效果,各项对应规则如下:
| 编译方式 | 等价操作 | 说明 |
|---|---|---|
编译去除 -g 参数 |
--strip-debug |
仅剔除调试信息 |
直接执行 strip 命令 |
--strip-debug + --strip-all |
剔除调试信息与全部符号信息,文件精简幅度更大 |
GCC 编译添加 -s 参数 |
strip 命令 |
功能完全一致,可直接生成精简后的可执行文件 |
功能限制规则 :静态库 .a 文件仅支持 --strip-debug 精简模式,无法完整剥离符号表;经过静态编译的程序不建议执行 strip 操作,该操作易引发链接异常。
二、strip 命令语法与参数详解
2.1 标准语法
strip [ -V ] [ -r [ -l ] | -x [ -l ] | -t | -H | -e | -E ] [ -X { 32 | 64 | 32_64 } ] [ -- ] File ...
2.2 完整参数说明
| 参数 | 功能描述 |
|---|---|
-e |
在对象文件可选头中设置 F_LOADONLY 标志。若文件存入归档,该标志会告知 ld 绑定程序,链接时忽略该文件的符号信息。 |
-E |
复位关闭对象文件可选头中的 F_LOADONLY 位,抵消 -e 参数的设置效果。 |
-H |
剔除对象文件头、所有可选头及段头部分,保留符号表信息。 |
-l(小写 L) |
单独剔除对象文件中的源代码行号调试信息。 |
-r |
剔除绝大部分符号表信息,仅保留外部符号与静态符号条目;同时清除调试段、typchk 段,保留重定位信息。处理后的文件仍可作为 ld 链接编辑器的输入文件。 |
-t |
剔除大部分符号表冗余信息,保留函数符号与行号信息。 |
-V |
打印 strip 命令的版本号信息。 |
-x |
剔除全部符号表信息,保留静态、外部符号标识;同步清除重定位信息,处理后的文件无法再次链接。 |
-X mode |
指定处理的对象文件位数类型,支持三种模式:32:仅处理 32 位对象文件(默认);64:仅处理 64 位对象文件;32_64:同时处理 32 位、64 位对象文件。可通过 OBJECT_MODE 环境变量默认配置,-X 参数优先级高于环境变量。 |
-- |
将后续所有参数解析为文件名,支持处理名称以连字符开头的特殊文件。 |
2.3 退出状态值
| 状态值 | 执行结果 |
|---|---|
0 |
命令执行成功 |
> 0 |
命令执行出错 |
2.4 命令路径
不同系统与编译环境下,strip 工具默认路径存在差异:AIX 系统默认路径为 /usr/ccs/bin/strip;主流 Linux 系统(Ubuntu、CentOS)GNU 工具集默认路径为 /usr/bin/strip;ARM 交叉编译链 strip 工具路径随工具链安装目录变动,位于工具链 bin 目录下。
三、strip 命令实操示例
3.1 基础精简可执行文件
剔除 a.out 默认可执行文件的符号表、行号及冗余调试信息:
bash
strip a.out
3.2 剔除文件头部信息
移除 a.out 的对象文件头、可选头及段头信息:
bash
strip -H a.out
3.3 批量处理 32 / 64 位库文件
精简静态库 lib.a 中所有 32 位、64 位冗余符号信息:
bash
strip -X 32_64 lib.a
3.4 实际瘦身效果对比
通过编写基础测试程序,可直观验证 strip 对文件体积的精简效果:
c
#include <stdio.h>
main()
{
printf("hello, world\n");
}
使用 cc 编译源码后,原始文件大小为 46176 字节。执行 strip 处理后,文件体积缩减至 30648 字节,体积缩减比例超过 1 / 3 1 / 3 1/3,处理后的程序可正常运行。
四、COFF 文件结构与 strip 作用区段
COFF(通用对象文件格式)是目标文件(.o)与可执行文件的通用存储格式。strip 命令的精简操作可作用于 COFF 文件的指定区段,文件完整组成结构及对应区段属性如下:
| 区段名称 | 功能说明 |
|---|---|
| 文件头(File header) | 存储文件基础通用信息,所有 COFF 文件默认包含,可通过 strip 部分参数剔除 |
| 扩展头(Optional header) | 仅存在于可执行文件,存储可执行程序专属信息,支持 strip 精简 |
| 区段头(Section header) | 记录所有文件区段的属性信息,每个区段对应一个独立区段头 |
| 原始数据区(Raw data sections) | 存储机器指令、初始化变量等业务数据,strip 不会剔除该区域内容 |
| 重定位信息(Relocation information) | 存储跨模块符号引用信息,仅存在于目标文件,部分 strip 参数可剔除该信息 |
| 行号信息(Line number information) | 源码行号调试信息,编译带 -g 参数时生成,是 strip 主要精简对象 |
| 符号表(Symbol table) | 存储文件所有符号信息,未被 strip 处理的可执行文件默认保留 |
| 字符串表(String table) | 存储长度超过 8 字节的长符号名 |
五、strip 开发使用规范与注意事项
5.1 使用场景规范
- 适用场景:已调试完成、功能稳定的可执行文件、发布版动态库,用于缩减程序体积、节省设备存储(嵌入式开发高频使用)。
- 禁用场景:开发调试阶段文件、静态库文件、需要后续链接的目标文件。
5.2 开发最佳实践
为同时满足程序调试与版本发布的使用需求,可采用双文件保留方案:
- 保留未
strip原始文件:用于线上问题定位、addr2line源码溯源、程序调试。 - 使用
strip精简后文件:用于设备部署、版本发布,减小存储占用。
5.3 常见问题说明
- 执行
strip后文件体积无变化,表明当前文件已完成精简,不存在可剔除的冗余信息。 - 经过
strip处理的文件会移除全部调试符号,无法使用dbx、addr2line等工具完成程序调试与溯源工作。 strip默认操作会清除文件的.symbol符号段与.debug调试段,未完成定型测试的程序不建议执行该操作。
六、ARM 交叉编译工具链及配套工具使用
6.1 交叉编译概述
交叉编译用于适配编译环境与程序运行环境不匹配的开发场景,典型场景为在 x86 架构设备上完成程序编译,生成可在 ARM 架构硬件设备上运行的可执行文件,是嵌入式开发的常用编译方式。
6.2 交叉编译链安装配置
6.2.1 工具链下载地址
- ARM 官方工具链 - Arm GNU Toolchain
https://developer.arm.com/Tools and Software/GNU Toolchain - https://developer.arm.com/open-source/gnu-toolchain
- Linaro 历史版本:Download Linaro Forge
https://www.linaroforge.com/release-history
https://www.linaroforge.com/download-forge-old-version
6.2.2 解压与环境变量配置
解压工具链至系统目录:
bash
sudo tar -xvf gcc-arm-11.2-2022.02-x86_64-arm-none-linux-gnueabihf.tar.xz -C /opt
编辑环境变量文件,追加工具链路径:
bash
vim ~/.bashrc
文件末尾追加:
bash
export PATH=$PATH:/opt/gcc-arm-11.2-2022.02-x86_64-arm-none-linux-gnueabihf/bin
生效环境变量:
bash
source ~/.bashrc
6.2.3 依赖兼容处理
32 位工具链在 64 位系统运行时,需安装兼容依赖:
bash
sudo apt-get install ia32-libs
sudo apt-get install libc6:i386
sudo apt-get install lib32z1
6.2.4 工具链校验
bash
arm-none-linux-gnueabihf-gcc -v
6.3 交叉编译工具集使用
嵌入式 ARM 开发常用工具集包含 gcc、readelf、objdump、size、nm、addr2line、objcopy、strings、strip,各工具的标准实操方式如下。
测试用例源码:
c
#include <stdlib.h>
#include <stdio.h>
int g_val = 12;
int g_uninit;
const char *str = "who am I?";
static char s_uninit;
int main()
{
printf("hello world!\n");
int *p = malloc(sizeof(int));
static int s_tmp = 0;
free(p);
return 0;
}
6.3.1 gcc 编译工具
基础编译命令(带调试信息):
bash
arm-none-linux-gnueabihf-gcc -g main.c -o main
编译后文件状态(未精简):带调试信息、未剥离符号。
bash
file main
输出:
main: ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV), dynamically linked,
interpreter /lib/ld-linux-armhf.so.3, for GNU/Linux 3.2.0, with debug_info, not stripped
6.3.2 readelf 文件信息查看工具
该工具用于读取并展示 ELF 可执行文件的文件头部、区段分布、符号表等底层信息。
查看文件头部信息:
bash
arm-none-linux-gnueabihf-readelf -h main
查看所有区段头信息:
bash
arm-none-linux-gnueabihf-readelf -S main
查看文件符号地址:
bash
arm-none-linux-gnueabihf-readelf -s main
6.3.3 objdump 反汇编工具
该工具用于完成文件反汇编操作,查看程序对应的汇编代码,多用于程序异常调试与代码逻辑分析。
bash
arm-none-linux-gnueabihf-objdump -D main > main.txt
6.3.4 size 段大小查看工具
该工具用于快速统计可执行文件中 text、data、bss 等区段的存储空间占用大小。
bash
arm-none-linux-gnueabihf-size main
6.3.5 nm 符号查看工具
该工具用于输出文件内所有全局变量、静态变量、自定义函数的符号信息及属性标识。
bash
arm-none-linux-gnueabihf-nm main
符号属性标识规则 :小写字母代表局部符号,大写字母代表全局符号;T 对应代码段、D 对应初始化数据段、B 对应未初始化 BSS 段、U 对应未定义符号。
6.3.6 addr2line 源码溯源工具
该工具可通过程序内存地址反向匹配对应的源码文件与代码行号,是程序崩溃定位的常用工具。
bash
arm-none-linux-gnueabihf-addr2line -e main -psfC 0x10451
6.3.7 objcopy 文件格式转换工具
该工具可实现目标文件格式转换、自定义区段增减、调试信息分离等操作,常用命令如下:
bash
# 转换为二进制裸机文件
arm-none-linux-gnueabihf-objcopy -O binary main main.bin
# 分离调试信息
arm-none-linux-gnueabihf-objcopy --only-keep-debug main main.debuginfo
# 剔除调试信息
arm-none-linux-gnueabihf-objcopy --strip-debug main main.stripdebug
6.3.8 strings 字符串查看工具
该工具用于提取可执行文件中所有可打印字符串,可用于查看程序内置的常量文本内容。
bash
arm-none-linux-gnueabihf-strings main
6.3.9 交叉编译环境 strip 工具实操
ARM 交叉编译链内置的 strip 工具,可对嵌入式可执行文件进行精简处理,降低文件体积,减少设备 Flash 存储空间占用:
bash
# 精简 ARM 可执行文件
arm-none-linux-gnueabihf-strip main
文件处理前后体积对比:原始文件大小为 13116 字节,精简后文件大小为 5600 字节,文件体积缩减幅度明显。
6.4 Linaro aarch64 交叉编译工具链专项配置
6.4.1 软硬件环境参数
编译主机环境:x86_64 架构,Ubuntu 20.04 系统;目标运行环境:RK3588 设备,aarch64 架构,Ubuntu 20.04 系统,小端字节序模式。
6.4.2 工具链版本选择
本次适配开发场景选用 Linaro 7.5 稳定版本工具链,该版本兼容性强,适配多数嵌入式 Linux 设备开发场景,无特殊定制需求时,可选用对应系列最新稳定版本。
工具链官方下载主页:https://releases.linaro.org/components/toolchain/binaries/
6.4.3 目标平台版本分类选型
Linaro 工具链针对 aarch64 架构划分多种适配版本,对应不同运行场景,具体分类如下:
| 版本名称 | 适用场景 |
|---|---|
aarch64-elf |
适配裸机嵌入式开发场景,无 Linux 系统依赖 |
aarch64-linux-gnu |
适配 aarch64 架构 Linux 系统开发场景,为常规嵌入式 Linux 开发通用版本 |
aarch64_be-elf |
大端字节序,适配裸机嵌入式开发场景 |
aarch64_be-linux-gnu |
大端字节序,适配 aarch64 架构 Linux 系统开发场景 |
本次 RK3588 aarch64 小端 Linux 设备开发,选用 aarch64-linux-gnu 版本工具链。
6.4.4 工具链文件解析与下载
aarch64-linux-gnu 目录下包含三类配套文件,各文件功能定义如下:
| 文件名 | 功能说明 |
|---|---|
gcc-linaro-7.5.0-2019.12-x86_64_aarch64-linux-gnu.tar.xz |
交叉编译工具包,集成 GCC 编译器、汇编器、链接器及各类配套调试、处理工具,用于在 x86_64 主机编译生成 aarch64 架构可执行文件 |
runtime-gcc-linaro-7.5.0-2019.12-aarch64-linux-gnu.tar.xz |
运行时依赖库包,包含目标设备运行程序所需的共享库文件 |
sysroot-glibc-linaro-2.25-2019.12-aarch64-linux-gnu.tar.xz |
系统根目录库文件包,包含目标平台 Glibc 标准库头文件、静态库与动态库文件,用于编译链接依赖系统库的程序 |
常规应用开发仅需下载编译工具包,完整下载地址:https://releases.linaro.org/components/toolchain/binaries/latest-7/aarch64-linux-gnu/gcc-linaro-7.5.0-2019.12-x86_64_aarch64-linux-gnu.tar.xz
6.4.5 工具链解压与目录结构
执行解压命令释放工具链文件:
bash
tar -xvf gcc-linaro-7.5.0-2019.12-x86_64_aarch64-linux-gnu.tar.xz
解压后目录结构如下,bin 目录集成全部交叉编译工具,包含 aarch64-linux-gnu-strip 精简工具:
.
├── aarch64-linux-gnu
│ ├── bin
│ ├── include
│ ├── lib
│ ├── lib64
│ └── libc
├── bin
│ ├── aarch64-linux-gnu-addr2line
│ ├── aarch64-linux-gnu-ar
│ ├── aarch64-linux-gnu-as
│ ├── aarch64-linux-gnu-g++
│ ├── aarch64-linux-gnu-gcc
│ ├── aarch64-linux-gnu-ld
│ ├── aarch64-linux-gnu-nm
│ ├── aarch64-linux-gnu-objcopy
│ ├── aarch64-linux-gnu-objdump
│ ├── aarch64-linux-gnu-readelf
│ ├── aarch64-linux-gnu-size
│ ├── aarch64-linux-gnu-strings
│ └── aarch64-linux-gnu-strip
├── include
├── lib
├── libexec
└── share
6.4.6 工具链功能测试
编写基础 HelloWorld 测试源码,完成交叉编译验证工具链可用性。x86_64 主机无法直接运行 aarch64 架构可执行文件,可通过 file 命令校验文件架构信息。
使用 nm 工具可正常读取编译后可执行文件的符号表信息,输出结果包含程序全局符号、局部符号、未定义库符号等完整数据,证明工具链运行正常。
bash
$ /root/workspace/cross_test/cross_build/gcc-linaro-7.5.0-2019.12-x86_64_aarch64-linux-gnu/bin/aarch64-linux-gnu-nm main
输出示例:
U abort@@GLIBC_2.17
0000000000411038 B __bss_end__
0000000000411038 B _bss_end__
0000000000411030 B __bss_start
0000000000411030 B __bss_start__
0000000000400578 t call_weak_fn
0000000000411030 b completed.7806
0000000000411020 D __data_start
0000000000411020 W data_start
0000000000400590 t deregister_tm_clones
00000000004005f8 t __do_global_dtors_aux
0000000000410dd0 t __do_global_dtors_aux_fini_array_entry
0000000000411028 D __dso_handle
0000000000410dd8 d _DYNAMIC
0000000000411030 D _edata
0000000000411038 B __end__
0000000000411038 B _end
00000000004006dc T _fini
0000000000400628 t frame_dummy
0000000000410dc8 t __frame_dummy_init_array_entry
0000000000400770 r __FRAME_END__
0000000000410fd8 d _GLOBAL_OFFSET_TABLE_
w __gmon_start__
0000000000400718 r __GNU_EH_FRAME_HDR
00000000004004b8 T _init
0000000000410dd0 t __init_array_end
0000000000410dc8 t __init_array_start
00000000004006f0 R _IO_stdin_used
w _ITM_deregisterTMCloneTable
w _ITM_registerTMCloneTable
00000000004006d8 T __libc_csu_fini
0000000000400658 T __libc_csu_init
U __libc_start_main@@GLIBC_2.17
000000000040062c T main
U puts@@GLIBC_2.17
00000000004005c0 t register_tm_clones
0000000000400530 T _start
0000000000411030 D __TMC_END__
6.4.7 CMake 交叉编译环境配置
基于 CMake 构建项目时,可通过固定参数配置交叉编译环境,指定工具链路径与编译链接参数,适配 aarch64 嵌入式平台开发,基础配置模板如下:
cmake
# 设置编译器和链接器路径
set(CMAKE_C_COMPILER "/path/to/embedded-gcc")
set(CMAKE_CXX_COMPILER "/path/to/embedded-g++")
set(CMAKE_LINKER "/path/to/embedded-ld")
# 配置编译与链接标志
set(CMAKE_C_FLAGS "-mcpu=cortex-m3 -mthumb")
set(CMAKE_CXX_FLAGS "-mcpu=cortex-m3 -mthumb")
set(CMAKE_EXE_LINKER_FLAGS "-T/path/to/linker_script.ld")
七、总结
strip 是应用于 Linux 与嵌入式开发的轻量化文件精简工具,功能为在不影响程序运行的前提下,剥离文件内的调试信息、符号信息、重定位信息等冗余数据,缩减文件存储体积。工具使用需区分开发调试场景与版本发布场景,规避调试信息丢失导致的问题无法溯源的情况。
在 ARM 交叉编译开发流程中,strip 可与 gcc、readelf、objdump 等工具配合使用。标准化的编译、调试、精简流程,可同时适配程序开发调试需求与设备部署的轻量化需求,是嵌入式产品量产发布的常用操作。
Reference
- strip 命令的用法_c 语言 strip 函数用法-CSDN 博客
https://blog.csdn.net/clozxy/article/details/5581452 - gcc 编译 strip 使用_gcc strip .a-CSDN 博客
https://blog.csdn.net/hailmy/article/details/26227347 - 编译中使用 strip 的介绍_编译 strip-CSDN 博客
https://blog.csdn.net/sevennineeleven/article/details/81218154 - gcc -strip 编译选项的作用_gcc strip-CSDN 博客
https://blog.csdn.net/weixin_43839785/article/details/108690150 - 交叉编译链安装及工具集(gcc、readelf、objdump、objcopy 和 strip 等)使用方法_交叉编译工具-CSDN 博客
https://blog.csdn.net/sinat_32152141/article/details/124970429 - linaro 交叉编译工具链下载与使用笔记-CSDN 博客
https://blog.csdn.net/yjkhtddx/article/details/134676016