Linux strip 命令 | 详解及在 Linaro 交叉编译工具链中的使用
注:本文为 “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默认可执行文件的符号表、行号及冗余调试信息:
strip a.out3.2 剔除文件头部信息
移除a.out的对象文件头、可选头及段头信息:
strip-Ha.out3.3 批量处理 32 / 64 位库文件
精简静态库lib.a中所有 32 位、64 位冗余符号信息:
strip-X32_64 lib.a3.4 实际瘦身效果对比
通过编写基础测试程序,可直观验证strip对文件体积的精简效果:
#include<stdio.h>main(){printf("hello, world\n");}使用cc编译源码后,原始文件大小为 46176 字节。执行strip处理后,文件体积缩减至 30648 字节,体积缩减比例超过1 / 3 1 / 31/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 解压与环境变量配置
解压工具链至系统目录:
sudotar-xvfgcc-arm-11.2-2022.02-x86_64-arm-none-linux-gnueabihf.tar.xz-C/opt编辑环境变量文件,追加工具链路径:
vim~/.bashrc文件末尾追加:
exportPATH=$PATH:/opt/gcc-arm-11.2-2022.02-x86_64-arm-none-linux-gnueabihf/bin生效环境变量:
source~/.bashrc6.2.3 依赖兼容处理
32 位工具链在 64 位系统运行时,需安装兼容依赖:
sudoapt-getinstallia32-libssudoapt-getinstalllibc6:i386sudoapt-getinstalllib32z16.2.4 工具链校验
arm-none-linux-gnueabihf-gcc-v6.3 交叉编译工具集使用
嵌入式 ARM 开发常用工具集包含gcc、readelf、objdump、size、nm、addr2line、objcopy、strings、strip,各工具的标准实操方式如下。
测试用例源码:
#include<stdlib.h>#include<stdio.h>intg_val=12;intg_uninit;constchar*str="who am I?";staticchars_uninit;intmain(){printf("hello world!\n");int*p=malloc(sizeof(int));staticints_tmp=0;free(p);return0;}6.3.1 gcc 编译工具
基础编译命令(带调试信息):
arm-none-linux-gnueabihf-gcc-gmain.c-omain编译后文件状态(未精简):带调试信息、未剥离符号。
filemain输出:
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 stripped6.3.2 readelf 文件信息查看工具
该工具用于读取并展示 ELF 可执行文件的文件头部、区段分布、符号表等底层信息。
查看文件头部信息:
arm-none-linux-gnueabihf-readelf-hmain查看所有区段头信息:
arm-none-linux-gnueabihf-readelf-Smain查看文件符号地址:
arm-none-linux-gnueabihf-readelf-smain6.3.3 objdump 反汇编工具
该工具用于完成文件反汇编操作,查看程序对应的汇编代码,多用于程序异常调试与代码逻辑分析。
arm-none-linux-gnueabihf-objdump-Dmain>main.txt6.3.4 size 段大小查看工具
该工具用于快速统计可执行文件中text、data、bss等区段的存储空间占用大小。
arm-none-linux-gnueabihf-size main6.3.5 nm 符号查看工具
该工具用于输出文件内所有全局变量、静态变量、自定义函数的符号信息及属性标识。
arm-none-linux-gnueabihf-nm main符号属性标识规则:小写字母代表局部符号,大写字母代表全局符号;T对应代码段、D对应初始化数据段、B对应未初始化 BSS 段、U对应未定义符号。
6.3.6 addr2line 源码溯源工具
该工具可通过程序内存地址反向匹配对应的源码文件与代码行号,是程序崩溃定位的常用工具。
arm-none-linux-gnueabihf-addr2line-emain-psfC0x104516.3.7 objcopy 文件格式转换工具
该工具可实现目标文件格式转换、自定义区段增减、调试信息分离等操作,常用命令如下:
# 转换为二进制裸机文件arm-none-linux-gnueabihf-objcopy-Obinary main main.bin# 分离调试信息arm-none-linux-gnueabihf-objcopy --only-keep-debug main main.debuginfo# 剔除调试信息arm-none-linux-gnueabihf-objcopy --strip-debug main main.stripdebug6.3.8 strings 字符串查看工具
该工具用于提取可执行文件中所有可打印字符串,可用于查看程序内置的常量文本内容。
arm-none-linux-gnueabihf-strings main6.3.9 交叉编译环境 strip 工具实操
ARM 交叉编译链内置的strip工具,可对嵌入式可执行文件进行精简处理,降低文件体积,减少设备 Flash 存储空间占用:
# 精简 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 工具链解压与目录结构
执行解压命令释放工具链文件:
tar-xvfgcc-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 └── share6.4.6 工具链功能测试
编写基础 HelloWorld 测试源码,完成交叉编译验证工具链可用性。x86_64 主机无法直接运行 aarch64 架构可执行文件,可通过file命令校验文件架构信息。
使用nm工具可正常读取编译后可执行文件的符号表信息,输出结果包含程序全局符号、局部符号、未定义库符号等完整数据,证明工具链运行正常。
$ /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 嵌入式平台开发,基础配置模板如下:
# 设置编译器和链接器路径 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
