ARM指令集
由于RAM采用了流水线机制,当读取PC值时,该值为当前指令地址值加8,也就是PC指向当前指令的下2条指令。
由于RAM指令是4字节对齐的,所以PC值的第0位和1位始终为0
使用STR/STM保存R15时,保存的是当前指令地址加8字节或者12字节,所以对于用户来说,尽量避免使用STR/STM来保存R15的值
如果非要用STR/STM来保存R15,那可以这样判断是加8字节还是12字节:
SUB R0,PC, #4
STR PC, [R1]
LDR R0, [R0]
SUB R0, R1, R0
最后R0中的值就是offset偏移值
寄存器移位方式:
ASR: 算术右移 考虑正负符号,在移位过程中符号不变,适合 signed 类型
ASL: 算术左移
LSL: 逻辑左移 适合unsigned 类型
LSR: 逻辑右移 适合unsigned 类型
ROL: 循环左移
ROR: 循环右移
RRX: 扩展的循环右移
循环移位也容易理解。比如我们有个1字节的数: x = 10111110。现在需要对其循环右移4位。也就是最后结果为x = 11101011。其实思路就是分离数据,我们需要提取出前四位1011,后四位1110。其实我们需要两个数的或操作,也就是00001011,11100000,我们只要得到这两个数然后让他们就行或操作:00001011|11100000 =11101011。把10111110 右移4位变为00001011(x>>4),把10111110左移4位变为11100000(x<<4),注意移位后的“空格”是用0填充的。最后执行或操作。
循环左移n位: (x>>(N - n) ) | (x<<n);
循环右移n位: (x<<(N - n) ) | (x>>n)
Load指令用于从内存中读取数据放入寄存器;Store指令用于寄存器中的数据保存到内存中。
【】里面默认作加法运算:
LDR R0, [R1, R2, LSL #2] 意思是将(R1 + R2 << 2)的值存到寄存器R0中
LDR R0, [R1, #4]! 意思是将(R1 + 4)中的内容读到R0寄存器,同时R1 = R1 + 4
LDR R0, [R1], #4 意思是将R1寄存器中的值放入R0寄存器中,同时R1 = R1 + 4
LDR R0, [R1], R2, LSL #2 意思是将R1中的数据读取到R0中,同时R1 = R1 + R2 << 2
LDRSB R0, [R1,#3] 意思是将(R1 + 3)中的有符号数据读取到R0中,R0中高24位设置成该字节数据的符号位
位B用于控制指令操作的数据类型,=1时指令访问的是无符号的字节数据; =0时访问的是字数据
位S用于控制半字访问的数据类型,=1时数据为带符号数; =0时数据为无符号数
STRH R0, [R1,R2] 意思是将R0中的低16位数据保存到内存单元(R1 + R2)中
STRH R0,[R1], #8 意思是将R0中的低16位数据读取到R1中,R1 = R1 + 8
LDRH R0, [R1,R2]! 意思是将(R1 + R2)中的半字数据读取到R0中,R0高16位设置为0;R1 = R1 + R2
LDRSH R7, [R6, #2] 意思是将(R6 + 2)单元中的字节数据读取到R7中,R6中高16位设置成该半字的符号位;R6 = R6 + 2
IA : a++
IB : ++a
DA : a--
DB : --a
LDMIA R0, {R5 - R8} ; 将R0到(R0 + 12)寄存器中的值分别读取到R5 到 R8寄存器中
BL FUNC_1 ; 程序跳转到FUNC_1处执行,同时将当前PC值保存到LR中
BCC Lable ; 当CPSR寄存器中的C条件标志位为1时,程序跳转到Lable处执行
数据处理指令:
MVN 数据求反传送指令
CMP 比较指令
CMN 基于相反数的比较指令
CMP Rn, #0 ; (Rn) - 0没有发生借位。CPSR中的条件标志位C = 1
CMN Rn, #0 ; (Rn) + 0没有发生溢出,CPSR中的条件标志位C = 0
TST 位测试指令
TEQ 相等测试指令
RSB 逆向减法指令
RSB Rd, Rx, #0 ; Rd = 0 - Rx
RSB Rd, Rx, Rx, LSL #n ; Rd = Rx << n - Rx
ADC 带位加法指令
SBC 带位减法指令
RSC 带位逆向减法指令
AND 逻辑与操作
BIC 位清除指令
EOR 逻辑异或操作
ORR 逻辑或操作
SUBS R4, R0, R2
SBC R5, R1, R3
SUBS 和 SBC指令联合使用可以实现64位的操作数相减
R0中存放被减数的低32位,R2中存放减数的低32位,最后得到的结果是R4存放低32位,R5存放高32位
指令语法格式: SBC{<cond>} {S} <Rd> , <Rn> , <shifter_operand>
S决定指令的操作是否影响CPSR中的条件标志位的值: 有S时指令更新CPSR中的条件标志位,没有就不更新
同样,ADDS 和ADC联合使用可以实现64位操作数相加
ADDS R4, R0, R2
ADC R5, R1, R3
状态寄存器访问指令:
MRS 用于将状态寄存器的内容传送到通用寄存器
MSR 用于将通用寄存器的内容或一个立即数传送到状态寄存器
LDRB R0, [R2, #3] ; 将内存单元(R2 + 3)中的低8位数据读取到R0,R0中的高24位设置为0
LDRH R0, [R1, #3] ; 将(R1 + 3)中的低16位数据读取到R0中,R0中的高16位设置为0
LDRSB R0, [R2, #3] ; 将内存单元(R2 + 3)中有符号的字节数据读取到R0,R0中的高24位设置为该字节的符号位
LDRSH R0, [R1, #3] ; 将(R1 + 3)中的有符号的半字数据读取到R0中,R0中的高16位设置为该半字的符号位
LDRT 用户模式的字数据读取指令
STRT 用户模式的字数据写入指令
STRBT 用户模式的字节数据写入指令
乘法指令:
MUL 32位乘法指令
MLA 32位带加法乘法指令
SMULL 64位有符号数的乘法指令
SMLAL 64位有符号数带加法指令
UMULL 64位无符号数乘法指令
UMLAL 64位带加法的无符号数乘法指令
批量Load/Store指令:
SWP 交换指令
SWPB 字节交换指令
SWP R1, R2, [R3] ; 将(R3)中的字数据读取到R1中,同时将R2中的数据写入(R3)中
SWPB R1, R2, [R3] ; 将(R3)中的字节数据读取到R1中,R1中高24位置0,同时将R2中的低8位数据写入(R3)中
条件码:
EQ 相等
NE 不相等
CS/HS 无符号数大于/等于
CC/LO 无符号数小于
MI 负数
PL 非负数
VS 上溢出
VC 没有上溢出
HI 无符号数大于
LS 无符号数小于等于
GE 带符号数大于等于
LT 带符号数小于
GT 带符号数大于
LE 带符号数小于/等于
AL 无条件执行
NV 该指令从不执行
符号定义伪操作:
GBLA 全局的算术变量 初始化为0
GBLL 全局的逻辑变量 初始化为{FALSE}
GBLS 全局的串变量 初始化为空串“”
LCLA 局部的算术变量
LCLL 局部的逻辑变量
LCLS 局部的串变量
RLIST 给寄存器列表定义名称
Context RLIST {r0 - r6.r8,r10 - r12, r15}
CN 为一个协处理器的寄存器定义名称
数据定义伪操作:
SPACE 分配一块内存单元,并用0初始化,%是同义词
DCB 分配一段字节的内存单元,并用指定的数据初始化,=是同义词
DCD/DCDU 分配一段字的内存单元,并用指定的数据初始化, &是DCD同义词
DCDO 分配一段字的内存单元,并将这个单元的内容初始化为该单元相对于静态基值寄存器的偏移量
MAP 用于定义一个结构化的内存表的首地址,^是同义词
FIELD 用于定义一个结构化内存表的数据域,#是同义词
MAP 和 FIELD 仅仅是定义数据结构,并不实际分配内存单元
DCD与DCDU的区别在于DCDU分配的内存单元并不严格字对齐
汇编控制伪操作:
IF ELSE ENDIF
WHILE WEND
MACRO 标识宏定义的开始 MEND 标识宏定义的结束
MEXIT 用于从宏中跳转出来
信息报告伪操作:
ASSERT 汇编编译器对汇编程序的第二遍扫描中,如果logical expression条件不成立,打印错误信息
ASSERT logical expression
INFO 伪操作支持在汇编处理过程中的第一遍扫描或第二遍扫描时报告诊断信息
INFO numeric-expression, string-expression
如果 numeric-expression = 0 第二遍扫描打印信息;如果 numeric-expression != 0 第一遍扫描打印信息;
INFO 0, "Version 1.0"
IF endofdata <= label1
INFO 4, "Data overrun at label1"
ENDIF
OPT 通过OPT可以在源程序中设置列表选项
其他伪操作:
ALIGN: 对齐
ALIGN 2 按2^2 = 4字节对齐
AREA
CODE16 告诉汇编编译器后面的指令序列为16位的Thumb指令
CODE32 告诉汇编编译器后面的指令序列为16位的Thumb指令,它们本身并不进行程序状态的切换
EQU * 是同义词 类似于c语言中的#define
abcd EQU 2
addr1 EQU 0x1C, CODE32 ; 该处为ARM指令
EXPORT及GLOBLE
GET/INCLUDE include
INCBIN 包含编译好的文件,比如可执行文件
ARM汇编语言语句格式:
在ARM汇编语言中,指令不能从一行的行头开始,在一行语句中,指令的前面必须有空格或者符号
当程序中的符号与指令助记符或伪操作同名时,用双竖线符号括起来,如||require||,这时双竖线并不是符号的组成部分。