玩嵌入式的,或多或少都接触ARM。
ARM既是一种处理器架构,也是一家公司,它不生产芯片,只靠芯片IP授权赚钱。
ARM处理器是英国Acorn有限公司设计的低功耗成本的第一款RISC微处理器。全称为Advanced RISC Machine。ARM处理器本身是32位设计,但也配备16位指令集,一般来讲比等价32位代码节省达35%,却能保留32位系统的所有优势。
更多详细介绍,请参考百度百科.
本文先列个大纲,后续有时间再补充。
这里整理了ARM汇编中非常基础的三大块知识,了解了这三大块内容基本可以看懂甚至编译一些简单的汇编程序。
ARM的寻址方式总共有9种,包括:
操作数是立即数,以“#”为前缀,表示 16 进制数值时以“0x”表示。
例:
MOV R0,#0xFF00 ;0xFF00 -> R0
SUBS R0,R0,#1 ;R0 – 1 -> R0
操作数的值在寄存器中,指令执行时直接取出寄存器值操作。
例:
MOV R1,R2 ;R2 -> R1
SUB R0,R1,R2 ;R1 - R2 -> R0
当第二操作数是寄存器偏移方式时,第二个寄存器操作数在与第一个操作数结合之前,选择进行移位操作。
例:
MOV R0,R2,LSL #3 ;R2 的值左移 3 位,结果放入 R0,即 R0 = R2 * 8
ANDS R1,R1,R2,LSL #3 ;R2 的值左移 3 位,然后和 R1 相与操作,结果放入 R1
可采用的移位操作:
LSL:逻辑左移(Logical Shift Left),低端空出位补 0
LSR:逻辑右移(Logical Shift Right),高端空出位补 0
ASR:算术右移(Arithmetic Shift Right),移位过程中符号位不变,即源操作数为正数,则高端空出位补 0,否则补 1
ROR:循环右移(Rotate Right),由低端移出位填入高端空出位
RRX:带扩展的循环右移(Rotate Right eXtended by 1 place),操作数右移一位,高端空出位用原 C 标志值填充。
操作数保存在寄存器指定地址的存储单元中,即寄存器为操作数的地址指针。
例:
LDR R1,[R2] ;将 R2 中的数值作为地址,取出此地址中的数据保存在 R1 中
SWP R1,R1,[R2] ;将R2中的数值作为地址,取出此地址中的数值与 R1 中的值**
将基址寄存器的值与偏移量相加,形成操作数的有效地址,基址寻址用于访问基址附近的存储单元,常用于查表、数组操作、功能寄存器访问等。
例:
LDR R2,[R3,#0x0F] ;将R3中的数值加 0x0F 作为地址,取此地址的值保存在 R2 中
STR R1,[R0,#-2] ;将R0中的数值减 2 作为地址,把 R1的值保存到此地址中
一次传送多个寄存器值,允许一条指令传送 16 个寄存器的任何子集或所有寄存器。多寄存器寻址时,寄存器子集按由小到大的顺序排列,连续的寄存器可用“-”连接,否则,用“,”分隔书写。
例:
LDMIA R1!,{R2-R7,R12} ;将 R1的值读出到 R2-R7,R12,过程中R1 自动加 1
STMIA R0!,{R3-R6,R10};将 R3-R6,R10的值保存到 R0 指向的地址,过程中R0 自动加 1
堆栈寻址使用堆栈指针SP,即R13,指向堆栈的栈顶。堆栈可分为两种:
向上生长:向高地址方向生长,称为递增堆栈,
向下生长:向低地址方向生长,称为递减堆栈,
堆栈指针指向最后压入的有效数据项,称为满堆栈,
堆栈指针指向下一个要放入的空位置,称为空堆栈,这样就有 4 种类型的堆栈。
A)满递增:堆栈地址向上增长,堆栈指针指向有效数据的最高地址。如 LDMFA,STMFA。
B)空递增:堆栈地址向上增长,堆栈指针指向堆栈上的第一个空位置。如 LDMEA,STMEA 。
C)满递减:堆栈地址向下增长,堆栈指针指向有效数据项的最低地址。如 LDMFD,STMFD。
D)空递减:堆栈地址向下增长,堆栈指针指向堆栈下的第一个空位置。如 LDMED,STMED 。
例:
STMFD SP!,{R1-R7,LR} ; 将 R1~R7,LR 入栈。满递减堆栈。
LDMFD SP!,{R1-R7,LR} ;数据出栈,放入 R1~R7,LR 寄存器。满递减堆栈。
用于将一块数据从存储器的某一位置拷贝到另一位置。
例:
STMIA R0!,{R1-R7} ;将R1~R7的数据保存到存储器中,存储器指针在保存第一个值之后增加,增长方向为向上增长。
STMIB R0!,{R1-R7} ;将R1~R7的数据保存到存储器中,存储器指针在保存第一个值之前增加,增长方向为向上增长。
STMDA R0!,{R1-R7} ;将R1~R7的数据保存到存储器中,存储器指针在保存第一个值之后增加,增长方向为向下增长。
STMDB R0!,{R1-R7} ;将R1~R7的数据保存到存储器中,存储器指针在保存第一个值之前增加,增长方向为向下增长。
相对寻址是基址寻址的一种变通,由程序计数器 PC 提供基准地址,指令中的地址
码字段作为偏移量,两者相加后得到有效地址。
例:
BL ROUTE1 ;调用ROUTE1 子程序
BEQ LOOP ;条件跳转到 LOOP 标号处
…
LOOP MOV R2,#2
…
ROUTE1
…
ARM共有37个32位物理寄存器,7种工作模式下可访问的寄存器见下表,User和System使用完全相同的物理寄存器。
其中 r0~r3 主要用于子程序间传递参数, r4~r11 主要用于保存局部变量,但在 Thumb 程序中,通常只能使用 r4~r7 来保存局部变量; r12 用作子程序间scratch 寄存器,即 ip 寄存器; r13 通常用做栈指针,即 sp; r14 寄存器又被称为连接寄存器(lr),用于保存子程序以及中断的返回地址; r15 用作程序计数器(pc),由于 ARM 采用了流水线机制,当正确读取了 PC 的值后,该值为当前指令地址加 8 个字节,即 PC 指向当前指令的下两条指令地址。
CPSR和SPSR都是程序状态寄存器,其中SPSR是用来保存中断前的CPSR中的值,以便在中断返回之后恢复处理器程序状态。
所有工作模式下,R0-R7都分别指向同一个物理寄存器(共8个物理寄存器),它们未被系统用作特殊的用途。在中断或异常处理进行工作模式转换时,由于不同工作模式均使用相同的物理寄存器,可能造成寄存器中数据的破坏。
在User&System、IRQ、Svc、Abt和Und模式下访问的R8~R12都是同一个物理寄存器(共5个物理寄存器);在FIQ模式下,访问的R8fiq~R12fiq是另外独立的物理寄存器(共5个物理寄存器)。
在User&System、IRQ、FIQ、Svc、Abt和Und访问的R13_~R14都是各自模式下独立的物理寄存器(共12个物理寄存器)。
R13在ARM指令中常用作堆栈指针(SP),但这只是一种习惯用法,用户也可使用其他的寄存器作为堆栈指针。而在Thumb指令集中,某些指令强制性的要求使用R13作为堆栈指针。
由于处理器的每种工作模式均有自己独立的物理寄存器R13,在用户应用程序的初始化部分,一般都要初始化每种模式下的R13,使其指向该工作模式的栈空间。这样,当程序进入异常模式时,可以将需要保护的寄存器放入R13所指向的堆栈,而当程序从异常模式返回时,则从对应的堆栈中恢复,采用这种方式可以保证异常发生后程序的正常执行。 R14称为链接寄存器(Link Register),当执行子程序调用指令(BL)时,R14可得到R15(程序计数器PC)的备份。在每一种工作模式下,都可用R14保存子程序的返回地址,当用BL或BLX指令调用子程序时,将PC的当前值复制给R14,执行完子程序后,又将R14的值复制回PC,即可完成子程序的调用返回。以上的描述可用指令完成。
执行以下任意一条指令: MOV PC, LR BX LR 在子程序入口处使用以下指令将R14存入堆栈: STMFD SP!,{,LR} 对应的,使用以下指令可以完成子程序返回: LDMFD SP!,{,PC} R14也可作为通用寄存器。
所有工作模式下访问的R15都是同一个物理寄存器,由于ARM体系结构采用了多级流水线技术,对于ARM指令集而言,PC总是指向当前指令的下两条指令的地址,即PC的值为当前指令的地址值加8个字节。
在ARM状态下,R15[1:0]为0,R15[31:2]用于保存PC;在Thumb状态下,R15[0]为0,R15[31:1]用于保存PC。
R16用作CPSR(Current Program Status Register,当前程序状态寄存器),CPSR可在任何工作模式下被访问,它包括条件标志位、中断禁止位、当前处理器模式标志位,以及其他一些相关的控制和状态位。
每一种工作模式下又都有一个专用的物理状态寄存器,称为SPSR(Specified Program Status Register,备份的程序状态寄存器),当异常发生时,SPSR用于保存CPSR的当前值,从异常退出时则可由SPSR来恢复CPSR。 User模式和System模式不属于异常模式,它们没有SPSR,当在这两种模式下访问SPSR,结果是未知的。
2.6 CPSR各标志位含义
31 | 30 | 29 | 28 | 27 | 26 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
N | Z | C | V | Q | DNM(RAZ) | I | F | T | M4 | M3 | M2 | M1 | M0 |
N(Negative)---设置成当前指令运算结果的bit[31]的值。当两个有符号整数运算时,N=1运算结果为负数,N=0运算结果为正。
Z(Zero)---Z=1运算结果为零;Z=0表示运算的结果不为零。对于CMP指令,Z=1表示进行比较的两个数大小相等。
C(Carried out)---分四种情况讨论 1)在加法指令中(包括比较指令CMP),当结果产生进位,则C=1,表示无符号运算发生上溢出;其他情况C=0。 2)在减法指令中(包括减法指令CMP),当运算发生借位,则C=0,表示无符号运算发生下溢出;其他情况下C=1。 3)对于包含移位操作的非加减运算指令,C中包含最后一次溢出的位的数值 4)对于其他非加减运算指令,C位的值通常不受影响 V(oVerflow)---对于加减运算指令,当操作数和运算结果为二进制的补码表示的带符号数时,V=1符号为溢出;通常其他指令不影响V位。
Q---在ARM V5的E系列处理器中,CPSR的bit[27]称为Q标识位,主要用于指示增强的DSP指令是否发生了溢出。同样的spsr的bit[27]位也称为Q标识位,用于在异常中断发生时保存和恢复CPSR中的Q标识位。在ARM V5以前的版本及ARM V5的非E系列的处理器中,Q标识位没有被定义。
I和F---当I=1时禁止IRQ中断,当F=1时禁止FIQ中断
T---对于ARM V4以更高版本的T系列ARM处理器,T=0表示执行ARM指令;T=1表示执行Thumb指令 对于ARM V5以及更高版本的非T系列处理器,T=0表示执行ARM指令;T=1表示强制下一条执行的指令产生未定指令中断
M[4:0]---定义了的ARM工作模式,具体见1中表CSPR[4:0]定义的ARM工作模式
由于ARM的指令非常多,本文仅列举常见的一些汇编指令,更多的指令格式,请参考其他资料。
数据传输指令 mov mvn 算术指令 add sub rsb adc sbc rsc 逻辑指令 and orr eor bic 比较指令 cmp cmn tst teq 乘法指令 mvl mla umull umlal smull smlal 前导零计数 clz
mrs & msr mrs用来读psr,msr用来写psr CPSR寄存器比较特殊,需要专门的指令访问,这就是mrs和msr。
b & bl & bx b 直接跳转(就没打开算返回) bl branch and link,跳转前把返回地址放入lr中,以便返回,以便用于函数调用 bx跳转同时切换到ARM模式,一般用于异常处理的跳转。
ldr/str & ldm/stm & swp 单个字/半字/字节访问 ldr/str 多字批量访问 ldm/stm swp r1, r2, [r0] swp r1, r1, [r0]
swi(software interrupt) 软中断指令用来实现OS中系统调用
欢迎关注我的github仓库01workstation,日常分享一些开发笔记和项目实战,欢迎指正问题。
同时也非常欢迎关注我的CSDN主页和专栏:
【CSDN主页:架构师李肯】
【RT-Thread主页:架构师李肯】
【C/C++语言编程专栏】
【GCC专栏】
【信息安全专栏】
【RT-Thread开发笔记】
【freeRTOS开发笔记】
【BLE蓝牙开发笔记】
【ARM开发笔记】
【RISC-V开发笔记】
有问题的话,可以跟我讨论,知无不答,谢谢大家。
以上参考资料,由本人整理,但来源于网络,侵删!
审核编辑:汤梓红
全部0条评论
快来发表一下你的评论吧 !