基础的汇编指令
目录
1、接上一个csdn特殊功能寄存器
1.1CPSR寄存器
1.2SPSR寄存器
1.3CPSR寄存器的高四位和第四位 编辑
2、汇编指令的分类
3、汇编指令的基本格式
4、数据搬移指令(赋值指令)
4.1指令码
4.2指令格式
4.3测试代码
4.5立即数
4.6ldr伪指令
5、位移操作运算指令
5.1指令码
5.2指令格式
5.3测试代码
6.位运算操作指令
6.1指令码
6.2指令格式
6.3测试代码
6.4练习代码
7、算数运算指令
7.1指令码
7.2指令格式
7.3测试代码
1、接上一个csdn特殊功能寄存器
1.1CPSR寄存器
CPSR寄存器------the current program status register
CPSR寄存器的中文名是当前程序状态寄存器
CPSR寄存器的作用:用于保存当前程序的状态
1.2SPSR寄存器
SPSR寄存器-------the save program status register
SPSR寄存器的中文名字是备份程序状态寄存器
SPSR寄存器的作用:用于备份程序的状态
这张图展示了ARM处理器用户模式(USER)与中断请求模式(IRQ)之间的异常处理流程,核心是通过CPSR和SPSR寄存器实现模式切换与状态备份恢复,流程是1.先正常执行,此时处理器处于普通执行状态,使用用户模式的寄存器,CPSR寄存器记录当前程序的运行状态,2.触发异常用户代码执行中断事件,处理器会备份当前状态将CPSR寄存器的值保存到IRQ模式对应的SPSR中确保用户模式下不会丢失,3.开始处理异常代码,此时使用IRQ模式的寄存器组,独立于用户模式的寄存器,保证不会干扰用户代码的执行,4.从IRQ到USER模式异常处理完毕后处理器会从SPSR中备份的用户模式状态写会CPSR切换到USER模式继续执行后面的代码,
CPSR:记录当前模式下的程序状态(标志位、中断控制、处理器模式等),是实时状态的 “快照”。
SPSR:是异常模式(如 IRQ、FIQ)下的 “备份寄存器”,用于保存 ** 原模式(如 USER)** 的 CPSR 值,确保异常处理完成后能恢复原状态。
总结:这种机制保证了 ARM 处理器在处理异常时,既能及时响应中断,又能在处理完毕后准确回到原程序的执行上下文,是 ARM 架构 “多模式、高可靠性” 设计的核心体现。自我理解:可以这样理解触发异常事件是将CPSR中保存的值给SPSR,异常执行结束将SPSR中的值还原给CPSR回到user模式继续执行后面的代码
1.3CPSR寄存器的高四位和第四位

