
ARM 异常处理
ARM 异常处理
ARM异常处理是ARM处理器处理特殊事件的机制,这些事件可能来自硬件或软件。
ARM异常类型的优先级
复位(Reset)最高优先级,可以中断任何其他异常。
数据中止(Data Abort)当访问内存时发生错误。
快速中断请求(FIQ - Fast Interrupt Request)用于需要快速响应的高优先级外部中断。
普通中断请求(IRQ - Interrupt Request)用于常规的外部中断。
预取指令中止(Prefetch Abort)当尝试从内存取指令时发生错误。
软件中断(SWI - Software Interrupt)由软件主动触发,通常用于系统调用。
未定义指令(Undefined Instruction)当遇到处理器无法识别的指令时触发。
异常向量表
简单来讲就是:统一管理所有异常情况。
当处理器遇到”异常”时,它会查看这个表。
举例:
假设你的手机死机了(未定义指令异常):
处理器查看表中的”异常”联系方式。
然后按这个地址找到对应的处理程序。
简单软中断
我们写一个简单的软中断程序,通过swi
进行触发,然后使用sirq_handler
方法进行处理,最后返回并继续往下执行。
.text
b main @0x00 reset
nop @0x04 undef
b sirq_handler @0x08 soft irq
nop @0x0c prefecth abort
nop @0x10 data abort
nop @0x14 reserved
nop @0x18 irq
nop @0x1C fiq
sirq_handler:
stmfd sp!,{r0-r12,lr}
add r2,#1
sirq_handler_end:
ldmfd sp!,{r0-r12,pc}
main:
ldr sp,=stack_buf
mov r1,#1
mov r2,#2
swi 0x1
cmp r2,#2
moveq r4,#4
movne r4,#6
.data
stack_buf:
.space 15*4
.end
当我们执行完swi
命令后,将会触发软中断,会在前面异常向量表找到sirq_handler
进行执行。
此时LR
会记录swi
的下一条指令的地址。
但是我们要对数据操作时需要缓存一下历史数据所以我们通过stmfd
进行存储,并在异常处理完成后,通过ldmfd
进行返回值。
然后继续执行下面相关指令。
这里值得注意的是我定义了一块存储空间,并且要将ldr的sp指向存储空间的地址,原因是如果不进行指定就会报错。
通过ldmfd
从堆栈拿数据回来的时候会导致没权限,然后报错。
多个软中断
在有多个软中断的情况下,我们可以通过获取lr
的地址,减4位获取到swi
的地址,并且通过ldr获取到它的值,但是需要使用bic
去掉高8位指令段,剩下的就是值,然后通过实际的值我们就可以实现不同的软中断不同的处理。
.text
b main @0x00 reset
nop @0x04 undef
b sirq_handler @0x08 soft irq
nop @0x0c prefecth abort
nop @0x10 data abort
nop @0x14 reserved
nop @0x18 irq
nop @0x1C fiq
sirq_handler:
stmfd sp!,{r0-r12,lr}
ldr r0,[lr,#-4]
bic r0,#0xff000000
cmp r0,#1
addeq r2,#1
cmp r0,#2
subeq r2,#1
sirq_handler_end:
ldmfd sp!,{r0-r12,pc}
main:
ldr sp,=stack_buf
mov r1,#1
mov r2,#2
swi 0x1
cmp r2,#2
moveq r4,#4
movne r4,#6
swi 0x2
mov r0,#3
.data
stack_buf:
.space 15*4
.end
当执行到第一个软中断swi 0x1
时。
执行到第二个软中断swi 0x2
时。
B指令做跳转异常的缺陷
一是只能在32M范围的数据进行跳转,二是方法在其他地方将无法完成跳转。
所以我们这里可以做一点修改,将替换为ldr pc, _sirq_handler
里面通过一个字符串来进行存储地址,并进行执行跳转。
这样既可以突破32M的范围限制,当方法在其他文件中同样可以进行跳转。
欢迎加群讨论技术,1群:677373950(满了,可以加,但通过不了),2群:656732739

