objcopy 是 GNU二进制工具集(binutils)的一部分,主要用于复制和转换目标文件。
在ARM GCC中,arm-none-eabi-objcopy
通常用于从链接后的ELF格式文件中提取出二进制文件或其他格式的内容,这对于嵌入式开发特别有用,因为这样的文件可以直接烧写到微控制器的闪存中。
下面是一些常用的参数:
-O
:表示输出文件的格式。常见的格式有:binary(二进制文件)、ihex(Intel HEX文件)、srec(Motorola SREC文件)、elf32-littlearm(小端字节序的ELF文件)等;
-S
(或 --strip-all
):去除所有的符号信息和重定位信息,使得输出文件更小;
-j
:仅复制指定的section。例如,-j .text
表示只复制.text段的内容;
-R
(或--remove-section
),输出文件中不要重定位信息和符号信息,缩小了文件尺寸。
下面是一个使用示例:
arm-none-eabi-objcopy -O binary -S -j .text -j .data myprogram.elf myprogram.bin
这行命令的意思是:从myprogram.elf
中提取出.text
段和.data
段的内容,并将它们转换为二进制文件myprogram.bin
。同时,所有的符号信息和重定位信息都会被去除。
注意:在使用arm-none-eabi-objcopy
时,你应当确保输入的ELF
文件已经正确链接。否则,你可能会得到一个无法在硬件上运行的二进制文件,此外,使用objcopy不能够改变大/小端。
$ arm-linux-objcopy -O binary -R .note -R .comment -S boot.elf boot.bin
GCC objdump
用于显示关于目标文件的信息。这些信息包括文件的头部信息、节区内容、符号表、重定位入口点等。使用 objdump
可以对二进制文件进行深入分析,这对于调试和理解程序的工作原理非常有用。
Objdump 支持大量的命令行选项,可以用来控制显示的信息的数量和类型。以下是一些主要的选项:
-a, --archive-header
: 显示存档的头部信息;
-d, --disassemble
: 反汇编代码段;
-h, --section-headers
: 显示节区头部;
-r, --reloc
: 显示重定位入口点;
-s, --full-contents
: 显示所有节区的完全内容;
-t, --syms
: 显示符号表。
一个简单的使用例子如下,假设我们编译出一个名为 soc.o 的 文件:
arm-none-eabi-objdump -h soc.o
soc.o: file format elf32-littlearm
Sections:
Idx Name Size VMA LMA File off Algn
0 .text 00000000 00000000 00000000 00000034 2**1
CONTENTS, ALLOC, LOAD, READONLY, CODE
1 .data 00000000 00000000 00000000 00000034 2**0
CONTENTS, ALLOC, LOAD, DATA
2 .bss 00000000 00000000 00000000 00000034 2**0
ALLOC
3 .text.__NVIC_SetPriority 00000054 00000000 00000000 00000034 2**2
CONTENTS, ALLOC, LOAD, READONLY, CODE
4 .text.SCB_EnableICache 0000004c 00000000 00000000 00000088 2**2
....
上面的命令显示了 soc 文件中各个节区的信息,包括名称、大小、虚拟地址、加载地址和文件偏移量等。
另一个例子是反汇编代码段:
arm-none-eabi-objdump -d soc.o
soc.o: file format elf32-littlearm
Disassembly of section .text.__NVIC_SetPriority:
00000000 <__NVIC_SetPriority>:
0: b480 push {r7}
2: b083 sub sp, #12
4: af00 add r7, sp, #0
6: 4603 mov r3, r0
8: 6039 str r1, [r7, #0]
a: 80fb strh r3, [r7, #6]
c: f9b7 3006 ldrsh.w r3, [r7, #6]
10: 2b00 cmp r3, #0
12: db0a blt.n 2a <__NVIC_SetPriority+0x2a>
14: 683b ldr r3, [r7, #0]
上面的命令显示了 soc 文件中.text. 段的反汇编代码。
readelf 是一个用于显示 ELF 格式文件信息的命令行工具, objdump 类似,readelf 也可以显示文件的头部信息、节区内容、符号表、重定位入口点等。但是,readelf 是专门针对 ELF 格式文件的工具,因此它可以显示更加详细的信息。
以下是一些主要的 readelf 选项:
-a, --all
: 显示所有信息;
-h, --file-header
: 显示 ELF 头部;
-l, --program-headers
, --segments: 显示程序头部或段;
-S, --section-headers
, --sections: 显示节区头部;
-s, --syms, --symbols
: 显示符号表;
-r, --relocs
: 显示重定位入口点。
一个简单的使用例子如下,假设我们有一个名为 soc.o 的文件:
arm-none-eabi-readelf -h soc.o
ELF Header:
Magic: 7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00
Class: ELF32
Data: 2's complement, little endian
Version: 1 (current)
OS/ABI: UNIX - System V
ABI Version: 0
Type: REL (Relocatable file)
Machine: ARM
Version: 0x1
Entry point address: 0x0
Start of program headers: 0 (bytes into file)
Start of section headers: 25652 (bytes into file)
Flags: 0x5000000, Version5 EABI
Size of this header: 52 (bytes)
Size of program headers: 0 (bytes)
Number of program headers: 0
Size of section headers: 40 (bytes)
Number of section headers: 61
Section header string table index: 60
上面的命令显示了 soc.o 文件的头部信息。
另一个例子是显示节区头部:
arm-none-eabi-readelf -S soc.o
There are 61 section headers, starting at offset 0x6434:
Section Headers:
[Nr] Name Type Addr Off Size ES Flg Lk Inf Al
[ 0] NULL 00000000 000000 000000 00 0 0 0
[ 1] .text PROGBITS 00000000 000034 000000 00 AX 0 0 2
[ 2] .data PROGBITS 00000000 000034 000000 00 WA 0 0 1
[ 3] .bss NOBITS 00000000 000034 000000 00 WA 0 0 1
[ 4] .text.__NVIC[...] PROGBITS 00000000 000034 000054 00 AX 0 0 4
[ 5] .text.SCB_En[...] PROGBITS 00000000 000088 00004c 00 AX 0 0 4
[ 6] .text.SCB_En[...] PROGBITS 00000000 0000d4 000088 00 AX 0 0 4
[ 7] .text.SysTic[...] PROGBITS 00000000 00015c 000044 00 AX 0 0 4
[ 8] .rel.text.Sy[...] REL 00000000 0047b8 000008 08 I 58 7 4
[ 9] .text.crg_key_en PROGBITS 00000000 0001a0 000028 00 AX 0 0 4
[10] .text.crg_key_dis PROGBITS 00000000 0001c8 000028 00 AX 0 0 4
[11] .text.unlock[...] PROGBITS 00000000 0001f0 000028 00 AX 0 0 4
[12] .text.lock_c[...] PROGBITS 00000000 000218 000024 00 AX 0 0 4
[13] .text.reboot PROGBITS 00000000 00023c 000030 00 AX 0 0 4
[14] .rodata.name PROGBITS 00000000 00026c 00001e 00 A 0 0 4
[15] FSymTab PROGBITS 00000000 00028c 00000c 00 A 0 0 4
[16] .relFSymTab REL 00000000 0047c0 000018 08 I 58 15 4
[17] .text.get_ref_clk PROGBITS 00000000 000298 000078 00 AX 0 0 4
上面的命令显示了 soc.o 文件中的节区头部信息。
nm
用于显示目标文件的符号表信息的命令行工具。符号表包含了程序中函数和变量的符号信息,这对于定位问题和理解程序的工作原理非常有用。
以下是一些主要的 nm 选项:
-a, --debug-syms
: 显示调试符号;
-g, --external-only
: 只显示外部符号;
-n, --numeric-sort
: 按照地址排序符号;
-r, --reverse-sort
: 反向排序符号;
-S, --print-size
: 显示符号的大小;
-u, --undefined-only
: 只显示未定义的符号。
一个简单的使用例子如下,假设我们有一个名为 soc.o 文件:
arm-none-eabi-nm -u soc.o
U __bss_end
U __bss_start
U clock_framework_init
U console_uart_init
U _edata
U enable_syscnt
U _estack
U _etext
U _heap_end
U _heap_start
U power_domain_framework_init
U reset_framework_init
U rt_components_board_init
U rt_console_set_device
U rt_hw_interrupt_init
U rt_interrupt_enter
U rt_interrupt_leave
U rt_kprintf
U rt_system_heap_init
U rt_tick_increase
U _sdata
U _sstack
U _stext
上面的命令只显示soc.o文件未定义的符号 。每行的输出包含了符号的类型和名字。类型是一个字符,指示了符号的类型和属性。