当前位置: 首页 > news >正文

基础的汇编指令

目录

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-------  逻辑右移/无符号数右移 ------低位移出,高位补0

ror  ------ 循环右移        ------   低位移出,补到高位

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, #0x1

mov 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位是因为发生了进位上面已经解释了。

http://www.dtcms.com/a/358692.html

相关文章:

  • 如何快速了解项目管理基础
  • 【机器学习入门】4.1 聚类简介——从“物以类聚”看懂无监督分组的核心逻辑
  • destoon8.0使用post插入keyword热搜到表
  • 深入理解shared_ptr与循环引用问题
  • 超越传统SEO:用生成引擎优化(GEO)驱动下一轮增长
  • 【蓝桥杯 2024 省 Python B】缴纳过路费
  • Markdown 文件编辑基础教程
  • 基于YOLO8的垃圾识别检测系统(数据集+源码+文章)
  • 【开题答辩全过程】以 线上游戏商城为例,包含答辩的问题和答案
  • Java学习day_14之API(正则表达式)
  • 【LeetCode】大厂面试算法真题回忆(121) —— 经典屏保
  • 嵌入式Linux驱动开发:蜂鸣器驱动
  • 图解LLM(AI大模型)的工作原理
  • SRE命令行兵器谱之二:lsof - 解密“端口被占用”与“文件句柄泄漏”的终极侦探
  • 吴恩达机器学习作业九:kmeans聚类
  • php电子签名
  • 2025年09月计算机二级MySQL选择题每日一练——第十二期
  • Rust 登堂 之 Sized和不定长类型 DST(七)
  • LabVIEW 时间字符串处理与显示
  • 继电器的作用、选型和测量-超简单解读
  • 算法题(195):点名
  • 【学Python自动化】 2. Windows Python 解释器使用笔记
  • 【shell】Shell脚本中的if判断条件和文件测试操作符
  • “人工智能+”政策驱动下的技术重构、商业变革与实践路径研究 ——基于国务院《关于深入实施“人工智能+”行动的意见》的深度解读
  • STM32的内存分配与堆栈
  • Redis 测试:过期 key 内存释放情况
  • JVM架构图是怎样的?
  • 算法(④KMP)
  • SpringAI应用开发工程师高阶面试剧本与知识点全解析(含RAG、多租户、流式推理、企业落地场景)
  • Python3 lambda(匿名函数)