Linux系统之objcopy 命令详解
objcopy 是 GNU Binutils 工具集的核心组件,用于复制目标文件(object file)并对其进行格式转换、内容修改或符号/段(section)操作。它基于 GNU BFD(Binary File Descriptor)库工作,支持几乎所有主流目标文件格式(如 ELF、PE、COFF、srec、raw binary 等),可实现“跨格式复制”“符号剥离”“段提取/添加”“内存布局调整”等核心功能,是嵌入式开发、二进制分析、调试信息管理的关键工具。
核心价值:
- 格式转换:将目标文件在不同格式间转换(如 ELF 转 raw binary、PE 转 srec);
- 内容精简:剥离符号、调试信息或无用段,减小二进制体积;
- 段/符号定制:添加/删除/重命名段、修改符号属性(如全局/局部、弱符号);
- 内存布局调整:修改段的加载地址(LMA)、运行地址(VMA),填充间隙或对齐内存。
核心概念铺垫
在理解选项前,需先明确目标文件的关键概念(objcopy 操作的核心对象):
| 概念 | 说明 |
|---|---|
| BFD 格式 | BFD 库定义的统一目标文件格式标识(如 elf64-x86-64、pe-i386、srec、binary),objcopy 通过 -I/-O 指定输入/输出格式。 |
| 段(Section) | 目标文件的基本数据单元,按功能分类(如 .text 代码段、.data 已初始化数据段、.bss 未初始化数据段、.debug_info 调试段),每个段有独立的地址(VMA/LMA)和属性(可读/可写/可执行)。 |
| VMA/LMA | - VMA(Virtual Memory Address):程序运行时段的内存地址; - LMA(Load Memory Address):程序加载时段的内存地址(嵌入式中常与 VMA 不同,如 ROM 加载、RAM 运行)。 |
| 符号(Symbol) | 程序中变量、函数的标识,包含名称、类型(全局/局部/弱符号)、地址等信息,objcopy 可剥离、保留或重命名符号。 |
| Raw Binary | 无格式的原始二进制文件(仅包含段数据,无符号/重定位信息),常用于嵌入式 ROM 烧录。 |
| S-record | 文本格式的二进制镜像(以 S 开头的记录行),便于串口传输或文本编辑,常用于嵌入式程序下载。 |
命令格式
objcopy [选项]... infile [outfile]
infile:必选,输入目标文件(如.o、.so、可执行文件、归档文件.a)。outfile:可选,输出目标文件路径。若省略,objcopy会创建临时文件,最终覆盖infile(谨慎使用,避免数据丢失)。- 选项:控制格式转换、段/符号操作、地址调整等(按功能分类详解见下文)。
选项详解(按功能分类)
objcopy 选项繁多(超 100 个),以下仅聚焦常用且核心的选项,按功能分组便于理解和使用:
1. 格式控制选项(核心:指定输入/输出格式)
控制输入/输出文件的 BFD 格式,是跨格式转换的基础。
| 选项 | 全称 | 说明 | 示例 |
|---|---|---|---|
-I bfdname |
--input-target=bfdname |
强制指定输入文件格式(不自动推导),bfdname 为 BFD 格式标识。 |
objcopy -I elf32-arm -O binary app.elf app.bin(输入为 ARM 32 位 ELF) |
-O bfdname |
--output-target=bfdname |
强制指定输出文件格式,常用格式: - binary:原始二进制(无符号/段信息);- srec:S-record 格式;- elf64-x86-64:64 位 x86 ELF;- pe-i386:32 位 PE 格式。 |
objcopy -O srec app.elf app.srec(ELF 转 S-record) |
-F bfdname |
--target=bfdname |
输入/输出格式均为 bfdname(无格式转换,仅复制内容)。 |
objcopy -F elf32-arm app.elf app_copy.elf(复制 ELF 文件,格式不变) |
-B bfdarch |
--binary-architecture=bfdarch |
为“无架构的输入文件”(如 raw binary)指定输出架构(如 arm、x86_64),生成可链接的目标文件。 |
objcopy -I binary -O elf32-arm -B arm img.png img.o(图片转 ARM ELF 目标文件) |
2. 段(Section)操作选项(核心:增删改查段)
段是目标文件的核心数据单元,objcopy 可灵活控制段的保留、删除、添加或修改。
| 选项 | 全称 | 说明 | 示例 |
|---|---|---|---|
-j sectionpattern |
--only-section=sectionpattern |
仅保留匹配 sectionpattern 的段(支持通配符 */?),其他段丢弃。多次使用可保留多个段。 |
objcopy -j .text -j .data -O binary app.elf app.bin(仅保留代码段和数据段,转 binary) |
-R sectionpattern |
--remove-section=sectionpattern |
删除匹配 sectionpattern 的段(支持通配符),多次使用可删除多个段。 |
objcopy -R .debug_info -R .debug_line app.elf app_stripped.elf(删除调试段) |
--add-section sectionname=filename |
- | 添加新段 sectionname,段内容从 filename 读取(需配合 --set-section-flags 设置段属性)。 |
objcopy --add-section .logo=logo.png --set-section-flags .logo=alloc,load,readonly app.elf app_with_logo.elf(添加图片为只读段) |
--dump-section sectionname=filename |
- | 提取段 sectionname 的内容到 filename(原始二进制,不处理重定位),与 --add-section 互为逆操作。 |
objcopy --dump-section .text=app_text.bin app.elf(提取代码段到文件) |
--rename-section oldname=newname[,flags] |
- | 将段 oldname 重命名为 newname,可选修改段 flags(如 alloc/readonly)。 |
objcopy -I binary -O elf32-arm -B arm --rename-section .data=.rodata,alloc,load,readonly img.bin img.o(二进制转 ELF 时,将 .data 重命名为只读段 .rodata) |
--gap-fill val |
- | 用 val(十六进制或十进制,如 0xff)填充段之间的内存间隙(基于 LMA 地址)。 |
objcopy --gap-fill 0xff --pad-to 0x10000 app.elf app_padded.elf(间隙填充 0xff,填充到地址 0x10000) |
--pad-to address |
- | 将输出文件填充到 address 地址(增大最后一个段的大小),填充内容由 --gap-fill 指定(默认 0)。 |
同上,填充到 0x10000 地址,确保二进制大小足够烧录到 ROM。 |
3. 符号操作选项(核心:剥离、保留、修改符号)
符号控制用于精简二进制或解决符号冲突,常用於调试或发布版本的优化。
| 选项 | 全称 | 说明 | 示例 |
|---|---|---|---|
-S |
--strip-all |
剥离所有符号和重定位信息(最彻底的精简,仅保留段数据)。 | objcopy -S app.elf app_stripped.elf(精简二进制,无法调试) |
-g |
--strip-debug |
仅剥离调试符号和调试段(保留普通符号,不影响链接或基本调试)。 | objcopy -g app.elf app_no_debug.elf(移除调试信息,体积减小但可链接) |
-K symbolname |
--keep-symbol=symbolname |
剥离符号时保留指定符号(多次使用可保留多个)。 | objcopy -S -K main -K printf app.elf app_keep_main.elf(剥离所有符号,仅保留 main 和 printf) |
-N symbolname |
--strip-symbol=symbolname |
剥离指定符号(多次使用可剥离多个,支持通配符,需配合 -w)。 |
objcopy -w -N "temp_*" app.elf app_no_temp.elf(剥离所有以 temp_ 开头的符号) |
--redefine-sym old=new |
- | 将符号 old 重命名为 new,解决符号冲突(如链接两个同名函数)。 |
objcopy --redefine-sym func=func_old libold.so libold_renamed.so(将 func 重命名为 func_old,避免与新库冲突) |
-G symbolname |
--keep-global-symbol=symbolname |
仅保留 symbolname 为全局符号,其他符号设为局部(隐藏外部可见性)。 |
objcopy -G main app.elf app_only_main_global.elf(仅 main 全局可见,其他符号局部) |
-W symbolname |
--weaken-symbol=symbolname |
将符号 symbolname 设为弱符号(链接时若有强符号则优先使用弱符号)。 |
objcopy -W func app.elf app_weak_func.elf(func 设为弱符号,可被其他强符号覆盖) |
4. 地址与内存布局选项(核心:调整段地址或起始地址)
常用于嵌入式开发中,调整段的加载/运行地址以匹配硬件内存布局。
| 选项 | 全称 | 说明 | 示例 |
|---|---|---|---|
--change-addresses incr |
--adjust-vma incr |
所有段的 VMA/LMA 地址及程序起始地址增加 incr(单位:字节,支持正负值)。 |
objcopy --change-addresses 0x1000 app.elf app_relocated.elf(所有地址 +0x1000,适配内存偏移) |
--change-section-vma sectionpattern{=,+,-}val |
- | 仅调整匹配段的 VMA 地址(= 设为 val,+/- 增减 val)。 |
objcopy --change-section-vma .text=0x8000000 app.elf app_text_8m.elf(将 .text 段 VMA 设为 0x8000000) |
--change-section-lma sectionpattern{=,+,-}val |
- | 仅调整匹配段的 LMA 地址(加载地址,常用于 ROM 加载、RAM 运行场景)。 | objcopy --change-section-lma .data=0x10000000 app.elf app_data_lma.elf(.data 加载到 0x10000000,运行在原 VMA) |
--set-start val |
- | 设置程序的起始地址(仅部分格式支持,如 ELF、PE)。 | objcopy --set-start 0x8000000 app.elf app_start_8m.elf(程序入口地址设为 0x8000000) |
5. 调试信息管理选项(核心:分离或压缩调试信息)
调试信息通常占二进制体积的 50% 以上,objcopy 可将其分离为独立文件,兼顾“精简发布版”和“完整调试能力”。
| 选项 | 全称 | 说明 | 示例(分离调试信息完整流程) |
|---|---|---|---|
--only-keep-debug |
- | 剥离所有非调试内容,仅保留调试段和符号(生成纯调试文件)。 | 1. 生成调试文件:objcopy --only-keep-debug app.elf app.dbg |
--add-gnu-debuglink=path |
- | 为目标文件添加 .gnu_debuglink 段,指向独立调试文件 path(调试器可自动关联)。 |
2. 剥离原文件调试信息:objcopy --strip-debug app.elf 3. 关联调试文件: objcopy --add-gnu-debuglink=app.dbg app.elf |
--compress-debug-sections |
- | 用 zlib 压缩 DWARF 调试段(减小调试文件体积)。 | objcopy --compress-debug-sections app.dbg app_compressed.dbg |
--strip-dwo |
- | 剥离 DWARF .dwo 段(用于 -gsplit-dwarf 拆分调试信息的场景,保留主调试段)。 |
objcopy --strip-dwo app.o app_stripped_dwo.o |
6. 特殊格式选项(针对 srec、binary、PE 等)
针对特定格式的专属功能,满足嵌入式或 Windows 平台的需求。
| 选项 | 全称 | 说明 | 示例 |
|---|---|---|---|
--srec-len=ival |
- | 生成 S-record 时,设置每条记录的最大长度(含地址、数据、CRC)。 | objcopy -O srec --srec-len 32 app.elf app.srec(S-record 每条记录最长 32 字节) |
--srec-forceS3 |
- | 生成 S-record 时,仅生成 S3 记录(32 位地址,不生成 S1/S2 记录)。 | objcopy -O srec --srec-forceS3 app.elf app_s3.srec |
--image-base=addr |
- | 针对 PE 格式,设置程序/DLL 的基地址(默认:可执行文件 0x400000,DLL 0x10000000)。 | objcopy --image-base 0x20000000 app.exe app_base_20m.exe |
--stack reserve[,commit] |
- | 针对 PE 格式,设置栈大小(reserve 保留大小,commit 初始提交大小)。 |
objcopy --stack 0x100000,0x10000 app.exe app_stack.exe(栈保留 1MB,初始提交 64KB) |
--reverse-bytes=num |
- | 按 num 字节一组反转段内容(解决嵌入式硬件字节序不匹配问题)。 |
objcopy --reverse-bytes=4 app.elf app_rev4.elf(4 字节一组反转,如 0x12345678 → 0x78563412) |
关键功能场景与示例
objcopy 的用法需结合实际场景,以下是最常用的 5 类场景及完整命令:
1. 生成嵌入式 ROM 用的 Raw Binary 文件
将 ELF 可执行文件转换为无格式二进制(仅保留代码和数据段),用于烧录到 ROM 或 Flash:
# 仅保留 .text(代码)、.data(已初始化数据)段,转 raw binary,填充间隙为 0xff
objcopy -j .text -j .data -O binary --gap-fill 0xff app.elf app.bin
2. 分离调试信息(精简发布版 + 独立调试文件)
发布时用精简二进制(无调试信息),调试时关联独立调试文件,兼顾体积和调试能力:
# 1. 生成纯调试文件(仅保留调试信息)
objcopy --only-keep-debug app.elf app.dbg
# 2. 剥离原文件的调试信息(体积减小)
objcopy --strip-debug app.elf
# 3. 为原文件添加调试链接(调试器可自动找到 app.dbg)
objcopy --add-gnu-debuglink=app.dbg app.elf
# 调试时,GDB 会自动关联 app.dbg:gdb ./app.elf
3. 将外部文件添加为目标文件的段(如嵌入式图片/配置)
将图片、配置文件等作为只读段添加到 ELF 中,程序可通过符号访问该段的地址和大小:
# 将 logo.png 作为 .logo 段添加到 app.elf,设置段属性为“可分配、可加载、只读”
objcopy --add-section .logo=logo.png --set-section-flags .logo=alloc,load,readonly app.elf app_with_logo.elf
# 程序中通过以下符号访问 .logo 段(BFD 自动生成):
# - _binary_logo_png_start:段起始地址
# - _binary_logo_png_end:段结束地址
# - _binary_logo_png_size:段大小
4. 生成 S-record 格式文件(嵌入式串口下载)
将 ELF 转换为 S-record 文本格式,便于通过串口传输到嵌入式设备:
# 转 S-record,每条记录最长 64 字节,仅生成 S3 记录(32 位地址)
objcopy -O srec --srec-len 64 --srec-forceS3 app.elf app.srec
5. 调整段地址(适配嵌入式内存布局)
将 .text 段加载到 0x8000000(ROM),运行时映射到 0x20000000(RAM),.data 段加载到 0x8010000 并复制到 0x20010000:
# .text 段:LMA=0x8000000(加载到 ROM),VMA=0x20000000(运行在 RAM)
# .data 段:LMA=0x8010000(加载到 ROM),VMA=0x20010000(运行在 RAM)
objcopy --change-section-lma .text=0x8000000 --change-section-vma .text=0x20000000 \
--change-section-lma .data=0x8010000 --change-section-vma .data=0x20010000 \
app.elf app_rom_ram.elf
注意事项
- 字节序限制:
objcopy无法直接修改目标文件的字节序(如大端转小端),仅能通过--reverse-bytes=num按字节组反转(需手动计算分组大小)。 - Relocatable 文件转换风险:跨格式复制“可重定位目标文件”(
.o)可能导致重定位信息失效,仅建议对“已链接的可执行文件”进行跨格式转换。 - 选项冲突:
-j(仅保留段)和-R(删除段)不可同时使用,行为未定义;--strip-all会覆盖-K(保留符号)的效果(需先保留符号再剥离)。 - PE 格式特殊性:
--image-base、--stack、--subsystem等选项仅对 PE 格式有效,其他格式会忽略这些选项。 - 调试链接路径:
--add-gnu-debuglink仅记录调试文件的文件名(非绝对路径),调试时需确保调试文件在 GDB 搜索路径中(如与可执行文件同目录、/usr/lib/debug)。
更多推荐



所有评论(0)