【发布时间】:2020-06-29 16:12:54
【问题描述】:
我正在尝试制作一个极简的 stm32f215 固件,以自学其启动的复杂性。现在我有了这个转储,据我所知,它应该将堆栈地址写入 r0 并永远循环:
firmware-d: file format elf32-littlearm
Disassembly of section .isr_vector:
08000000 <vector>:
8000000: 20002000 andcs r2, r0, r0
8000004: 08000009 stmdaeq r0, {r0, r3}
08000008 <reset_handler>:
8000008: f85f 00c ldr.w r0, [pc, #-12] ; 8000000 <vector>
0800000c <loop>:
800000c: e7fe b.n 800000c <loop>
但是当我调试它时,我最终得到 PC = 0xFFFFFFFF,LR = 0x20002000,R0 = 0x0 和 SP = 0x0。 而且,CFSR 中也没有任何内容暗示出了什么问题……
这里有经验丰富的编码员吗?
(PS:硬件启动管脚设置为别名0x0到0x800 0000)
编辑:我刚刚意识到 CPSR 设置了溢出标志。但仍然不知道为什么。
编辑2:
- 我发现的所有信息都表明,cortex-m3 只能执行 thumb,如果被告知执行 arm,则会出现硬故障。
- 我知道从长远来看,将我的代码放在 isr_vector 中是个坏主意。我试过用地址填充它以“循环”,但它没有改变。我有这个代码作为一个最小的例子。
- “有断点...” 到目前为止,我无法让它在任何断点处停止。唯一有效的是“starti”,它会在分支到“reset_handler”之前停止它。从那里“stepi”让我直接进入所描述的状态。
- 这是 elf 文件的转储,因为它看起来比 GDB 的输出更漂亮。我已验证该数据存在于芯片上的 0x0 和 0x800 0000 中。
- 卡中的数据、新闪存和“starti”:
(gdb) info registers
r0 0x0 0
r1 0x0 0
r2 0x6d8d1d05 1837964549
r3 0x7fbf 32703
r4 0x8000008 134217736
r5 0x8000008 134217736
r6 0x8000008 134217736
r7 0x8000008 134217736
r8 0x8000008 134217736
r9 0x8000008 134217736
r10 0x8000008 134217736
r11 0x8000008 134217736
r12 0x8000008 134217736
sp 0x8000008 0x8000008
lr 0x8000008 134217736
pc 0x8000008 0x8000008
cpsr 0x8000008 134217736
(gdb) disassemble /r 0x0,0x10
Dump of assembler code from 0x0 to 0x10:
0x00000000: 00 20 movs r0, #0
0x00000002: 00 20 movs r0, #0
0x00000004: 09 00 movs r1, r1
0x00000006: 00 08 lsrs r0, r0, #32
0x00000008: 00 48 ldr r0, [pc, #0] ; (0xc)
0x0000000a: fe e7 b.n 0xa
0x0000000c: 68 46 mov r0, sp
(如您所见,0xc 中的值当前是死代码。)
(gdb) disassemble /r 0x8000000,0x8000010
Dump of assembler code from 0x8000000 to 0x8000010:
0x08000000 <vector+0>: 00 20 movs r0, #0
0x08000002 <vector+2>: 00 20 movs r0, #0
0x08000004 <vector+4>: 09 00 movs r1, r1
0x08000006 <vector+6>: 00 08 lsrs r0, r0, #32
=> 0x08000008: 00 48 ldr r0, [pc, #0] ; (0x800000c <reset_handler_c>)
0x0800000a: fe e7 b.n 0x800000a
0x0800000c <reset_handler_c+0>: 68 46 mov r0, sp
- 该板是基于 stm32f215 的定制板。我使用 st-link (v2) 通过https://github.com/stlink-org/stlink 进行闪烁和调试。 用已知的好代码刷新它适用于这个解决方案,但我不确定调试器是否完全正常工作。
- 两个引导引脚均通过 1kOhm 电阻器直接接地。
- 稍微更改代码以直接分支到循环后,我可以得出结论,无论首先是什么汇编指令,它都会锁定。返回循环的分支导致了同样的错误。
- CFSR 和 HFSR:
(gdb) print/x *(uint32_t *) 0xE000ED28
$1 = 0x0
(gdb) print/x *(uint32_t *) 0xE000ED2C
$2 = 0x0
- 我几乎可以保证我使用的 stlink 应用程序混淆了 sp 和 lr。一个已知的好程序没有 sp=0x8f0d180 和 lr=0x2001ff88。明天会考虑改用 openocd。
【问题讨论】:
-
这里的硬件不熟悉,但我知道ARM。如果您的 ISR 登陆
,那么它正在执行数据而不是代码。几乎 100% 确定这两个操作码是堆栈地址 (0x20002000) 和入口点 (0x08000009)。请注意,地址是奇数,因此系统采用“Thumb”指令。仔细检查这是否是您想要的。我会假设 ARM 在启动时,所以这对我来说很奇怪。 infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.faqs/… -
重新阅读 - 引导至
0x800 0000的别名几乎可以肯定意味着您正在执行“池”而不是从重置处理程序开始。这也意味着您可能在执行第二条指令时抛出异常,因为 R0 几乎可以肯定是垃圾。要么将第一条指令作为的分支,将引导引脚别名为 ,要么将池从入口点移开。 -
“但是当我调试它时,我最终......” - 但是它在之前做了什么?在
reset_handler有一个断点,它甚至会停在那里吗?无论如何,将代码放在向量表中可能不是一个好主意。如果发生 NMI 或硬故障异常,它会将您的代码解释为向量并跳转到无效地址。你的reset_handler应该位于向量表的上方。 -
我宁愿看到它在FLASH中而不是在文件中。
-
@P__J__ : 发布的代码是反汇编而不是源文件,所以它大概是闪存中的内容。