1 前言
玩嵌入式的,或多或少都接触ARM。 ARM既是一种处理器架构,也是一家公司,它不生产芯片,只靠芯片IP授权赚钱。 ARM处理器是英国Acorn有限公司设计的低功耗成本的第一款RISC微处理器。全称为Advanced RISC Machine。ARM处理器本身是32位设计,但也配备16位指令集,一般来讲比等价32位代码节省达35%,却能保留32位系统的所有优势。
2 ARM知识图谱
本文先列个大纲,后续有时间再补充。
3 ARM汇编基础三大块
这里整理了ARM汇编中非常基础的三大块知识,了解了这三大块内容基本可以看懂甚至编译一些简单的汇编程序。
3.1 寻址方式 ARM的寻址方式总共有9种,包括:
3.1.1 立即寻址 操作数是立即数,以“#”为前缀,表示 16 进制数值时以“0x”表示。 例: MOV R0,#0xFF00 ;0xFF00 -> R0 SUBS R0,R0,#1 ;R0 – 1 -> R0
3.1.2 寄存器寻址 操作数的值在寄存器中,指令执行时直接取出寄存器值操作。 例: MOV R1,R2 ;R2 -> R1 SUB R0,R1,R2 ;R1 - R2 -> R0
3.1.3 寄存器偏移寻址 当第二操作数是寄存器偏移方式时,第二个寄存器操作数在与第一个操作数结合之前,选择进行移位操作。 例:
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 标志值填充。
3.1.4 寄存器间接寻址 操作数保存在寄存器指定地址的存储单元中,即寄存器为操作数的地址指针。 例:
LDR R1,[R2] ;将 R2 中的数值作为地址,取出此地址中的数据保存在 R1 中 SWP R1,R1,[R2] ;将R2中的数值作为地址,取出此地址中的数值与 R1 中的值**
3.1.5 基址寻址 将基址寄存器的值与偏移量相加,形成操作数的有效地址,基址寻址用于访问基址附近的存储单元,常用于查表、数组操作、功能寄存器访问等。 例:
LDR R2,[R3,#0x0F] ;将R3中的数值加 0x0F 作为地址,取此地址的值保存在 R2 中 STR R1,[R0,#-2] ;将R0中的数值减 2 作为地址,把 R1的值保存到此地址中
3.1.6 多寄存器寻址 一次传送多个寄存器值,允许一条指令传送 16 个寄存器的任何子集或所有寄存器。多寄存器寻址时,寄存器子集按由小到大的顺序排列,连续的寄存器可用“-”连接,否则,用“,”分隔书写。 例:
LDMIA R1!,{R2-R7,R12} ;将 R1的值读出到 R2-R7,R12,过程中R1 自动加 1 STMIA R0!,{R3-R6,R10};将 R3-R6,R10的值保存到 R0 指向的地址,过程中R0 自动加 1
3.1.7 堆栈寻址 堆栈寻址使用堆栈指针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 寄存器。满递减堆栈。
3.1.8 块拷贝寻址 用于将一块数据从存储器的某一位置拷贝到另一位置。 例:
STMIA R0!,{R1-R7} ;将R1~R7的数据保存到存储器中,存储器指针在保存第一个值之后增加,增长方向为向上增长。
STMIB R0!,{R1-R7} ;将R1~R7的数据保存到存储器中,存储器指针在保存第一个值之前增加,增长方向为向上增长。
STMDA R0!,{R1-R7} ;将R1~R7的数据保存到存储器中,存储器指针在保存第一个值之后增加,增长方向为向下增长。
STMDB R0!,{R1-R7} ;将R1~R7的数据保存到存储器中,存储器指针在保存第一个值之前增加,增长方向为向下增长。
3.1.9 相对寻址 相对寻址是基址寻址的一种变通,由程序计数器 PC 提供基准地址,指令中的地址 码字段作为偏移量,两者相加后得到有效地址。 例:
BL ROUTE1 ;调用ROUTE1 子程序 BEQ LOOP ;条件跳转到 LOOP 标号处 … LOOP MOV R2,#2 … ROUTE1 …
3.2 寄存器的用途
3.2.1 ARM寄存器列表
ARM共有37个32位物理寄存器,7种工作模式下可访问的寄存器见下表,User和System使用完全相同的物理寄存器。
3.2.2 ARM寄存器的用途 其中 r0~r3 主要用于子程序间传递参数, r4~r11 主要用于保存局部变量,但在 Thumb 程序中,通常只能使用 r4~r7 来保存局部变量; r12 用作子程序间scratch 寄存器,即 ip 寄存器; r13 通常用做栈指针,即 sp; r14 寄存器又被称为连接寄存器(lr),用于保存子程序以及中断的返回地址; r15 用作程序计数器(pc),由于 ARM 采用了流水线机制,当正确读取了 PC 的值后,该值为当前指令地址加 8 个字节,即 PC 指向当前指令的下两条指令地址。
CPSR和SPSR都是程序状态寄存器,其中SPSR是用来保存中断前的CPSR中的值,以便在中断返回之后恢复处理器程序状态。
3.2.2.1 R0~R7 所有工作模式下,R0-R7都分别指向同一个物理寄存器(共8个物理寄存器),它们未被系统用作特殊的用途。在中断或异常处理进行工作模式转换时,由于不同工作模式均使用相同的物理寄存器,可能造成寄存器中数据的破坏。
3.2.2.2 R8~R12 在User&System、IRQ、Svc、Abt和Und模式下访问的R8R12都是同一个物理寄存器(共5个物理寄存器);在FIQ模式下,访问的R8_fiqR12_fiq是另外独立的物理寄存器(共5个物理寄存器)。
3.2.2.3 R13(SP)和R14(LR) 在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也可作为通用寄存器。
3.2.2.4 程序计数器PC(R15) 所有工作模式下访问的R15都是同一个物理寄存器,由于ARM体系结构采用了多级流水线技术,对于ARM指令集而言,PC总是指向当前指令的下两条指令的地址,即PC的值为当前指令的地址值加8个字节。
在ARM状态下,R15[1:0]为0,R15[31:2]用于保存PC;在Thumb状态下,R15[0]为0,R15[31:1]用于保存PC。
3.2.2.5 CPSR和SPSR R16用作CPSR(Current Program Status Register,当前程序状态寄存器),CPSR可在任何工作模式下被访问,它包括条件标志位、中断禁止位、当前处理器模式标志位,以及其他一些相关的控制和状态位。
每一种工作模式下又都有一个专用的物理状态寄存器,称为SPSR(Specified Program Status Register,备份的程序状态寄存器),当异常发生时,SPSR用于保存CPSR的当前值,从异常退出时则可由SPSR来恢复CPSR。
User模式和System模式不属于异常模式,它们没有SPSR,当在这两种模式下访问SPSR,结果是未知的。
2.6 CPSR各标志位含义
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工作模式
3.3 汇编指令 由于ARM的指令非常多,本文仅列举常见的一些汇编指令,更多的指令格式,请参考其他资料。
3.3.1 数据处理指令 数据传输指令 mov mvn 算术指令 add sub r*** adc ***c rsc 逻辑指令 and orr eor bic 比较指令 cmp cmn tst teq 乘法指令 mvl mla umull umlal smull smlal 前导零计数 clz
3.3.2 cpsr访问指令 mrs & msr mrs用来读psr,msr用来写psr CPSR寄存器比较特殊,需要专门的指令访问,这就是mrs和msr。
3.3.3 跳转(分支)指令 b & bl & bx b 直接跳转(就没打开算返回) bl branch and link,跳转前把返回地址放入lr中,以便返回,以便用于函数调用 bx跳转同时切换到ARM模式,一般用于异常处理的跳转。
3.3.4 访存指令 ldr/str & ldm/stm & swp 单个字/半字/字节访问 ldr/str 多字批量访问 ldm/stm swp r1, r2, [r0] swp r1, r1, [r0]
3.3.5 软中断指令 swi(software interrupt) 软中断指令用来实现OS中系统调用。
|