ARM 异常处理 电脑版发表于:2024/6/30 17:17 ![](https://img.tnblog.net/arcimg/hb/6930d1439f4b43e785a433685b813262.png) >#ARM 异常处理 [TOC] ARM 异常处理 ------------ tn2>ARM异常处理是ARM处理器处理特殊事件的机制,这些事件可能来自硬件或软件。 ### ARM异常类型的优先级 tn2>复位(Reset)最高优先级,可以中断任何其他异常。 数据中止(Data Abort)当访问内存时发生错误。 快速中断请求(FIQ - Fast Interrupt Request)用于需要快速响应的高优先级外部中断。 普通中断请求(IRQ - Interrupt Request)用于常规的外部中断。 预取指令中止(Prefetch Abort)当尝试从内存取指令时发生错误。 软件中断(SWI - Software Interrupt)由软件主动触发,通常用于系统调用。 未定义指令(Undefined Instruction)当遇到处理器无法识别的指令时触发。 ### 异常向量表 tn2>简单来讲就是:统一管理所有异常情况。 当处理器遇到"异常"时,它会查看这个表。 <br/> 举例: 假设你的手机死机了(未定义指令异常): 处理器查看表中的"异常"联系方式。 然后按这个地址找到对应的处理程序。 ![](https://img.tnblog.net/arcimg/hb/f89a3dc10aff4a5493cb498e37778198.png) ![](https://img.tnblog.net/arcimg/hb/6be3a48d47d5468a99d86b626bcc7873.png) ### 简单软中断 tn2>我们写一个简单的软中断程序,通过`swi`进行触发,然后使用`sirq_handler`方法进行处理,最后返回并继续往下执行。 ```bash .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 ``` ![](https://img.tnblog.net/arcimg/hb/ffa63017834c41c5be4a04844b16a380.png) tn2>当我们执行完`swi`命令后,将会触发软中断,会在前面异常向量表找到`sirq_handler`进行执行。 此时`LR`会记录`swi`的下一条指令的地址。 但是我们要对数据操作时需要缓存一下历史数据所以我们通过`stmfd`进行存储,并在异常处理完成后,通过`ldmfd`进行返回值。 然后继续执行下面相关指令。 ![](https://img.tnblog.net/arcimg/hb/10eb8560311943da8649f064dd665042.png) ![](https://img.tnblog.net/arcimg/hb/fb435c90d53d430cbe8fb19d0e792f56.png) ![](https://img.tnblog.net/arcimg/hb/019661d936e646deb52ede52ca8f2b21.png) tn>这里值得注意的是我定义了一块存储空间,并且要将ldr的sp指向存储空间的地址,原因是如果不进行指定就会报错。 通过`ldmfd`从堆栈拿数据回来的时候会导致没权限,然后报错。 ### 多个软中断 tn2>在有多个软中断的情况下,我们可以通过获取`lr`的地址,减4位获取到`swi`的地址,并且通过ldr获取到它的值,但是需要使用`bic`去掉高8位指令段,剩下的就是值,然后通过实际的值我们就可以实现不同的软中断不同的处理。 ```bash .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 ``` tn2>当执行到第一个软中断`swi 0x1`时。 ![](https://img.tnblog.net/arcimg/hb/fbf6d50dac924403bc8c088dfcf7fedd.png) ![](https://img.tnblog.net/arcimg/hb/2d06c44c0d80444684fcdfb66bb55a9f.png) tn2>执行到第二个软中断`swi 0x2`时。 ![](https://img.tnblog.net/arcimg/hb/ce1ca115b2e3449dac5576bbaaf174bd.png) ### B指令做跳转异常的缺陷 tn2>一是只能在32M范围的数据进行跳转,二是方法在其他地方将无法完成跳转。 所以我们这里可以做一点修改,将替换为`ldr pc, _sirq_handler`里面通过一个字符串来进行存储地址,并进行执行跳转。 这样既可以突破32M的范围限制,当方法在其他文件中同样可以进行跳转。 ![](https://img.tnblog.net/arcimg/hb/6d9fe931d56b4e97bb3f2855433c88c7.png) ![](https://img.tnblog.net/arcimg/hb/739ace32a8764279beb45344e15e229e.png)