本文主要面向初次接触ARM的初学者,主要做基础知识的讲解与科普,希望能对初学者有所帮助.
文章目录
前言
本文主要是介绍了ARM中常用的一些指令,异常源和处理过程的分析,面向广大初学者有扩展知识和夯实基础的效果。
一、什么是指令?指令有哪些?
很多初学者认为计算机要执行相应的功能,是由程序实现的。实际上计算机只识别二进制代码,而我们的程序实际上都是在通过编译器编译后产生二进制文件(机器码),该文件又被我们的计算机识别从而实现。
告诉计算机从事某一特殊运算的代码即是指令,指令本文介绍的有如下几种:
1.数据处理指令:对数据进行逻辑、算数运算
2.跳转指令:实现程序的跳转,实质是修改PC
3.Load/Store指令:对内存的读写操作//如 a++ 读a的值,将运算结果从cpu写入内存
4.状态寄存器传送指令: 对CPSR进行读写操作//其他都不能动CPSR
5.异常中断产生指令: 触发软中断,常用于内核的系统调用 //SWI:软中断
6.协处理器指令: 操作协处理器的指令
二、常用指令
1.数据处理指令
数据搬移指令 mov ldr
●@ 格式:mov Rd, oprand2 /ldr
●如果是立即数,前边必须加#:
mov r1,#0x2 @将0x2得值赋给寄存器r1
加法指令 add/adc/adcs
●@格式:<操作码><目标寄存器><第一操作寄存器><第二操作数>
ADD R3,R1,R2;
@R2可以是立即数 只有乘法的R2不能为立即数
●操作码 指定当前指令是哪种运算
●目标寄存器 存放运算结果
●第一操作寄存器 存放参与运算的一个数据(只能是寄存器)
●第二操作数 存放参与运算的另一个数据(可以是寄存器/立即数)
注: add为普通加法运算,adc为带进位的加法运算,adcs表示运算的结果对NZCV四位标志位产生影响改动
同理,还有减法指令sub/subs,除法指令div,乘法指令mul
立即数:
转换为二进制后,所有的1加起来不超过255,右移偶数次可以得到原数即为立即数。
立即数是保存在指令中的数,取指令的同时将值取过去,和普通变量的区别是,变量保存在内存中的数据,需要单独取值运算。
立即数的本质:立即数是包含在指令当中的数据(即属于指令的一部分)
立即数的优点:读取指令的同时也将立即数读取到了内存中,速度快
立即数的缺点:数量有限
2.数据跳转指令
跳转的实质是修改PC的内容
1.直接对PC进行修改,mov (不建议)
@注意修改时按4的倍数修改,因为一个指令4个字节,若未修改4的倍数则向下取整
例如:mov pc,#0x3 —> 实际跳转至0x0
2.跳转指令跳转 b/bl
b:不带返回值跳转,即不更新lr存储指令寄存器的地址
bl:带返回值跳转
beq: 数据跳转指令,标志寄存器中Z标志位等于零时, 跳转到BEQ后标签处.
3.Load/Store指令
单寄存器指令 ldr/str
格式:ldr/str Rm, [Rn]
Rm: 存储是数据
Rn:存储的数据,地址
str用来将数据写入到指定地址中,ldr用来将指定地址的数据读出到某个寄存器中
ldr r0,=0x40002000
ldr r1,=0x12345678
@str r1,[r0] 将r1的值写入到r0中
@ldr r3,[r0] 将r0地址内的值存到r3中
@str r1,[r0,#0x4] 将r1的值写入到r0+4的地址中
@ldr r3,[r0,#0x4] 将r0+4地址内的值存到r3中
@str r1,[r0],#0x4 将r1的值写入到r0中,同时r0=r0+4
@str r1,[r0,#0x4]! 将r1的值写入到r0中,同时r0=r0+4
!的作用即表示同时更新寄存器的地址(无设定步长即表示自增或自减)
多寄存器操作指令 stm/ldm
stm R0, {Rm-Rn}:将Rm到Rn中的值存储到R0指向地址空间中
ldm R0, {Rm-Rn}:将r0指向的地址空间中,连续的数据,读到Rm到Rn的寄存器中
如果不连续,则可以用逗号隔开,例如:stm r0,{r1-r4,r6}
注:
不管寄存器列表中的寄存器编号顺序如何变化,
都是小地址对应小编号的寄存器高地址对应大编号的寄存器
栈的操作指令 stmfd/ldmfd
stmfd/ldmfd sp!, {寄存器列表}
stmfd sp!, {r1-r5}(写) (压栈)更新栈指针指向的地址空间
ldmfd sp!, {r6-r10}(读) (出栈)
4.状态寄存器指令
状态寄存器指令 msr/mrs
读cpsr—>mrs
写cpsr—>msr
在user模式下一般用不了cpsr修改状态寄存器的值,上电就是svc模式,只能切换到user模式
一般情况下,我们只使用cpsr_c 对低八位控制域进行修改;
USER模式下不可进行模式更改,防止应用程序修改CPU程序,保护操作系统
5.异常中断寄存器指令
swi 编号(立即数或者数字)
注:
处理器遇到异常后会暂停当前的程序转而去处理异常(执行异常处理程序)
处理完成后返回到被异常打断的代码处继续执行
6.协处理器指令
操作协处理器的指令
如3x3 —》用加法器实现3+3+3,比较慢。我们可以外接一个协处理器(乘法器)(每个协处理器的功能比较单一),
协处理器指令就是操作这个协处理器的,用的比较多的cp15协处理器。
三、异常源
1)复位异常reset(进入异常模式svc):CPU刚上电时或按下reset重启键之后进入该异常
2)IRQ/FIQ 一般/快速中断请求(异常模式IRQ/FIQ)
快速中断具有最高中断优先级和最小的中断延迟,通常用于处理高速数据传输及通道的中数据恢复处理,
如DMA等,绝大部分外设使用一般中断请求。
3)预取指令终止异常PrefetchAbort(异常模式abort)
CPU三级流水线阶段取指阶段指令地址非法
4)未定义指令异常(Undef)
CPU三级流水线译码阶段,若当前指令无法被识别为有效指令(错误指令)
5)软中断指令异常swi(异常模式svc)
该异常是应用程序自己调用时产生的,用于用户程序申请访问硬件资源时
/*辅助理解*/
例如:printf()打印函数,要将用户数据打印到显示器上,用户程序要想实现打印必须申请使用显示器,
而用户程序又没有外设硬件的使用权,只能通过使用软件中断指令切换到内核态,通过操作系统内核代码来访问外设硬件,
内核态是工作在特权模式下,操作系统在特权模式下完成将用户数据打印到显示器上。
这样做的目的无非是为了保护操作系统的安全和硬件资源的合理使用,该异常在管理模式下处理。
6)数据中止访问异常 DataAbort(异常模式abort)
该异常发生在要访问数据地址不存在或者为数据非法地址时
四、异常处理
四大步三小步:
1)拷贝CPSR到SPSR_
将正在运行的模式的cpsr保存到对应异常模式下的spsr中。
2)修改CPSR:(修改cpsr让它切换到对应异常模式下)
a.进入ARM状态 (强制)
b.进入相应的异常模式 (切换模式)
c.禁止其他中断 (再来异常,不会打断当前的异常处理)
3)保存返回地址到LR_
跳转到异常处理(修改的是pc)之前,将pc下一条指令地址保存lr中,再修改pc跳转对应异常处理位置。
4)设置PC为相应的异常向量地址(跳转到异常向量表中对应的位置)
跳转到中断执行程序
修改pc切换到异常处理位置
异常向量表:
异常向量表是处于内存中的一段空间
在异常向量表中为每个异常源分配了四个字节的存储空间
当产生了异常后PC的值会自动变成该异常源在异常向量表中的地址
我们在异常向量表对应的位置写一条跳转指令使其跳转到异常处理程序入口
五、异常处理过程
@模拟异常处理的过程
b reset
b undef_handler
b swi_handler
b . @.:占位,表示该异常向量表所在的地址有内容,但无跳转标签
b .
b .
b .
b .
reset:@初始化
@svc模式下的栈
ldr sp,=0x40000100
msr cpsr_c,#0x10 @切换到user模式下执行基本代码
@初始化user模式下栈
msr cpsr_c,#0x10
ldr sp,=0x4000200
ldr r1,=0x12345678
ldr r2,=0x22345678
swi 2
ldr r3,=0x32345678
ldr r4,=0x42345678
b stop
undef_handler:
swi_handler: @IRQ异常处理函数
@压栈保护现场,LR需要注意同时压栈,防止处理过程中调用其他中断或其他函数
stmfd sp!,{r0-r12,lr}
mov r1,#0x1
mov r2,#0x2
ldmfd sp!,{r0-r12,pc}^ @^:作用是将spsr值赋给cpsr
stop:
b stop
.end
总结
至此,本文将ARM的常用指令及异常处理等内容进行了简答讲解,希望对大家有所帮助。