【发布时间】:2021-03-21 00:04:01
【问题描述】:
我正在为 ARM Cortex-M0 微控制器(特别是 STM32F072B 作为 STM32 Discovery 开发板的一部分)编写一些固件代码。
我的链接器脚本没有做任何特别的事情,它只是填写向量表,然后包含我代码中的所有文本和数据部分:
OUTPUT_FORMAT("elf32-littlearm")
MEMORY {
ROM (rx) : ORIGIN = 0x00000000, LENGTH = 16K
FLASH (r) : ORIGIN = 0x08000000, LENGTH = 64K
RAM (rw) : ORIGIN = 0x20000000, LENGTH = 16K
}
ENTRY(_start)
PROVIDE(__stack_top = ORIGIN(RAM) + LENGTH(RAM));
SECTIONS {
.vector_table : {
LONG(__stack_top); /* 00 */
LONG(_start); /* 04 */
LONG(dummy_isr); /* 08 */
LONG(dummy_isr); /* 0C */
LONG(dummy_isr); /* 10 */
LONG(dummy_isr); /* 14 */
LONG(dummy_isr); /* 18 */
LONG(dummy_isr); /* 1C */
LONG(dummy_isr); /* 20 */
LONG(dummy_isr); /* 24 */
LONG(dummy_isr); /* 28 */
LONG(dummy_isr); /* 2C */
LONG(dummy_isr); /* 30 */
LONG(dummy_isr); /* 34 */
LONG(dummy_isr); /* 38 */
LONG(dummy_isr); /* 3C */
LONG(dummy_isr); /* 40 */
LONG(dummy_isr); /* 44 */
LONG(dummy_isr); /* 48 */
LONG(dummy_isr); /* 4C */
LONG(dummy_isr); /* 50 */
LONG(dummy_isr); /* 54 */
LONG(dummy_isr); /* 58 */
LONG(dummy_isr); /* 5C */
LONG(dummy_isr); /* 60 */
LONG(dummy_isr); /* 64 */
LONG(dummy_isr); /* 68 */
LONG(dummy_isr); /* 6C */
LONG(dummy_isr); /* 70 */
LONG(dummy_isr); /* 74 */
LONG(dummy_isr); /* 78 */
LONG(dummy_isr); /* 7C */
LONG(dummy_isr); /* 80 */
LONG(dummy_isr); /* 84 */
LONG(dummy_isr); /* 88 */
LONG(dummy_isr); /* 8C */
LONG(dummy_isr); /* 90 */
LONG(dummy_isr); /* 94 */
LONG(dummy_isr); /* 98 */
LONG(dummy_isr); /* 9C */
LONG(dummy_isr); /* A0 */
LONG(dummy_isr); /* A4 */
LONG(dummy_isr); /* A8 */
LONG(dummy_isr); /* AC */
LONG(dummy_isr); /* B0 */
LONG(dummy_isr); /* B4 */
LONG(dummy_isr); /* B8 */
LONG(dummy_isr); /* BC */
} > ROM AT > FLASH
.text : {
*(.text*)
} > ROM AT > FLASH
.rodata : {
*(.rodata*)
*(.data.rel.ro)
} > FLASH
.bss (NOLOAD) : {
*(.bss*)
*(COMMON)
} > RAM
.data : {
*(.data*)
} > RAM
.ARM.exidx : {
*(.ARM.exidx)
} > FLASH
}
当我构建和链接一个 ELF 文件并转储符号时,我注意到以 .vector_table 部分结尾的地址以及 ELF 入口点都偏移了一个:
[shell]$ llvm-objdump --syms zig-cache/bin/main-flash
zig-cache/bin/main-flash: file format elf32-littlearm
SYMBOL TABLE:
00000000 l df *ABS* 00000000 main-flash
0000013c l .text 00000000 $d.1
000000c0 l .text 00000000 $t.0
000000c4 g F .text 00000088 _start
000000c0 g F .text 00000002 dummy_isr
20004000 g *ABS* 00000000 __stack_top
[shell]$ llvm-objdump --full-contents --section=.vector_table zig-cache/bin/main-flash
zig-cache/bin/main-flash: file format elf32-littlearm
Contents of section .vector_table:
0000 00400020 c5000000 c1000000 c1000000 .@. ............
0010 c1000000 c1000000 c1000000 c1000000 ................
0020 c1000000 c1000000 c1000000 c1000000 ................
0030 c1000000 c1000000 c1000000 c1000000 ................
0040 c1000000 c1000000 c1000000 c1000000 ................
0050 c1000000 c1000000 c1000000 c1000000 ................
0060 c1000000 c1000000 c1000000 c1000000 ................
0070 c1000000 c1000000 c1000000 c1000000 ................
0080 c1000000 c1000000 c1000000 c1000000 ................
0090 c1000000 c1000000 c1000000 c1000000 ................
00a0 c1000000 c1000000 c1000000 c1000000 ................
00b0 c1000000 c1000000 c1000000 c1000000 ................
[shell]$ readelf -h zig-cache/bin/main-flash
ELF Header:
...
Entry point address: 0xc5
符号表在 0xC4 处显示 _start,而在链接描述文件中定义为 _start 的 ELF 入口点设置为 0xC5。同样,写入向量表的dummy_isr的地址也是非一(dummy_isr符号定义为0xC0,而0xC1被链接器写入向量表)。 .text的反汇编确认_dummy_isr和_start分别从0xC0和0xC4开始,所以链接器写的地址是错误的:
[shell]$ llvm-objdump --disassemble --section=.text zig-cache/bin/main-flash
zig-cache/bin/main-flash: file format elf32-littlearm
Disassembly of section .text:
000000c0 <dummy_isr>:
c0: fe e7 b #-4 <dummy_isr>
c2: c0 46 mov r8, r8
000000c4 <_start>:
c4: 82 b0 sub sp, #8
c6: 01 23 movs r3, #1
c8: d8 04 lsls r0, r3, #19
ca: 1c 49 ldr r1, [pc, #112]
...
0xC1 和 0xC5 甚至不是有效指令的地址,它们都在一条指令的中间。什么可能导致这种差异?
【问题讨论】:
-
查看 arm 文档,向量需要在处理程序地址或与一个。 (lsbit set,表示这是thumb函数)
-
如果没有设置 lsbit 那么你会得到一个错误
-
"所有其他条目必须将 bit[0] 设置为 1,因为该位定义了异常条目上的 EPSR.T 位。"
-
"在异常入口时,如果关联向量表入口的位 [0] 为 0,则执行第一条指令会导致 HardFault。"