这是一个非常好的问题!isr_vector 必须放到最前面是由 ARM Cortex-M 处理器的硬件设计决定的。
硬件层面的原因:
1. Cortex-M 处理器的启动机制
-
ARM Cortex-M 处理器上电或复位后,硬件自动从特定地址读取向量表
-
第一个字(0x08000000):主堆栈指针(MSP)的初始值
-
第二个字(0x08000004):复位向量(Reset_Handler 的地址)
-
处理器用这两个值来初始化堆栈和程序计数器
2. 硬编码的地址
// 处理器复位后的硬编码行为:
uint32_t initial_sp = *(uint32_t*)0x00000000; // 从0x08000000读取堆栈指针
uint32_t reset_handler = *(uint32_t*)0x00000004; // 从0x08000004读取复位向量
SetSP(initial_sp); // 设置堆栈指针
JumpTo(reset_handler); // 跳转到复位处理程序
3. 如果 isr_vector 不在最前面会发生什么?
你的原始链接脚本问题:
.itcm : ALIGN(4) { ... } >ITCMRAM AT>FLASH /* 这个段被放到了0x08000000 */
.isr_vector : { ... } >FLASH /* 向量表被放到了后面 */
结果:
-
0x08000000处是.itcm段的数据,不是向量表 -
处理器读取到的是随机数据作为堆栈指针和复位地址
-
PC 指向非法地址 (
0x657B079A),程序跑飞
4. 正确的内存布局:
0x08000000: [堆栈指针初始值] <- 处理器从这里开始读取
0x08000004: [Reset_Handler地址]
0x08000008: [NMI_Handler地址]
0x0800000C: [HardFault_Handler地址]
...
0x0800xxxx: [.text 代码段]
0x0800yyyy: [.itcm 数据(加载地址)]
5. 类比理解:
想象一本书:
-
向量表 = 书籍的目录页(必须放在最前面)
-
代码段 = 书籍的正文内容
-
数据段 = 书籍的附录
如果目录页被放到了书中间,读者就找不到各个章节的位置了。
总结:
isr_vector 必须放在 Flash 的最前面是因为 ARM Cortex-M 处理器的硬件设计强制要求从固定地址读取启动信息。这是处理器的"硬编码"行为,无法通过软件改变。
这就是为什么调整段顺序后,你的程序才能正常启动的原因!