做题知识不够用,我又来学习了。
ARM指令集机器编码基本格式:
31-28 | 27-20 | 19-16 | 15-12 | 11-0 |
---|---|---|---|---|
条件码 | 指令码 | 目的寄存器 | 操作数1寄存器 | 操作数2 |
1. 寻址方式
1.1 立即寻址
操作数包含在指令的32位机器编码中。#
表示立即数。
1 | ADD R0,R0,#1 ;R0 <- R0 + 1 |
问题:32位长立即数的编码问题(合法性问题)
原因:在指令中,立即数作为操作数2出现,编码格式中仅安排了12位,32位立即数不能直接编码。
解决:12位编码包括8位常数和4位循环右移值,由8位常数循环右移4位值的2倍得到最后的32位立即数。
例:MOV R0,#0x0000F200
机器代码:E3A00CF2
机器代码含义:E表示无条件,3A是MOV的机器码,00表示R0寄存器,C是4位循环右移值,F2是8位常数。
方法:0xF2循环右移12*2=24位得到原32位数值
移位前: | |||||||
---|---|---|---|---|---|---|---|
0000 | 0000 | 0000 | 0000 | 0000 | 0000 | 1111 | 0010 |
移位后: | |||||||
0000 | 0000 | 0000 | 0000 | 1111 | 0010 | 0000 | 0000 |
1.2 寄存器寻址
操作数存放在寄存器中。
1.2.1 基本方式
1 | ADD R0,R1,R2 ;R0 <- R1 + R2 |
1.2.2 对第二操作数寄存器的移位操作
1 | ADD R3,R2,R1,LSR #2 ;R3 <- R2 + R1 / 4 |
移位方式:
移位方式 | 含义 |
---|---|
LSL | 逻辑左移(乘) |
LSR | 逻辑右移(除) |
ASL | 算术左移,和LSL一样。类似于小数点移位,左移数变小 |
ASR | 算术右移,分正负来填充右移后的空余位,右移数变大 |
ROR | 循环右移 |
RRX | 带扩展的循环右移,循环右移1位后左端用C填充,这种方式只移位1位,所以无需指定移位位数 |
1.2.3 寄存器间接寻址
利用寄存器的值作为存储器指针,数据传送类的load/store类指令都使用寄存器间接寻址方式。
1 | LDR R0,[R1] ;R0 <- mem32[R1] |
1.2.4 基址加偏移地址
1 | 前变址 |
1.3 多寄存器及块拷贝寻址
一条指令完成多字数据或数据块的传送。
基本指令:LDM/STM
基址寄存器变化方式 | 含义 |
---|---|
IA | 操作完后地址递增 |
IB | 地址先增后完成操作 |
DA | 操作完后地址递减 |
DB | 地址先减后完成操作 |
多寄存器语法表示:多寄存器用{}
包含,连续寄存器使用-
间隔,不连续的用,
分隔。
例1:
1 | LDMID R0,{R1-R4,R6} ;R1=[R0],R2=[R0+4],...,R6=[R0+16] |
R0作为基址寄存器,其值可自动更新:
1 | LDMID R0!,{R1-R4,R6} |
例2:
LDM指令和STM指令配合实现数据块拷贝:
1 | LDMIA R0,{R1-R5} ;以R0为基址读取五字存储单元数据加载至R1-R5 |
1.4 堆栈寻址
存储空间中的数据栈与寄存器组之间的批量数据传输,采用R13(SP)作为堆栈指针,采用FILO(先进后出)的方式工作,SP指向栈顶。
基本指令:LDM/STM
堆栈组织生成方式:
FD/ED:满递减/空递减
FA/EA:满递增/空递增
1 | STMFD SP!,{R0-R7,LR} ;入栈 |
先将LR入栈,最后才是R0入栈;先R0出栈,最后LR出栈。
FD相当于多寄存器寻址的DB。
事实上,堆栈寻址与多寄存器寻址均可操作堆栈,在需要保存特定某些寄存器值时,采用STM进行压栈,采用LDM操作弹出堆栈。
1 | 保存数据 |
1.5 相对寻址
将程序计数器PC作为基址寄存器,指令中的地址标号字段作为偏移量进行寻址,跳转指令采用相对寻址方式。
2. ARM指令集
2.1 存储器访问(L/S)指令
常规:
1 | LDR R2,[R5] ;将R5为地址的存储单元中数据加载至R2(读) |
传送数据类型:
1 | LDRB R3,[R2],#1 ;以R2为地址读取1字节数据至R3,R2 = R2 + 1 |
多寄存器补充:在非用户或系统模式下,可出现^
后缀,若LDM指令寄存器列表中包含PC,则会额外将SPSR拷贝。
2.2 数据处理类指令
2.2.1 数据传送指令
1 | MOV R1,R0 ;R1 <- R0 |
2.2.2 算数逻辑运算指令
例1:64位整数加法
R0/R1与R2/R3分别存放两个加数的低/高32位,R4/R5存放结果的低/高32位。
1 | ADDS R4,R0,R2 ;带S后缀结果影响CPSR的标志位C |
例2:64位整数减
1 | SUBS R4,R0,R2 |
例3:逆向减法
1 | RSB R0,R1,R2 ;R0=R2-R1 |
例4:逻辑运算
1 | AND R0,R0,#3 ;保持R0的0、1位,其余清零 |
例5:比较指令
1 | CMP R1,R0 ;R1-R0,结果影响CPSR中的标志位,但不保留运算结果 |
例6:测试指令
1 | TST R1,#3 ;按位与,结果影响CPSR中的标志位 |
上述比较与测试指令可与带S后缀的算数逻辑运算指令对比,如TEQ与EORS对比,其运算操作一致,但运算指令保留结果,比较测试指令只修改CPSR中标志位,不保留运算结果。
例7:乘法指令
MUL:32位乘法
MLA:三操作数乘法,将操作数1与操作数2相乘,结果加第三个操作数,存入目的寄存器
1 | MLA Rd,Rm,Rs,Rn ;Rd <- Rm*Rs+Rn |
规则:Rd和Rm不能是同一寄存器
形成两个矢量的标量积的例子:
1 | mov r11,#20 ;r11 <- 20 |
2.2.3 数据交换指令
1 | SWP R1,R1[R0] ;需要中间人 |
2.3 跳转指令
跳转指令用于控制程序的走向,可完成从当前指令向前或向后的32MB的地址空间跳转,包括基本跳转指令(无条件跳转)B,带返回的跳转指令BL,带状态切换(ARM与Thumb之间)的跳转指令BX,带返回和状态切换的跳转指令BLX。
ARM指令地址间隔为4,Thumb指令地址间隔为2。
例:
1 | BL LABEL ;程序无条件跳转至LABEL处执行 |
跳转范围不受限制的方式:
1 | LDR PC,=LABEL |
BEQ:相等就跳
NEQ:不相等就跳
2.4 程序状态寄存器访问指令
当前程序状态寄存器可分为4个8位独立域:
1 | CPSR[31:24]:_f(标志域) |
例:清CPSR标志位,先读到寄存器里去再进行修改,修改完后用MSR指令赋值给标志位。
1 | MRS R0,CPSR ;R0 <- CPSR |