ARM-汇编指令
汇编指令简介
汇编指令是汇编语言中使用的一些操作符和助记符,还包括一些伪指令如.text,.end等,
同机器指令一一对应。每一种CPU都有自己的汇编指令集。
- 操作符:表示该指令应进行什么性质的操作:+、-、*、/…
- 助记符:描述指令功能和指令操作数的符号:MOV,ADD…
- 按指令作用对象来分,可分为伪指令和真指令(硬指令)。
- 伪指令也就是作用于汇编程序的命令;真指令就是作用于真正处理器的命令。
指令格式
指令是计算机能够识别和执行的操作命令,由二进制数“0”、“1”组成。每条指令的编码格式由机器指令系统规定。通常,一条指令一般包含操作码和操作数两部分。
- 操作码(Operation Code):用来说明指令操作的性质与功能,常用OP表示。操作码是指令中不可缺少的部分,通常由1~2个字节组成,机器通过译码电路(译码器)来识别指令。
- 操作数:用于提供指令中要处理的数据及数据所在的地址信息。
eg:MOV指令的格式为:MOV dst,src。
其中:MOV为指令助记符,表示传送;dst为目标操作数;src表示源操作数;该指令的功能是将源操作数传送到目标单元。
注:
- 伪操作:指导编译器对代码的编译,不占据内存空间。
eg:常见2种:(1)带点.的:.text 和 .end (2)标签label:_start:或者 loop : - 伪指令:不是作用于处理器的指令,而是编译器编译成多条指令以完成伪操作的指令。
- 汇编代码注释:
@
/* …*/
.text @伪指令,代表当前代码段
.globl _start @声明一个全局变量_start
_start: @汇编程序的入口
mov r0,#0x1 @汇编代码数据操作书写位置
loop: @死循环
b loop
.end @代表汇编程序的结束
编译器格式要求:预留一空行
汇编指令的常用操作
指令格式:
<OP指令操作名><条件码>[s:状态标志] Rd(目标寄存器), Rn(第一个临时寄存器), 立即数
注:op、条件码、s连起来写 空格 寄存器和立即数之间,逗号隔开
数据操作指令
MOV / MVN
有效数:包括立即数和取反后的立即数;有效数前面要加#号
指令操作名:不区分大小写,mov和MOV一样使用
寄存器编号:大小写也一样R0-R15
mov r0,#0x8
mov r1, r0
mov pc, #0x3 @验证ARM指令集中地址传给PC时低两位数据无效,始终为0。
mvn r2, #0x5 @0x5取反放入r2
mov R3, #0xFFFFFF00 @编译后有效数:mvn #0xFF
ldr r0, =0xFFF
立即数
算数运算指令
(1)add / adc
-
add:加法指令
add r0, #0x3
add r1, r0, #0x1 -
adc:带进位的加法指令
(2)sub/sbc
subs :状态标志
mov r0,#0x1
mov r1,#0x2
subs r3,r0,r1
(3)mul:乘法指令
乘法指令的第二个操作数只能是寄存器
mov r0, #0x2
mov r1, #0x3
mul r2, r1, r0 @正确
mul r3, #0x5 @错误,乘法指令的第二个操作数只能是寄存器
位操作汇编指令
- and:与
- orr:或
- eor:异或
- bic:位清除,把哪位清零就把哪位写1
bic r1,r0,#0x1F @把[4:0]位清零
比较指令cmp
跳转指令:b /bl
- b:不保存返回地址的跳转
- bl:保存返回地址的跳转
执行bl跳转时,R14:lr会保存返回地址
恢复现场:mov pc, lr
load / store 指令
单寄存器操作指令
ldr/str:针对的是一个寄存器
ldrb/strb:单个字节(8位Byte)指令操作
ldrh/strh:半字指令操作
将ldr/sdr与内、外存搬移联系,对初学者很容易不理解实质记混,有点死记硬背的感觉。其实:
不管是ldr/sdr操作的内存还是外存,只要是涉及寄存器操作的就是内存;牵扯到地址访问[rn]操作的就是外存(外部内存)。
ldr:有读操作(read)的意味
sdr:有写操作(write)的意味
注:读和写都是相对寄存器的角度来讲的。
- ldr(加载)
ldr rd , [rn] / 数值
加载(read 读):只能向寄存器中加载,而操作数的第一个参数必须是寄存器。故只能是把后面的数值加载到rd中
- str(存储)
str rd,[rn]
存储(write 写):把第一次操作数的内容 搬移(写)到 [rn]指向的地址中:[rn]也相当于*(rn->地址)
ldr r0,=0x40001000 @将=后面的数据加载到寄存器R0中
ldr r1,=0x12345678 @将=后面的数据加载到寄存器R1中
str r1,[r0] @将R1存储到*[r0]中
ldr r2,[r0] @将*[r0]中的内容加载到R2
ldrb R3,[R0] @ldrb将*[r0]中单个字节(低位)加载R3
str r1, [r0, #4] @将r1中的值存储到r0+4的地址空间中,r0值不变
str r2, [r0], #4 @将r2中的值存储到r0指向的地址空间中,之后寄存器中r0的值:r0 = r0 + 4
str r3, [r0, #4]! @将r2中的值存储到r0+4指向的地址空间中,之后寄存器中r0的值:r0 = r0 + 4
keil 5.0 内存映射读写设置
多寄存器操作指令
@ 栈的操作指令 stmfd ldmfd
@ 栈的种类
@ 1. 空栈(Empty)
@ 栈指针指向的地址是空的,
@ 在栈中存储数据时,可以直接存储,
@ 存储完成之后需要将栈指针再次指向
@ 空的位置。
@ 2. 满栈(Full)
@ 栈指针指向的地址有数据,
@ 在占中存储数据时,需要先将栈指针
@ 指向一个空的位置,然后在存储数据。
@ 3. 增栈(Ascending)
@ 栈指针向高地址方向移动
@ 4. 减栈(Descending)
@ 栈指针向低地址方向移动
@ 操作栈的方式有四种
@ 满增栈 满减栈 空增栈 空减栈
@ FA:Full Ascending 满增(FA)
@ FD:Full Descending 满减(FD)
@ EA:Empty Ascending 空增(EA)
@ ED:Empty Descending空减(ED)
@ ARM默认采用的是满减栈
@ stmfd/ldmfd<code> sp!, {寄存器列表}
@ 更新栈指针指向的地址空间
@ ldr sp, =0x40001020
@ ldr r1, =0x11111111
@ ldr r2, =0x22222222
@ ldr r3, =0x33333333
@ ldr r4, =0x44444444
@ ldr r5, =0x55555555
@ stmfd sp!, {r1-r5}
@ ldmfd sp!, {r6-r10}
/*
ldr sp, =0x40001020
mov r0, #0x1
mov r1, #0x2
bl add_func1
add r2, r0, r1 @ r2 = 0x3
b loop
add_func1:
@ 保存r0,r1,保存到栈
stmfd sp!,{r0-r1,lr}
mov r0, #0x3
mov r1, #0x4
bl add_func2
add r3, r0, r1 @ r3 = 0x7
@ 恢复r0,r1,
ldmfd sp!,{r0-r1,pc}
@ mov pc, lr
add_func2:
stmfd sp!,{r0-r1}
mov r0, #0x5
mov r1, #0x6
add r4, r0, r1
ldmfd sp!,{r0-r1}
mov pc, lr
*/
特殊功能寄存器操作指令
mrs:mov register -》 status
msr:mov status -》 register
@ 特殊功能寄存器操作指令 mrs msr
@ 对cpsr进行操作
@ mrs Rm, cpsr 将cpsr中的值写到Rm中
@ msr cpsr, Rm 将Rm中的值写到cpsr中
@ 从SVC模式切换到User模式
@ 10011 10000
@ 第一种方式
@ mov R0, #0xD0
@ msr cpsr, r0
@ msr cpsr, #0xD0
@ 第二种方式
@ 1. 先将cpsr中的值读到普通寄存器中
mrs r0, cpsr
@ 2. 修改普通的寄存器中的值
bic r0, r0, #0x1F
@ and r0, r0, #(~0x1F)
orr r0, r0, #0x10
@ 3. 将普通寄存器中的值写回到cpsr中
msr cpsr, r0
软中断指令
@ 软中断指令 swi
@ 格式swi 中断号
@ 中断号的范围 0-2^24-1
@ 按键中断,异常处理