汇编语言的组成
- 伪操作
- 不参与程序执行,但是用于告诉编译器程序怎么编译
.text .global .end .if .else .endif .data
- 汇编指令
- 编译器将一条汇编指令编译成一条机器码,在内存里一条指令占4字节内存,一条指令可以实现一个特定的功能
- 伪指令
- 不是指令,看起来像是一条指令,可以实现和指令类似的功能。一条伪指令实际上可能是由多条指令共同实现
- 注释
- 条件编译
.if 0
@text
.else
@text
.endif
汇编指令的介绍
- 基本数据操作指令
- 数据搬移指令:=
- 数据位移指令:<< >>
- 数据算数运算指令:+ - * /
- 位运算指令:$ |~ ^
- 数据比较指令:
- 跳转指令
- 内存读写指令
- 状态寄存器读写指令
- 软中断指令
汇编指令的基本语法格式
基本格式: <opcode>{cond}{s} Rd,Rn,#oprand2
解释:
opcode:指令码
cond:条件码
指令不加条件码,指令默认无条件执行
指令加条件码,指令有条件执行
s:状态位
指令不加s,指令执行的结果不会影响CPSR寄存器
指令加s,指令执行的结果会影响CPSR寄存器
Rd:目标寄存器
Rn:第一操作寄存器
#oprand2:第二操作数
1)立即数
2)有效数:将一个数取反之后,变成立即数
3)寄存器
4)经过移位的寄存器
注意事项:
1)汇编指令中不区分大小写
2)汇编指令不需要以;号结尾
3)<opcode>{cond}{s}:需要连在一起写
4)Rd,Rn,#oprand2:需要用逗号分隔开
5) <opcode>{cond}{s}和Rd,Rn,#oprand2需要用空格分隔开
数据搬移指令
- 指令码:
mov mvn
- 格式:
<opcode>{cond}{s} Rd,#oprand2
@代码1:
mov r0,#0xf @ r0 = 0xf
mov r1,#0xff
@ mov r2,#0xfff @ error
@ mov r3,#0xffff @ error
@ mov r4,#0xfffff @ error
mov r5,#0xffffff
mov r6,#0xfffffff
mov r7,#0xffffffff
/*------------------ ------------------ ---------------*/
@ 代码2:
mvn r5,#0xff @ 0xff按位取反之后,赋值给r5
mov r0,#0xff000000 @ 0xff 8
mov r1,#0x1f800000 @ 0x7e 10
mov r2,#0x00ffffff @ ~r2 = 0xff000000
mov r3,#0x0fffffff @ ~r3 = 0xf0000000
mov r4,#0xffffffff @ ~r4 = 0x00000000
立即数判断
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/d07b26e32d809a8ba6513e5d96a8316d.png#pic_center)
- 立即数就是队#号后面的这个数有要求
- 首先要从你判断的这个数中间找到0~0xff之间的数(需要将要判断的这个数所有的1包含)
- 将找到的这个0~0xff之间的数,循环右移偶数位(低位移出,补到高位)
- 如果能够得到你要判断的那个数,说明你这个数是一个立即数
示例代码
要判断的数:0xf
0000 0000 0000 0000 0000 0000 0000 1111
找到0~0xff: 0xf
0000 0000 0000 0000 0000 0000 0000 1111
循环右移位数:0
是否为立即数:是
要判断的数:0xff
0000 0000 0000 0000 0000 0000 1111 1111
找到0~0xff:
0xff
循环右移位数:
0
是否为立即数:是
要判断的数:0xfff
0000 0000 0000 0000 0000 1111 1111 1111
找到0~0xff:
不能
循环右移位数:
是否为立即数:不是
要判断的数:0xf000000f
1111 0000 0000 0000 0000 0000 0000 1111
找到0~0xff:
0xff
0000 0000 0000 0000 0000 0000 1111 1111
循环右移位数:4
是否为立即数:是
要判断的数:0xff000000
1111 1111 0000 0000 0000 0000 0000 0000
找到0~0xff:
0xff
0000 0000 0000 0000 0000 0000 1111 1111
循环右移位数:8
是否为立即数:是
要判断的数:0x1fe00000
0001 1111 1110 0000 0000 0000 0000 0000
找到0~0xff:
0xff
0000 0000 0000 0000 0000 0000 1111 1111
循环右移位数:11
是否为立即数:不是
要判断的数:0x1f800000
0001 1111 1000 0000 0000 0000 0000 0000
找到0~0xff:
0x7e
0000 0000 0000 0000 0000 0000 0111 1110
循环右移位数:10
是否为立即数:是
伪指令(将非立即数保存至寄存器中)
伪指令:
LDR 目标寄存器,=数值
将指定的数据放在目标寄存器中
ex:LDR r1,=0X12345678
移位操作指令
- 格式:
<opcode>{cond}{s} Rd,Rn,#oprand2
- 指令码
lsl
:逻辑左移 高位移出,低位补0lsr
:逻辑右移 低位移出,高位补0asr
:算数右移 有符号数右移,低位移出,高位补符号位ror
:循环右移 低位移出,补到高位
示例
mov r0,#0xff
@1.将0xff逻辑右移4位,并存入r1寄存器中
lsr r1,r0,#0x4 @ r1 = r0 >> 4 = 0xf
@ 0000 0000 0000 0000 0000 0000 1111 1111
@ 0000 0000 0000 0000 0000 0000 0000 1111
@2.将r1逻辑左移4位,并存入r2寄存器中
lsl r2,r1,#0x4 @ r2 = r1 << 4 = 0xf0
@ 0000 0000 0000 0000 0000 0000 0000 1111
@ 0000 0000 0000 0000 0000 0000 1111 0000
ldr r3,=0x800000f0
@将r3寄存器中的值,算数右移4位,并存入r4寄存器中
asr r4,r3,#0x4 @ r4 = 0xf800000f
@ 1000 0000 0000 0000 0000 0000 1111 0000
@ 1111 1000 0000 0000 0000 0000 0000 1111
@将r4寄存器中的值,循环右移4位,并存入r5寄存器中
ror r5,r4,#0x4 @ r5 = 0xff800000
@ 1111 1000 0000 0000 0000 0000 0000 1111
@ 1111 1111 1000 0000 0000 0000 0000 0000
位运算指令
- 格式:
<opcode>{cond}{s} Rd,Rn,#oprand2
- 口诀:看到清零用& 看到置1用|
and:按位与(&)------>与0清0,与1不变
orr:按位或(|) ------>或0不变,或1置1
eor:按位异或(^) ------>异或0不变,异或1取反
bic:按位清除 ------> 哪一位写1,对应的位进行清0
示例
ldr r0,=0x12345678
@ 1> 将R0寄存器中的第[4]位清0,保持其他位不变
bic r1,r0,#(0x1 << 4)
and r1,r0,#(~(0x1 << 4))
@ 2> 将R0寄存器中的第[7]位置1,保持其他位不变
orr r2,r0,#(0x1 << 7)
@ 3> 将R0寄存器中的第[31:28]位清0,保持其他位不变
bic r0,#(0xf << 28)
and r0,#(~(0xf << 28))
@ 4> 将R0寄存器中的第[7:4]位置1,保持其他位不变
orr r0,#(0xf << 4)
@ 5> 将R0寄存器中的第[15:11]位修改为10101,保持其他位不变
@ 先置1,在清0
orr r0,#(0x1f << 11)
and r0,#(~(0x1 << 12))
and r0,#(~(0x1 << 14))
@ 先清0,在置1 ----->重点掌握
and r0,r0,#(~(0x1f << 11))
orr r0,r0,#(0x15 << 11)
算数运算指令
指令码:add adc sub sbc mul
基本格式: <opcode>{cond}{s} Rd,Rn,#oprand2
add: 普通加法指令
adc:带进位加法指令
sub:普通减法指令
sbc:带借位减法指令
mul:乘法指令 格式:<opcode>{cond}{s} Rd,Rn
示例
1.ADD:加法
ex1: mov r1,#1
mov r2,#2
add r3,r1,r2@r3=r1+r2
ex:
mov r1,#0XFFFFFFFE
mov r2,#2
addS r3,r1,r2@r3=r1+r2 @运算的结果影响到条件位
2.SUB
mov r1,#0XFFFFFFFE
mov r2,#2
sub r3,r1,r2@r3=r1-r2
ex2:
mov r1,#0XFFFFFFFE
mov r2,#2
subs r3,r2,r1@r3=r2-r1
3.ADC
mov r1,#0XFFFFFFFE
mov r2,#2
ADDS r3,r2,r1 @r3=r1+r2
ADC R4,R2,#3 @R4=R2+3+cpsr(C位) 6
4.sbc:减法运算考虑条件位
mov r1,#0XFFFFFFFE
mov r2,#2
SUBS r3,r2,r1 @r3=R2-R1 4
sbC R4,R1,#3 @R4=R1-3-CPSR(C位取反)
64位数据进行算术运算
原则:
一个 64位数保存在两个寄存器
高32位运算,低32位运算
mov r1,#0XFFFFFFFE @保存第一个数据的低32位
mov r2,#2@保存第一个数据的高32位
mov r3,#3 @保存第二个数据的低32位
mov r4,#4 @保存第2数据的高32位
@低32位运算要求影响条件位
ADDS R5,R1,R3@R5保存运算后结果的低32位
ADC R6,R2,R4@R6寄存器保存运算结果的高32位,需要考虑条件位
比较指令
指令码:cmp
基本格式: <opcode>{cond} Rn,#oprand2
1)比较指令没有目标寄存器
2)比较指令本质做减法运算
3)比较指令的执行结果会影响CPSR寄存器的NZCV位,不需要加s
4)比较指令需要和条件码搭配使用
5)前面所有学习的指令都属于无条件指令,比较指令属于有条件执行
/*
比较两个数大小
第一个数比第二个数大:第一个数减第二个数
第一个数比第二个数小:第二个数减第一个数
*/
mov r0,#0x3
mov r1,#0x4
cmp r0,r1
subhi r0,r0,r1 @ r0 = r0 - r1
subcc r1,r1,r0 @ r1 = r1 - r0
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/53c8a39e063755f5b3733dfb1e04e4cd.png#pic_center)
跳转指令
指令码:b
格式:b {cond} 标签
b指令码:有去无回,不会保存函数的返回地址到LR寄存器中
-------------------
b loop
-------------------
loop:
-------------------
/****************************************************/
指令码: bl
格式:bl{cond} 标签
bl指令码:有去有回,会保存函数的返回地址到LR寄存器中
-------------------
bl loop
------------------- ----->会保存函数的返回地址到LR寄存器中
loop:
-------------------
示例
mov r0,#0x1
mov r1,#0x2
bl add_func @ 跳转到add_func标签下第一条指令执行
mov r3,#0x3
b stop
add_func:
add r0,r0,r1
mov pc,lr @手动恢复现场 pc = lr