N【31】位:
负数标志位(用于比较两个数的大小)
当汇编指令的执行结果位负数时,N位会被硬件自动置为1;否则,清0;
Z【30】位:
零标志(用于比较两个数是否相等时)
当汇编指令的执行结果为0时,z位会被硬件自动置1否则;清0;C【29】位:
进位/借位标志位
当汇编指令的执行结果产生进位时,c位会被硬件自动置为1;否则清零(加法运算)
当汇编指令的执行结果产生借位时,C位会被硬件自动清零;否则置1(减法运算)
可以看后面的第八条
V【28】位:
溢出标志位/符号标志位
当汇编指令的执行结果对符号位产生变化时,v位会被硬件自动置1;否则,清零
I【7】位:
FRQ模式使能位/IRQ模式屏蔽位
I=1时,屏蔽IRQ模式(无法进入到IRQ模式下)
I=0时,不屏蔽FIQ模式(可以进入到FIQ模式下)
T【5】位:状态位/ARM状态屏蔽位
T=1时,屏蔽ARM状态(不适用ARM汇编指令集,默认使用Tumb汇编指令集)
T=0时,不屏蔽AMR状态(可以使用ARM汇编指令集)
M【4:0】位
模式位/工作模式位
CPSR寄存器的高四位由硬件控制,不需要认为更改
CPSR寄存器的第八位可以认为更改
M[4:0] -> 处理器模式
10000 -> User 模式
10001 -> FIQ 模式
10010 -> IRQ 模式
10011 -> Supervisor(SVC)模式
10110 -> Monitor(MON)模式
10111 -> Abort(ABT)模式
11010 -> Hyp(HYP)模式
11011 -> Undef(UND)模式
11111 -> System(SYS)模式
2、汇编指令的分类
基础汇编指令:
1、数据操作指令
1.1数据搬移指令(赋值指令=)
1.2移位运算指令(<<,>>)
1.3位运算指令(&,|,~,^)
1.4算术运算指令(+,-,*,/)
1.5比较指令(<,>,==,!=)
2、跳转指令
进阶汇编指令:
3、单寄存器内存读写指令
4、栈指针寄存器内存读写指令(包含了多寄存器内存读写指令)
5、CPSR特殊功能寄存器内存读写指令
6、swi软中断指令
3、汇编指令的基本格式
{opcode}{cond}{s} Rd,Rn, oprand_shifter2|
| | | | | |----------------->第二操作数(相当于右操作数)
| | | | | |----------------->第二操作数可以是:
| | | | | | 1、立即数
| | | | | | 2、普通寄存器
| | | | | | 3、经过移位的寄存器
| | | | |
| | | | |------------------第一操作寄存器(相当于左操作数)
| | | |------------目标寄存器,用于存放当前汇编指令的执行结果
| | |
| | |----------状态位,+s,当前汇编指令的执行结果会影响xpsr寄存器的nzcv位
| | 不+s,当前汇编指令的执行结果不会影响cpsr寄存器的nzcv位
| |----------条件码,用于让汇编指令的指令(在使用比较指令时会使用)
|
|----------------指令码,也就是汇编指令的名字
注意:
1、{opcode}{cond}{s}指令码、条件码,状态位连在一起写的,不允许出现空格
2、Rd,Rn,oprand_shifter2目标寄存器、第一操作寄存器、第二操作数连在一起写、但是需要使用逗号隔开
3、{opcode}{cond}{s} 和 Rd,Rn,oprand_shifter2 这两个部分中间需要用空格隔开
4、汇编指令指令么有以;结尾,所以一条汇编指令写一行
5、汇编指令没有大小写区分
mov r0,#0xff ==== MOV R0,#0xFF ====MoV r0,#0xFF这三句是一样的
6、在当前汇编文件中,使用的汇编器支持的注释方式:
6.1单行注释@(不同的编译器支持的注释方式不同,可能有;,#......)
6.2多行注释
/**/
.if 0/1 .else .endif
4、数据搬移指令(赋值指令)
4.1指令码
mov -------- 直接赋值指令
mvn ------ 按位取反后赋值
4.2指令格式
mov/mvn Rd,operand_shifter2
赋值指令时没有第一操作寄存器的,只有目标寄存器和第二操作数
4.3测试代码
.text
.global _start
_start:
mov r0,#oxff @解释:将0xff赋值到R0寄存器中
@如果使用赋值指令时,第二个操作数是一个立即数
@需要在他的前面加上#
mvn r1,#0xff @解释:将0xff全部按位取反后,赋值给r1寄存器
@r1=~(0xff)=0xffffff00
mov r2,#(-0xff) @-0xff(存储的补码,正数源码和补码是一致的,负责需要计算)
@源码:0x800000ff
@反码:0xffffff00
@补码:0xffffff01
stop:
b stop
.end
4.5立即数
以mov这条汇编指令为例,不同的汇编指令的立即数是不一样的
以mov r0, #0xff为例,一条汇编指令占四个字节的空间
立即数是指可以被指令直接编码、无需从内存或者寄存器读取的常数。它的核心特点是“能被指令格式直接表示“。
立即数的判断步骤:
1、确定带判断数a;
2、在0x00~0xff范围内找一个数b;
3、将b循环右移偶数位(0、2、4......30位),若结果等于a,则是立即数
eg:
0xff是否为立即数
在0x00~0xff中找到b=0xff;
将b循环右移32位(等价于右移0位,因为32是偶数),结果仍为0xff,因此0xff是立即数
0xfff是否是立即数
在0x00~0xff中找不到任何数循环右移等于0xfff的,所以0xfff不是立即数
有效数:如果一个数全部按位取反后,能够得到一个立即数,这个数就是一个有效数
有效数可以当做立即数使用
4.6ldr伪指令
ldr伪指令可以实现0x00000000~0xffffffff之间任意数的赋值操作
指令格式:ldr Rd,=任意数
如果以后遇到一个数,不知道是否是立即数,可以直接使用ldr进行赋值操作
eg:
ldr r0,=0x12345678
5、位移操作运算指令
5.1指令码
lsl-------逻辑左移/无符号位 ------ 高位移出,低位补0
lsr------- 逻辑右移/无符号数右移 ------低位移出,高位补0ror ------ 循环右移 ------ 低位移出,补到高位
asr ----- 算数右移/有符号数右移 ----低位移出,高位补符号位
5.2指令格式
lsl/lsr/ror/asr Rd, Rn, oprand_shifter2
5.3测试代码
/***********************2、移位运算指令**************************/ /*
mov r0, #0xff
lsl r1, r0, #8 @ 将r0寄存器中的值逻辑左移8位后赋值给r1寄存器
@ r1 = r0 << 8 = 0xff00
lsr r2, r1, #12 @ 将r1寄存器中的值逻辑右移12位后赋值给r2寄存器
@ r2 = r1 >> 12 = 0xf
ror r3, r2, #4 @ 将r2寄存器中的值循环右移4位后赋值给r3寄存器
@ r3 = 0xf0000000
asr r4, r3, #4 @ 将r3寄存器中的值算术右移4位后赋值给r4寄存器
@ r4 = 0xff
@ 高位补符号位指的是所有高位都需要补符号位,而不是只有最高位补符号位
*/ /***********************2、第二操作数的所有情况**************************/
@ 第二操作数可以是一个立即数
mov r0, #0xff @ 解释:将0xff赋值给r0寄存器中
@ 第二操作数可以是一个普通寄存器
mov r1, r0 @ 解释:将r0寄存器中的值赋值给r1寄存器中
@ 第二操作数可以是一个经过移位的寄存器
mov r2, r1, lsl #4 @ 解释:将r1寄存器中的值逻辑左移4位后赋值给r2寄存器
@ 上述汇编指令的作用和这条lsl r2, r1, #4汇编指令的作用是一致的
6.位运算操作指令
6.1指令码
and --- 按位与(&)
orr --- 按位或(|)
eor --- 按位异或(^)mvn --- 按位取反(~)
口诀:
与0清0,与1不变
或1置1,或0不变
异或1取反,异或0不变
6.2指令格式
and/orr/eor/mvn Rd, Rn, oprand_shifter2
6.3测试代码
/***********************4、位运算操作指令**************************/
@ 32位数:
@ 31 0 @ **** **** **** **** **** **** **** ****
mov r0, #0xff
@ 目的:将r0寄存器中的第[3]位清0,其他位不变,最后赋值给r0寄存器
@ c语言写法:r0 = r0 & (~(0x1 << 3))
and r0, r0, #(~(0x1 << 3)) @ r0 = 0xf7
@ 目的:将r0寄存器中的第[3]位置1,其他位不变,最后赋值给r0寄存器
orr r0, r0, #(0x1 << 3)
6.4练习代码
@假设你不知道r0寄存器中的值
ldr r0, =0x12345678
@ 31 0
@ **** **** **** **** **** **** **** ****
@ 1> 将r0寄存器的第[3]位清0,保持其他位不变
and r0, r0, #(~(0x1 << 3))
@ 2> 将r0寄存器的第[29]位置1,保持其他位不变
orr r0, r0, #(0x1 << 29)
@ 3> 将r0寄存器的第[7:4]位清0,保持其他位不变
and r0, r0, #(~(0xf << 4))
@ and r0, r0, #(~(0b1111 << 4))
@ 4> 将r0寄存器的第[15:8]位置1,保持其他位不变
orr r0, r0, #(0xff << 8) @ orr r0, r0, #(0x0000ff00)
@ 5> 将r0寄存器的第[3:0]位按位取反,保持其他位不变
eor r0, r0, #(0xf << 0)
@ 6> 将r0寄存器的第[11:4]位修改为10101011,保持其他位不变
@ 推荐使用先清0再置1
and r0, r0, #(~(0xff << 4))
orr r0, r0, #(0b10101011 << 4) @ orr r0, r0, #(0xab << 4)
@ 也可以先置1再清0
orr r0, r0, #(0xab << 4)
and r0, r0, #(~(0x54 << 4))
7、算数运算指令
7.1指令码
add -----基础加法指令(不涉及CPSR寄存器中的c位的使用)
adc-------进阶加法指令(涉及CPSR寄存器中的c位使用)
sub--------基础减法指令(不涉及CPSR寄存器中的c位的使用)
sbc------进阶减法指令(涉及CPSR寄存器中的c位使用)
mul-------- 乘法指令
div-------除法指令(使用除法指令需要架构ARM-V8架构之上)
7.2指令格式
add/adc/sub/abc/mul/div Rd,Rn,oprand_shifter2
7.3测试代码
mov r1, #0x1
mov r2, #0x3
add r3, r1, r2 @r3=0x1+0x3=0x4
sub r4, r2, r1 @r4=0x3-0x1=0x2
@模拟两个64位数相减
@r1寄存器存放第一个64位数的高32位,r2寄存器存放第一个64位数的低32位
@r3寄存器存放第二个64位数的高32位,r4寄存器存放第二个64位数的低32位
@r5寄存器中存放相减后的高32位数,r6寄存器存放相减后的低32位数
mov r1, #0x5
mov r2, #0x2
mov r3, #0x1
mov r4, #0x8
@先低位相减
subs r6, r2, r4 @此时需要使用到s状态位
@由于当前指令的执行结果产生了借位
@并且高32位运算时,需要用到产生借位后的c位
@r6=r2-r4=0x2-0x8=0x2-0x2-0x6=0x0-0x6=0x0-0x1-0x5
@=0xffffffff-0x5=0xfffffffa
注:-1 mod 2³² = 2³² - 1 = 0xffffffff
(因为0xffffffff + 1 = 0x100000000
,对 2³² 取模后等于 0)。同样也可以这样理解当你10-1的时候是不是等于九是不是个位数里面最大的数同理当你0x0-0x1时也是一样的等于最大值0xffffffff
sbc r5, r1, r3 此时需要使用到sbc
由于此处高32位相减时,需要使用到产生借位后的位
r5= r1- r3- C位(注:无论是进位还是借位的c位都是0x1)
r5=r1-r3-c位=0x5-0x1-0x1=0x3
注意:不管C位存放的是0/1
只要c位产生了借位,就需要多减一个0x1
只要c位产生了进位,就要多加一个0x1
注:为什么加s,subs中的s是为了强制更新 CPSR 的借位标志(C 位),让后续的高位运算能正确处理低 32 位产生的借位,当指令后加s
(即 “set flags”)时,会在执行运算后自动更新 CPSR 的关键标志位(N、Z、C、V 等),其中:C 位(进位 / 借位标志):对于减法,C=0
表示有借位,C=1
表示无借位,这是 64 位减法中处理高位运算的核心依据。
@模拟两个64位数相加
@r1寄存器存放第一个64位数的高32位,r2寄存器存放第一个64位数的低32位
@r3寄存器存放第二个64位数的高32位,r4寄存器存放第二个64位数的低32位
@r5寄存器中存放相加后的高32位数,r6寄存器存放相加后的低32位数
mov r1, #0x1mov r2, #0xfffffffe
mov r3, #0x2
mov r4, #0x4
adds r6, r2, r4 r6=0xfffffffe+0x4=0xfffffffe+0x1+0x3=0xfffffffff+0x3
=oxffffffff+0x1+0x2=0x0+0x2=0x2
注:可以这样理解当9+1的时候是不是等于十是不是十位数里面最小的数同理当你0xffffffff+0x1时也是一样的等于0x0
adc r5, r1, r3 r5=r1+r3+c位=0x1+0x2+0x1=0x4
注:为什么加c位是因为发生了进位上面已经解释了。