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 默认可执行文件的符号表、行号及冗余调试信息:

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 开发最佳实践

为同时满足程序调试与版本发布的使用需求,可采用双文件保留方案:

  1. 保留未 strip 原始文件:用于线上问题定位、addr2line 源码溯源、程序调试。
  2. 使用 strip 精简后文件:用于设备部署、版本发布,减小存储占用。

5.3 常见问题说明

  • 执行 strip 后文件体积无变化,表明当前文件已完成精简,不存在可剔除的冗余信息。
  • 经过 strip 处理的文件会移除全部调试符号,无法使用 dbxaddr2line 等工具完成程序调试与溯源工作。
  • strip 默认操作会清除文件的 .symbol 符号段与 .debug 调试段,未完成定型测试的程序不建议执行该操作。

六、ARM 交叉编译工具链及配套工具使用

6.1 交叉编译概述

交叉编译用于适配编译环境与程序运行环境不匹配的开发场景,典型场景为在 x86 架构设备上完成程序编译,生成可在 ARM 架构硬件设备上运行的可执行文件,是嵌入式开发的常用编译方式。

6.2 交叉编译链安装配置

6.2.1 工具链下载地址
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 开发常用工具集包含 gccreadelfobjdumpsizenmaddr2lineobjcopystringsstrip,各工具的标准实操方式如下。

测试用例源码

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 段大小查看工具

该工具用于快速统计可执行文件中 textdatabss 等区段的存储空间占用大小。

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 可与 gccreadelfobjdump 等工具配合使用。标准化的编译、调试、精简流程,可同时适配程序开发调试需求与设备部署的轻量化需求,是嵌入式产品量产发布的常用操作。


Reference