我应该在固件中填充多少异常向量?

How much exception vectors should I fill in the firmware?

我正在使用 STM32F103C8T6 Blue Pill 开发板玩 ARM。根据它的 Programming Manual (Section 2.3.4 Vector Table), there are a total of 83 exception vectors to be set. However, this tutorial only fills the first 6 and this tutorial 前 10 个。奇怪的是,尽管没有很多异常处理程序,但我可以验证两个固件都按预期执行。

澄清一下,下面是我所指的部分 (link to original file)。如您所见,只有前几个单词被分配了一个处理程序,所有后续的 space 都用于保存 .text 部分。

.section .isr_vector
.align  2
.global _isr_vector
_isr_vector:
    .long   __StackTop /* we will need this later */
    .long   Reset_Handler
    .long   Default_Handler
    .long   Default_Handler
    .long   Default_Handler
    .long   Default_Handler
    .long   Default_Handler
    .long   0
    .long   0
    .long   0
    .long   0
    .long   Default_Handler
    .long   Default_Handler
    .long   0
    .long   Default_Handler
    .long   Default_Handler

这让我很困惑:我需要填充的异常处理程序的最少数量是多少?在我的用例中(只不过是一个玩具项目),没有例外,所以我可以只设置 Reset Handler 吗?

作为奖励,编程手册指定 "The least-significant bit of each vector must be 1, indicating that the exception handler is Thumb code." 但是,上面的代码显然不遵循此约定,那么它如何在启动时正确调用重置处理程序?

理论上只能设置两个。初始堆栈和重置处理程序。如果您不调用任何中断(并且您的程序不会以硬故障结束,则您不必设置任何

.thumb
.global _start
_start:
.word 0x20001000
.word one
.word two
.align
.thumb_func
one:
    b .
two:
    b .

arm-none-eabi-as so.s -o so.o
arm-none-eabi-ld -Ttext=0x08000000 so.o -o so.elf
arm-none-eabi-objdump -D so.elf

so.elf:     file format elf32-littlearm


Disassembly of section .text:

08000000 <_start>:
 8000000:   20001000    andcs   r1, r0, r0
 8000004:   0800000d    stmdaeq r0, {r0, r2, r3}
 8000008:   0800000e    stmdaeq r0, {r1, r2, r3}
    
0800000c <one>:
 800000c:   e7fe        b.n 800000c <one>

0800000e <two>:
 800000e:   e7fe        b.n 800000e <two>

首先,_start 不是必需的,你会得到一个警告,把它放在那里更容易。

您需要将标签声明为一个函数,在 gnu 汇编器中有几种方法可以做到这一点。 .thumb_func 很容易,它不必是在 .thumb_func 和标签之间可以有其他内容之前的那一行,但下一个标签标记为函数。

你会看到编译器的输出做这样的事情(使用 -save-temps 或 -S 查看编译器输出),还有另一种在 gas 中声明函数的方法,对于全尺寸的 arm 有您必须使用一个不同的。

您可以看到,当正确声明时,工具会照顾您和 orr 向量中地址的 lsbit table 当您没有正确声明它时,您会在向量中得到错误的地址 table 这是行不通的。

正如所回答的那样,最少只有两个条目,因为您需要在 offset/address 4. 请注意,在这些 STM32 平台上启动时,0x08000000 映射到 0x00000000。如果您不需要任何其他向量,则最小值是重置向量,但处于偏移量时您需要填充前四个字节。不妨将堆栈指针初始值放在那里,然后用相同的代码设置它。

矢量 table 并没有什么神奇之处,它只是一个地址 space 你可以进行提取和数据循环。

两个是最小值,但如果你最终遇到对齐错误或其他错误,那么它会尝试在那里找到一个向量,如果是偶数,那么这是一个问题,如果是奇数,那么尝试从该地址(lsbit 被剥离了 pc 中没有奇数,它只是一种指示拇指与手臂的机制)。因此,虽然从技术上讲是一个向量,但重置是最小值,为了以防万一,覆盖前 16 (15) 个可能是个好主意。

.thumb
.global _start
_start:

.word 0x20001000
.word reset
.word loop
.word loop

.word loop
.word loop
.word loop
.word loop

.word loop
.word loop
.word loop
.word loop

.word loop
.word loop
.word loop
.word loop

.thumb_func
reset:
    b .

.thumb_func
loop:
    b .

虽然您可以混合代码和向量,但如果您最终使用外围设备的中断处理程序,那么您可能不希望在异常之间和中断处理程序向量所在的位置混淆代码。如果你真的很想在 Flash 中获取代码 space,那么从技术上讲你可以...

至少 P__J__ 的答案是答案。我添加了这个答案来涵盖 lsbit 问题。