objcopyGNU Binutils 工具集的核心组件,用于复制目标文件(object file)并对其进行格式转换、内容修改或符号/段(section)操作。它基于 GNU BFD(Binary File Descriptor)库工作,支持几乎所有主流目标文件格式(如 ELF、PE、COFF、srec、raw binary 等),可实现“跨格式复制”“符号剥离”“段提取/添加”“内存布局调整”等核心功能,是嵌入式开发、二进制分析、调试信息管理的关键工具。

核心价值:

  1. 格式转换:将目标文件在不同格式间转换(如 ELF 转 raw binary、PE 转 srec);
  2. 内容精简:剥离符号、调试信息或无用段,减小二进制体积;
  3. 段/符号定制:添加/删除/重命名段、修改符号属性(如全局/局部、弱符号);
  4. 内存布局调整:修改段的加载地址(LMA)、运行地址(VMA),填充间隙或对齐内存。

核心概念铺垫

在理解选项前,需先明确目标文件的关键概念(objcopy 操作的核心对象):

概念 说明
BFD 格式 BFD 库定义的统一目标文件格式标识(如 elf64-x86-64pe-i386srecbinary),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)指定输出架构(如 armx86_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(剥离所有符号,仅保留 mainprintf
-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.elffunc 设为弱符号,可被其他强符号覆盖)
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

注意事项

  1. 字节序限制objcopy 无法直接修改目标文件的字节序(如大端转小端),仅能通过 --reverse-bytes=num 按字节组反转(需手动计算分组大小)。
  2. Relocatable 文件转换风险:跨格式复制“可重定位目标文件”(.o)可能导致重定位信息失效,仅建议对“已链接的可执行文件”进行跨格式转换。
  3. 选项冲突-j(仅保留段)和 -R(删除段)不可同时使用,行为未定义;--strip-all 会覆盖 -K(保留符号)的效果(需先保留符号再剥离)。
  4. PE 格式特殊性--image-base--stack--subsystem 等选项仅对 PE 格式有效,其他格式会忽略这些选项。
  5. 调试链接路径--add-gnu-debuglink 仅记录调试文件的文件名(非绝对路径),调试时需确保调试文件在 GDB 搜索路径中(如与可执行文件同目录、/usr/lib/debug)。
Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