i.mx6ull中断向量表部分代码如下:
疑问:在_start中,汇编代码具体是如何执行和跳转的(越具体越好,从下面的代码分析)?ldr pc, =label是否会被执行?
我的理解:
①程序必然执行第一行ldr pc, =Reset_Handler,随后跳转到Reset_Handler中,并最终通过b main跳转到main函数
②剩余的ldr pc,=label 不会被执行,但编译器会给到这些指令相应的程序地址(0x04、0x08、0x0C),用于发生中断时跳转到相应的程序地址去执行中断函数
.global _start
_start:
ldr pc, =Reset_Handler /* Reset */
ldr pc, =Undefined_Handler /* Undefined instructions */
ldr pc, =SVC_Handler /* Supervisor Call */
ldr pc, =PrefAbort_Handler /* Prefetch abort */
ldr pc, =DataAbort_Handler /* Data abort */
.word 0 /* RESERVED */
ldr pc, =IRQ_Handler /* IRQ interrupt */
ldr pc, =FIQ_Handler /* FIQ interrupt */
Reset_Handler:
cpsid i /* 全局关闭中断 */
mrc p15, 0, r0, c1, c0, 0 /*读取CP15系统控制寄存器 */
bic r0, r0, #(0x1 << 12) /* 清除第12位(I位)禁用 I Cache */
bic r0, r0, #(0x1 << 2) /* 清除第 2位(C位)禁用 D Cache */
bic r0, r0, #0x2 /* 清除第 1位(A位)禁止严格对齐 */
bic r0, r0, #(0x1 << 11) /* 清除第11位(Z位)分支预测 */
bic r0, r0, #0x1 /* 清除第 0位(M位)禁用 MMU */
mcr p15, 0, r0, c1, c0, 0 /* 将修改后的值写回CP15寄存器 */
/* 定义IRQ工作模式的栈起始地址 */
cps #0x12
ldr sp, =IRQ_model_stack_start
/*定义User工作模式的栈起始地址,与Supervisor相同*/
cps #0x1F
ldr sp, =SUP_model_stack_start
/*定义Supervisor工作模式的栈起始地址,与User相同 */
cps #0x13
ldr sp, =SUP_model_stack_start
/*跳转到系统初始化函数,初始化GIC、CACHE-L1、mmu等等*/
ldr r2, =SystemInit
blx r2
/*开启全局中断*/
cpsie i
/*跳转到到 main 函数执行,*/
b main
b . /*死循环*/
在i.mx6ull中断向量表部分的代码中,_start
标签表示程序的入口点。程序开始执行时,它会首先执行ldr pc, =Reset_Handler
这一指令,该指令将Reset_Handler
的地址加载到寄存器pc中,并通过跳转指令实现跳转到该地址处执行中断处理函数。然后,程序会进入中断向量表,寻找相应的处理函数,具体如下:
Undefined_Handler
处理函数。SVC
类型的中断,程序会跳转到SVC_Handler
处理函数。Prefetch Abort
异常,程序会跳转到PrefAbort_Handler
处理函数。Data Abort
异常,程序会跳转到DataAbort_Handler
处理函数。IRQ_Handler
处理函数。FIQ_Handler
处理函数。在Reset_Handler
中,程序首先关闭全局中断,然后使用MRC指令读取CP15系统控制寄存器中的值。接下来的一系列BIC指令用于清除寄存器中的特定位,用于关闭I Cache、D Cache、严格对齐、分支预测、MMU等功能。之后,程序通过MCR指令将修改后的值写回CP15寄存器。此外,程序还会定义栈的起始地址,然后跳转到系统初始化函数(SystemInit)进行系统初始化。最后,开启全局中断并通过跳转指令跳转到main函数执行。
对于剩余的ldr pc, =label
指令,它们不会被实际执行。这些指令只是用于为中断处理函数指定相应的程序地址,以便在发生中断时跳转到正确的处理函数。
你的理解是对的!