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

[ARM][汇编] 02.ARM 汇编常用简单指令

目录

1.数据传输指令

MRS - Move from Status Register

指令用途

指令语法

代码示例

读取 CPSR 到通用寄存器

在异常处理程序中读取 SPSR

使用场景

MSR - Move to Status Register

指令语法

使用场景

示例代码

改变处理器模式为管理模式

设置条件标志位

异常处理结束后恢复状态

禁用IRQ中断

注意事项

LDR - Load Register

基本概念

语法格式(寻址方式)

立即数偏移寻址

寄存器偏移寻址

文字池寻址

使用场景

注意事项

STR - Store Register

基本概念

语法格式(寻址方式)

立即数偏移寻址

寄存器偏移寻址

使用场景

注意事项

PUSH

指令功能

语法结构

使用场景

代码示例

代码解释

注意事项

POP

指令功能

语法结构

使用场景

代码示例

代码解释

注意事项

2.数据处理指令

BIC - Bit Clear

指令语法

操作原理

使用场景

示例代码

清除寄存器中特定的位

清除标志位并更新条件标志

ORR - Logical Inclusive OR

指令语法

操作原理

使用场景

示例代码

设置寄存器中特定的位

设置标志位并更新条件标志

ADD - Add

指令功能

语法结构

使用场景

代码示例

注意事项

ADDS - Add

指令功能

语法结构

使用场景

代码示例

注意事项

SUB - Subtract

指令功能

语法结构

使用场景

代码示例

注意事项

SUBS - Subtract

基本功能

语法结构

寄存器 - 寄存器形式

寄存器 - 立即数形式

使用场景

示例代码

注意事项

3.分支跳转指令

B - Branch

基本概念

语法格式

使用场景

注意事项

BX - Branch and Exchange

基本功能

语法结构

指令集切换规则

使用场景

代码示例

代码解释

注意要点

BL - Branch with Link calls

基本概念

语法格式

工作原理

使用场景

示例代码

注意事项

BLX - Branch with Link and Exchange

基本功能

语法格式(寻址方式)

立即数寻址

寄存器寻址

使用示例

指令用途

4.协处理器指令

MRC - Move Register from Coprocessor

指令功能

语法结构

使用场景

代码示例

代码解释

注意事项

MCR - Move to Coprocessor Register

指令功能

语法结构

使用场景

代码示例

代码解释

注意事项

5.功能指令

CPSID - Change Processor State (Interrupt Disable)

基本功能

语法结构

使用场景

代码示例

代码解释

注意事项

CPSIE - Change Processor State(Interrupt Enable)

基本功能

语法结构

使用场景

代码示例

代码解释

注意事项

CPS - Change PE State

指令功能

语法结构

使用场景

代码示例

代码解释

注意事项

DSB - Data Synchronization Barrier

指令功能

语法结构

使用场景

代码示例

代码解释

注意事项

ISB - Instruction Synchronization Barrier

指令功能

语法结构

使用场景

代码示例

代码解释

注意事项


1.数据传输指令

MRS - Move from Status Register

MRS(Move from Status Register)指令用于将程序状态寄存器(CPSR,Current Program Status Register)或备份程序状态寄存器(SPSR,Saved Program Status Register)中的值传送到通用寄存器中。

指令用途

在 ARM 架构里,CPSR 包含了当前处理器的状态信息,例如条件标志位、中断使能位、处理器模式等。

SPSR 则是在异常发生时,用于保存 CPSR 的备份寄存器,以便异常处理完成后能恢复处理器的状态。

MRS 指令可让用户读取这些状态寄存器的值,进而依据处理器状态开展相应的操作,比如在编写异常处理程序时,就需要读取 SPSR 来恢复异常发生前的处理器状态。

指令语法

MRS {cond} Rd, <psr>
  • {cond}:可选的条件码,用于指定指令执行的条件。只有当条件码满足时,指令才会执行。像 EQ(相等)、NE(不相等)等。

  • Rd:目标寄存器,用于存放从状态寄存器中读取的值。

  • <psr>:状态寄存器,可以是 CPSR 或者 SPSR_<mode>,其中 <mode> 表示处理器模式,如 SVC(管理模式)、IRQ(中断模式)等。

代码示例

读取 CPSR 到通用寄存器
MRS R0, CPSR ; 将 CPSR 的值读取到寄存器 R0 中

这个例子里,MRS 指令把 CPSR 的值传送到寄存器 R0 中,之后就可以操作 R0,从而检查处理器的状态。

在异常处理程序中读取 SPSR
; 假设当前处于中断处理模式
MRS R1, SPSR_IRQ ; 将 SPSR(中断模式)的值读取到寄存器 R1 中

异常处理程序中,借助 MRS 指令读取 SPSR 的值,就能够获取异常发生前的处理器状态,方便后续恢复。

使用场景

  • 异常处理:在异常处理程序开始时,使用 MRS 指令读取 SPSR 的值,以保存异常发生前的处理器状态。异常处理结束时,再通过 MSR(Move to Status Register)指令将保存的状态写回到 CPSR 中,以此恢复处理器状态。

  • 状态检查:通过读取 CPSR 的值,能够检查处理器的条件标志位(如 N、Z、C、V),进而判断之前的运算结果,实现条件分支等操作。

MSR - Move to Status Register

MSR(Move to Status Register)指令用于将通用寄存器里的值或立即数,写入程序状态寄存器(CPSR)或备份程序状态寄存器(SPSR)。

指令语法

MSR {cond} <psr_fields>, <Rm | #immed_8r>
  • {cond}:可选的条件码,指令只有在条件码满足时才会执行。常见条件码有 EQ(相等)、NE(不相等)、GT(大于)等。

  • <psr_fields>:规定了要写入状态寄存器的位域,有以下几种情况:

    • cpsr 或 spsr:对整个状态寄存器进行操作。

    • cpsr_f 或 spsr_f:仅操作标志位域(N、Z、C、V)。

    • cpsr_c 或 spsr_c:操作控制位域(像处理器模式、中断使能位)。

    • cpsr_x 或 spsr_x:操作扩展位域。

    • cpsr_s 或 spsr_s:操作状态位域。

  • <Rm | #immed_8r>:可以是通用寄存器(如 R0 - R15),也可以是 8 位的立即数(#immed_8r)。

使用场景

  • 异常处理:异常处理程序结束时,需要把之前保存的 SPSR 值写回 CPSR,以恢复处理器在异常发生前的状态。

  • 中断控制:通过设置 CPSR 里的中断使能位(I 和 F),能够开启或者关闭中断。

  • 处理器模式切换:根据需求把处理器切换到不同的模式,例如用户模式、系统模式、管理模式等。

示例代码

改变处理器模式为管理模式
; 将处理器模式设置为管理模式(SVC),同时禁用 IRQ 和 FIQ 中断
MOV R0, #0xD3  ; 0xD3 对应的二进制为 11010011; 其中 10011 表示管理模式,I = 1(禁用 IRQ),F = 1(禁用 FIQ)
MSR CPSR_c, R0 ; 将 R0 的值写入 CPSR 的控制位域
设置条件标志位
MOV R1, #0x10  ; 准备一个值用于设置标志位
MSR CPSR_f, R1 ; 将 R1 的值写入 CPSR 的标志位域
异常处理结束后恢复状态
; 假设异常处理结束,恢复状态
MRS R2, SPSR_IRQ  ; 读取 SPSR(中断模式)的值到 R2
MSR CPSR_cxsf, R2 ; 将 R2 的值写回到 CPSR,恢复状态
禁用IRQ中断
; 禁用 IRQ 中断
MOV R3, #0x80  ; 0x80 对应的二进制为 10000000,I 位为 1
MSR CPSR_c, R3 ; 将 R3 的值写入 CPSR 的控制位域,禁用 IRQ 中断

注意事项

  • 权限问题:修改 CPSR 或 SPSR 一般需要特定权限,通常只有在特权模式下才能操作。

  • 位域选择:明确指定要操作的位域,防止意外修改其他重要的状态信息。

  • 影响范围:对状态寄存器的修改会立即影响处理器的行为,例如改变中断使能位可能会导致中断响应的变化。

LDR - Load Register

LDR(Load Register)指令用于从内存中读取数据到寄存器

基本概念

LDR 指令的核心功能是把内存中的数据加载到指定的寄存器中。

计算机系统中,数据通常存储在内存中,而处理器要对这些数据进行操作,就需要先把数据从内存加载到寄存器里。LDR 指令正是实现此类数据传输的关键指令。

语法格式(寻址方式)

LDR 指令有多种语法格式(寻址方式),常见的如下:

  • 立即数偏移寻址:适用于偏移量固定的情况。例如,从数组中按固定偏移量读取元素。

  • 寄存器偏移寻址:适用于偏移量动态变化的情况。例如,通过循环变量来访问数组元素。

  • 文字池寻址:常用于加载常量或者全局变量的地址。

立即数偏移寻址
LDR <Rt>, [<Rn>, #<offset>]
  • <Rt>:目标寄存器,用于存放从内存中读取的数据。

  • <Rn>:基地址寄存器,包含内存操作的基地址。

  • #<offset>:立即数偏移量,它会和基址寄存器的值相加,得到最终的内存地址。

代码示例:

    MOV R0, #0x1000  ; 设置基地址LDR R1, [R0, #4] ; 从地址 0x1004 处读取数据到 R1 寄存器
寄存器偏移寻址
LDR <Rt>, [<Rn>, <Rm>]
  • <Rt>、<Rn> 含义同上。

  • <Rm>:偏移寄存器,其值会和基址寄存器的值相加,得到最终的内存地址。

代码示例:

    MOV R0, #0x1000  ; 设置基地址MOV R2, #4       ; 设置偏移量LDR R1, [R0, R2] ; 从地址 0x1004 处读取数据到 R1 寄存器
文字池寻址
LDR <Rt>, =<expr>
  • <Rt>:目标寄存器。

  • <expr>:表达式,可以是一个常量或者标号。这种寻址方式会在文字池中查找 expr 的地址,并将该地址处的数据加载到目标寄存器中。

代码示例:

LDR R0, =0x1234  ; 将常量 0x1234 的地址处的数据加载到 R0 寄存器

使用场景

  • 读取数组元素:在处理数组时,可使用 LDR 指令按索引读取数组中的元素。

  • 访问全局变量:通过 LDR 指令读取全局变量的值。

  • 加载常量:使用文字池寻址加载常量到寄存器中。

注意事项

  • 内存访问权限:要确保目标内存地址具有可读权限,否则会导致内存访问错误。

  • 寻址方式选择:根据具体需求选择合适的寻址方式,不同的寻址方式适用于不同的场景。

  • 数据类型:LDR 指令默认加载 32 位数据。如果需要加载 8 位或 16 位数据,可以使用 LDRB(加载字节)或 LDRH(加载半字)指令。

STR - Store Register

STR(Store Register)指令用于将寄存器中的数据存储到内存中的指令,与 LDR 指令的加载功能相对。

基本概念

计算机系统中,处理器对数据进行运算和处理时通常在寄存器中操作,但最终结果可能需要保存到内存里。STR 指令的作用就是把寄存器中的数据存储到指定的内存地址,从而实现数据从寄存器到内存的传输。

语法格式(寻址方式)

STR 指令有多种常见的语法格式:

  • 立即数偏移寻址:适用于偏移量固定的情况。例如,将数据存储到数组中固定的位置。

  • 寄存器偏移寻址:适用于偏移量动态变化的情况。例如,通过循环变量将数据依次存储到数组的不同元素中。

立即数偏移寻址
STR <Rt>, [<Rn>, #<offset>]
  • <Rt>:源寄存器,里面存放着要存储到内存的数据。

  • <Rn>:基地址寄存器,包含内存操作的基地址。

  • #<offset>:立即数偏移量,它会和基地址寄存器的值相加,得到最终的内存地址。

代码示例:

MOV R0, #0x1000  ; 设置基地址
MOV R1, #0xABCD  ; 将数据 0xABCD 存入 R1 寄存器
STR R1, [R0, #4] ; 将 R1 中的数据存储到地址 0x1004 处
寄存器偏移寻址
STR <Rt>, [<Rn>, <Rm>]
  • <Rt>、<Rn> 的含义同上。

  • <Rm>:偏移寄存器,其值会和基址寄存器的值相加,得到最终的内存地址。

代码示例:

MOV R0, #0x1000  ; 设置基地址
MOV R1, #0xABCD  ; 将数据 0xABCD 存入 R1 寄存器
MOV R2, #4       ; 设置偏移量
STR R1, [R0, R2] ; 将 R1 中的数据存储到地址 0x1004 处

使用场景

  • 保存数组元素:在处理数组时,可使用 STR 指令将数据按索引存储到数组的相应位置。

  • 更新全局变量:通过 STR 指令将计算结果保存到全局变量所在的内存地址。

  • 栈操作:在函数调用过程中,使用 STR 指令将寄存器的值保存到栈中,以保存现场。

注意事项

  • 内存访问权限:要确保目标内存地址具有可写权限,否则会导致内存访问错误。

  • 寻址方式选择:根据具体需求选择合适的寻址方式,不同的寻址方式适用于不同的场景。

  • 数据类型:STR 指令默认存储 32 位数据。如果需要存储 8 位或 16 位数据,可以使用 STRB(存储字节)或 STRH(存储半字)指令。

PUSH

PUSH 指令属于栈操作指令,用于将寄存器中的数据压入栈中。

指令功能

PUSH 指令的主要功能是把一个或多个寄存器的值保存到栈中。

在程序执行过程中,当需要调用子程序或者处理中断时,常常需要保存当前寄存器的值,以防止在子程序或中断处理过程中这些寄存器的值被修改。PUSH 指令可以将这些寄存器的值按顺序压入栈中,等子程序或中断处理完毕后,再使用 POP 指令将这些值从栈中恢复出来。

语法结构

PUSH 指令的语法格式如下:

PUSH {<registers>}
  • <registers>:这是一个寄存器列表,用于指定要压入栈中的寄存器。可以是单个寄存器,也可以是多个寄存器,多个寄存器之间用逗号分隔。例如,{R0} 表示只将寄存器 R0 的值压入栈中;{R0 - R3} 表示将寄存器 R0、R1、R2 和 R3 的值按顺序压入栈中;{R0, R2, R4} 表示将寄存器 R0、R2 和 R4 的值按顺序压入栈中。

使用场景

  • 子程序调用:在调用子程序之前,使用 PUSH 指令将需要保存的寄存器的值压入栈中,在子程序返回之前,使用 POP 指令将这些值从栈中恢复出来,以保证子程序不会影响主程序中寄存器的值。

  • 中断处理:在中断处理程序中,使用 PUSH 指令将当前寄存器的值压入栈中,在中断处理程序返回之前,使用 POP 指令将这些值从栈中恢复出来,以保证中断处理不会影响主程序中寄存器的值。

代码示例

以下是一个简单的 ARM 汇编代码示例,展示了 PUSH 指令在子程序调用中的使用:

    ; 主程序MOV R0, #10          ; 将立即数 10 赋值给寄存器 R0MOV R1, #20          ; 将立即数 20 赋值给寄存器 R1PUSH {R0, R1}        ; 将 R0 和 R1 的值压入栈中BL SUBROUTINE        ; 调用子程序POP {R0, R1}         ; 从栈中恢复 R0 和 R1 的值B END_PROGRAM        ; 跳转到程序结束处SUBROUTINE:; 子程序MOV R0, #30          ; 将立即数 30 赋值给寄存器 R0MOV R1, #40          ; 将立即数 40 赋值给寄存器 R1BX LR                ; 返回主程序END_PROGRAM:B .                  ; 进入无限循环

代码解释

  1. 主程序部分:

    1. 将立即数 10 赋值给寄存器 R0,将立即数 20 赋值给寄存器 R1,然后使用 PUSH {R0, R1} 指令将 R0 和 R1 的值压入栈中。

    2. 接着调用子程序 SUBROUTINE,在子程序返回后,使用 POP {R0, R1} 指令从栈中恢复 R0 和 R1 的值。

  2. 子程序部分:在子程序中,将立即数 30 赋值给寄存器 R0,将立即数 40 赋值给寄存器 R1,然后使用 BX LR 指令返回主程序。

  3. 程序结束部分:跳转到 END_PROGRAM 处,然后进入无限循环。

注意事项

  • 栈的操作需要遵循后进先出(LIFO)的原则,因此在使用 PUSH 和 POP 指令时,要确保寄存器的顺序一致,否则可能会导致数据混乱。

  • 栈指针(通常是 SP 寄存器)的值会随着 PUSH 和 POP 指令的执行而自动调整,因此不需要手动修改栈指针的值。但是,要确保栈空间足够,避免栈溢出的问题。

POP

POP 指令与 PUSH 指令相对应,是用于栈操作的重要指令,主要功能是从栈中弹出数据并恢复到寄存器。

指令功能

POP 指令的核心功能是从栈中按照后进先出(LIFO)的顺序取出数据,并将这些数据依次恢复到指定的寄存器中。

在程序执行过程中,当使用 PUSH 指令将寄存器的值保存到栈中后,在合适的时机就需要使用 POP 指令将这些值从栈中恢复出来,以保证程序的正确执行。

语法结构

POP 指令的语法格式如下:

POP {<registers>}
  • <registers>:这是一个寄存器列表,用于指定从栈中弹出的数据要恢复到哪些寄存器。可以是单个寄存器,也可以是多个寄存器,多个寄存器之间用逗号分隔。例如,{R0} 表示只从栈中弹出一个数据并恢复到寄存器 R0;{R0 - R3} 表示依次从栈中弹出 4 个数据,分别恢复到寄存器 R0、R1、R2 和 R3;{R0, R2, R4} 表示依次从栈中弹出 3 个数据,分别恢复到寄存器 R0、R2 和 R4。

使用场景

  • 子程序返回:在调用子程序之前,使用 PUSH 指令将需要保存的寄存器的值压入栈中,在子程序返回时,使用 POP 指令将这些值从栈中恢复出来,以保证子程序不会影响主程序中寄存器的值。

  • 中断处理返回:在中断处理程序中,使用 PUSH 指令将当前寄存器的值压入栈中,在中断处理程序返回之前,使用 POP 指令将这些值从栈中恢复出来,以保证中断处理不会影响主程序中寄存器的值。

代码示例

以下是一个简单的 ARM 汇编代码示例,展示了 POP 指令在子程序调用中的使用:

    ; 主程序MOV R0, #10          ; 将立即数 10 赋值给寄存器 R0MOV R1, #20          ; 将立即数 20 赋值给寄存器 R1PUSH {R0, R1}        ; 将 R0 和 R1 的值压入栈中BL SUBROUTINE        ; 调用子程序POP {R0, R1}         ; 从栈中恢复 R0 和 R1 的值B END_PROGRAM        ; 跳转到程序结束处SUBROUTINE:; 子程序MOV R0, #30          ; 将立即数 30 赋值给寄存器 R0MOV R1, #40          ; 将立即数 40 赋值给寄存器 R1BX LR                ; 返回主程序END_PROGRAM:B .                  ; 进入无限循环

代码解释

  1. 主程序部分:

    1. 首先将立即数 10 赋值给寄存器 R0,将立即数 20 赋值给寄存器 R1。

    2. 然后使用 PUSH {R0, R1} 指令将 R0 和 R1 的值压入栈中,接着调用子程序 SUBROUTINE。

    3. 在子程序返回后,使用 POP {R0, R1} 指令从栈中恢复 R0 和 R1 的值,这样 R0 和 R1 就恢复到了调用子程序之前的值。

  2. 子程序部分:在子程序中,将立即数 30 赋值给寄存器 R0,将立即数 40 赋值给寄存器 R1,然后使用 BX LR 指令返回主程序。

  3. 程序结束部分:跳转到 END_PROGRAM 处,然后进入无限循环。

注意事项

  • 栈操作顺序:栈的操作遵循后进先出(LIFO)原则,所以使用 PUSH 和 POP 指令时,寄存器的顺序必须一致。例如,PUSH {R0, R1} 后,必须使用 POP {R0, R1} 来恢复寄存器的值,否则会导致数据混乱。

  • 栈指针与栈溢出:栈指针(通常是 SP 寄存器)的值会随着 PUSH 和 POP 指令的执行而自动调整,一般不需要手动修改。但要确保栈空间足够,避免栈溢出的问题。如果栈溢出,可能会覆盖其他重要的数据,导致程序崩溃。

  • PC 寄存器特殊处理:在某些情况下,如果需要将栈中的数据恢复到程序计数器 PC 寄存器(如子程序返回),可以使用 POP {PC} 来实现。但要注意栈中存储的返回地址必须是合法的,否则会导致程序跳转到错误的地址。

2.数据处理指令

BIC - Bit Clear

BIC(Bit Clear)指令用于对寄存器中的指定位进行清零操作。

指令语法

BIC {cond}{S} Rd, Rn, <Operand2>
  • {cond}:可选的条件码,用于指定指令执行的条件。只有当条件码满足时,指令才会执行。常见的条件码如 EQ(相等)、NE(不相等)、GT(大于)等。

  • {S}:可选后缀,如果指定了该后缀,则会根据操作结果更新 CPSR(当前程序状态寄存器)中的条件标志位(如 N、Z、C、V)。

  • Rd:目标寄存器,用于存放操作结果。

  • Rn:第一个操作数寄存器,提供要进行位清除操作的原始数据。

  • <Operand2>:第二个操作数,可以是立即数或者寄存器。该操作数的位为 1 的位置,会对应将 Rn 寄存器中相同位置的位清零。

操作原理

BIC 指令通过将 Rn 寄存器的值与 Operand2 的反码进行按位与(AND)操作来实现位清除。具体的:

  • 对于 Operand2 中值为 1 的位,Rn 中对应位置的位会被清零;

  • 而 Operand2 中值为 0 的位,Rn 中对应位置的位保持不变。

使用场景

  • 清除特定标志位:当需要清除寄存器中某些特定的标志位时,可以使用 BIC 指令。例如,在状态寄存器中清除某些状态标志。

  • 数据预处理:在进行其他操作之前,可能需要清除数据中的某些无效位,以确保后续操作的正确性。

示例代码

清除寄存器中特定的位
; 假设 R0 中存储了一个 32 位的数据,现在要清除第 2 位和第 5 位
MOV R1, #(1 << 2) | (1 << 5) ; R1 的值为 0000 0000 0000 0000 0000 0000 0010 0100
BIC R0, R0, R1               ; 清除 R0 中第 2 位和第 5 位

上述示例中,首先将需要清除的位对应的位置为 1,存储在 R1 中。然后使用 BIC 指令将 R0 中对应 R1 为 1 的位清零。

清除标志位并更新条件标志
; 假设 R2 中存储了状态信息,要清除第 0 位,并更新条件标志
MOV R3, #1      ; R3 的值为 0000 0000 0000 0000 0000 0000 0000 0001
BICS R2, R2, R3 ; 清除 R2 中第 0 位,并根据结果更新 CPSR 的条件标志位

在这个示例中,使用 BICS 指令清除 R2 中的第 0 位,并根据操作结果更新 CPSR 中的条件标志位,方便后续进行条件判断。

ORR - Logical Inclusive OR

ORR(Logical Inclusive OR,逻辑或)指令的功能是对两个操作数进行按位逻辑或运算,然后把结果存于目标寄存器。

指令语法

ORR {cond}{S} Rd, Rn, <Operand2>
  • {cond}:可选的条件码,用于规定指令执行的条件。只有条件码满足时,指令才会执行。常见的条件码有 EQ(相等)、NE(不相等)、GT(大于)等。

  • {S}:可选后缀,若指定了该后缀,就会依据操作结果更新 CPSR(当前程序状态寄存器)里的条件标志位(像 N、Z、C、V)。

  • Rd:目标寄存器,用来存放逻辑或运算的结果。

  • Rn:第一个操作数寄存器,提供进行逻辑或运算的一个操作数。

  • <Operand2>:第二个操作数,可以是立即数或者寄存器。

操作原理

ORR 指令会对 Rn 寄存器的值和 Operand2 的值逐位进行逻辑或运算。

逻辑或运算的规则是:只要两个对应位中有一个为 1,结果位就为 1;只有当两个对应位都为 0 时,结果位才为 0。

使用场景

  • 设置特定标志位:当需要把寄存器里的某些特定位置为 1 时,可以使用 ORR 指令。例如,在状态寄存器里设置某些状态标志。

  • 组合数据:可以把多个数据的不同位组合到一个寄存器中。

示例代码

设置寄存器中特定的位
; 假设 R0 中存储了一个 32 位的数据,现在要设置第 2 位和第 5 位
MOV R1, #(1 << 2) | (1 << 5) ; R1 的值为 0000 0000 0000 0000 0000 0000 0010 0100
ORR R0, R0, R1               ; 设置 R0 中第 2 位和第 5 位为 1

在这个例子里,先把需要设置的位对应的位置为 1,存于 R1 中。接着使用 ORR 指令将 R0 中对应 R1 为 1 的位设置为 1。

设置标志位并更新条件标志
; 假设 R2 中存储了状态信息,要设置第 0 位,并更新条件标志
MOV R3, #1      ; R3 的值为 0000 0000 0000 0000 0000 0000 0000 0001
ORRS R2, R2, R3 ; 设置 R2 中第 0 位为 1,并根据结果更新 CPSR 的条件标志位

此示例使用 ORRS 指令将 R2 中的第 0 位设置为 1,并且依据操作结果更新 CPSR 里的条件标志位,以便后续进行条件判断。

ADD - Add

ADD 指令用于执行加法运算的基础指令。

指令功能

ADD 指令的核心功能是对两个操作数进行加法运算,并将结果存储到目标寄存器中。

与 ADDS 指令不同,ADD 指令执行加法运算时不会更新程序状态寄存器(CPSR)中的标志位,而 ADDS 指令在执行加法运算的同时会更新标志位。

语法结构

ADD 指令有多种语法形式,常见的如下:

寄存器 - 寄存器形式

ADD <Rd>, <Rn>, <Rm>
  • <Rd>:目标寄存器,用于存放加法运算的结果。

  • <Rn>:第一个操作数所在的寄存器。

  • <Rm>:第二个操作数所在的寄存器。

寄存器 - 立即数形式

ADD <Rd>, <Rn>, #<immediate>
  • <Rd>:目标寄存器,用于存放加法运算的结果。

  • <Rn>:第一个操作数所在的寄存器。

  • #<immediate>:立即数,即一个常量值。

寄存器移位形式

ADD <Rd>, <Rn>, <Rm>, <shift>
  • <Rd>:目标寄存器,用于存放加法运算的结果。

  • <Rn>:第一个操作数所在的寄存器。

  • <Rm>:第二个操作数所在的寄存器。

  • <shift>:移位操作,对 <Rm> 进行移位操作后再与 <Rn> 相加。常见的移位操作有 LSL(逻辑左移)、LSR(逻辑右移)等。

使用场景

  • 数值计算:在进行数学计算时,若需要对两个数值进行加法运算,可使用 ADD 指令。例如,计算两个变量的和。

  • 地址计算:在处理内存地址时,可能需要对地址进行偏移计算,此时使用 ADD 指令能方便地实现地址的加法操作。

  • 计数器更新:在循环或计数操作中,可使用 ADD 指令对计数器进行递增操作。

代码示例

以下是几个使用 ADD 指令的示例:

示例 1:寄存器 - 寄存器形式

    MOV R0, #5          ; 将立即数 5 赋值给寄存器 R0MOV R1, #3          ; 将立即数 3 赋值给寄存器 R1ADD R2, R0, R1      ; R2 = R0 + R1,即 R2 = 5 + 3 = 8

上述代码中,把 5 赋值给 R0,3 赋值给 R1,然后用 ADD 指令计算 R0 + R1 的结果,将结果 8 存到 R2 中。

示例 2:寄存器 - 立即数形式

    MOV R0, #10         ; 将立即数 10 赋值给寄存器 R0ADD R1, R0, #5      ; R1 = R0 + 5,即 R1 = 10 + 5 = 15

上述代码中,把 10 赋值给 R0,使用 ADD 指令计算 R0 + 5 的结果,将结果 15 存到 R1 中。

示例 3:寄存器移位形式

    MOV R0, #2          ; 将立即数 2 赋值给寄存器 R0MOV R1, #3          ; 将立即数 3 赋值给寄存器 R1ADD R2, R0, R1, LSL #2  ; 先将 R1 逻辑左移 2 位(R1 = 3 << 2 = 12),然后 R2 = R0 + 12,即 R2 = 2 + 12 = 14

上述代码中,把 2 赋值给 R0,3 赋值给 R1,先将 R1 逻辑左移 2 位得到 12,再用 ADD 指令计算 R0 + 12 的结果,将结果 14 存到 R2 中。

注意事项

  • 操作数范围:对于立即数形式的 ADD 指令,立即数的取值范围是有限制的,要保证使用的立即数在合法范围内,不然可能会导致指令无法正确执行。

  • 寄存器的选择:要选择合适的寄存器来存放操作数和结果,避免寄存器冲突造成数据丢失或错误。

ADDS - Add

ADDS 指令是 ADD 指令的变体。

指令功能

ADDS 指令的主要功能是对两个操作数执行加法运算,然后把结果存到目标寄存器中。

与 ADD 指令不同的是,ADDS 指令在完成加法运算后,还会依据运算结果更新程序状态寄存器(CPSR)里的标志位。这些标志位能够反映运算结果的特性,像结果是否为零、是否产生进位等,后续的条件分支指令可以依据这些标志位来决定是否执行相应操作。

语法结构

ADDS 指令有多种常见的语法形式:

寄存器 - 寄存器形式

ADDS <Rd>, <Rn>, <Rm>
  • <Rd>:目标寄存器,用于存放加法运算的结果。

  • <Rn>:第一个操作数所在的寄存器。

  • <Rm>:第二个操作数所在的寄存器。

寄存器 - 立即数形式

ADDS <Rd>, <Rn>, #<immediate>
  • <Rd>:目标寄存器,用于存放加法运算的结果。

  • <Rn>:第一个操作数所在的寄存器。

  • #<immediate>:立即数,也就是一个常量值。

寄存器移位形式

ADDS <Rd>, <Rn>, <Rm>, <shift>
  • <Rd>:目标寄存器,用于存放加法运算的结果。

  • <Rn>:第一个操作数所在的寄存器。

  • <Rm>:第二个操作数所在的寄存器。

  • <shift>:移位操作,对 <Rm> 进行移位操作后再与 <Rn> 相加。常见的移位操作有 LSL(逻辑左移)、LSR(逻辑右移)等。

使用场景

  • 数值计算与状态判断:在进行数值计算时,若需要根据加法运算结果的状态来进行后续操作,就可以使用 ADDS 指令。例如,判断两个数相加的结果是否为零,以此来决定程序的执行流程。

  • 条件分支:结合条件分支指令(如 BEQ、BNE、BCS 等)使用,根据 ADDS 指令更新的标志位来决定程序的执行方向。比如,在循环中判断计数器是否达到某个值,从而决定是否退出循环。

代码示例

以下是几个使用 ADDS 指令的示例:

示例 1:寄存器 - 寄存器形式

    MOV R0, #5          ; 将立即数 5 赋值给寄存器 R0MOV R1, #3          ; 将立即数 3 赋值给寄存器 R1ADDS R2, R0, R1     ; R2 = R0 + R1,即 R2 = 5 + 3 = 8; 根据结果更新标志位,这里 Z 标志位为 0(结果不为零)

上述代码中,把 5 赋值给 R0,3 赋值给 R1,然后用 ADDS 指令计算 R0 + R1 的结果,将结果 8 存到 R2 中。由于结果不为零,CPSR 中的 Z 标志位会被置为 0。

示例 2:结合条件分支指令

    MOV R0, #10         ; 将立即数 10 赋值给寄存器 R0MOV R1, # - 10       ; 将立即数 -10 赋值给寄存器 R1ADDS R2, R0, R1     ; R2 = R0 + R1,即 R2 = 10 + (-10) = 0BEQ EQUAL           ; 如果 Z 标志位为 1(结果为零),跳转到 EQUAL 标签处B NOT_EQUAL         ; 否则,跳转到 NOT_EQUAL 标签处EQUAL:; 处理相等的情况MOV R3, #1          ; 可以在这里进行一些操作,比如将 R3 赋值为 1B END_PROGRAMNOT_EQUAL:; 处理不相等的情况MOV R3, #0          ; 将 R3 赋值为 0B END_PROGRAMEND_PROGRAM:B .                 ; 进入无限循环

上述代码中,把 10 赋值给 R0, - 10 赋值给 R1,使用 ADDS 指令计算 R0 + R1 的结果,结果为 0。因为结果为零,CPSR 中的 Z 标志位会被置为 1,BEQ 指令会根据 Z 标志位的值决定是否跳转到 EQUAL 标签处执行相应操作。

注意事项

  • 标志位的使用:要清楚 ADDS 指令更新的标志位(如 N、Z、C、V 标志位)的含义,并且在后续使用条件分支指令时,要根据具体需求正确使用这些标志位。

  • 操作数范围:对于立即数形式的 ADDS 指令,立即数的取值范围是有限制的,需要确保使用的立即数在合法范围内,否则可能会导致指令无法正确执行。

  • 寄存器的选择:要确保选择合适的寄存器来存放操作数和结果,避免寄存器冲突导致数据丢失或错误。

SUB - Subtract

SUB 指令用于执行减法运算的基础指令。

指令功能

SUB 指令的主要功能是对两个操作数进行减法运算,把结果存到目标寄存器中。

它和 SUBS 指令不同,SUB 指令不会更新程序状态寄存器(CPSR)里的标志位,而 SUBS 指令在执行减法运算的同时会更新标志位。

语法结构

SUB 指令有多种语法形式,下面是常见的几种:

寄存器 - 寄存器形式

SUB <Rd>, <Rn>, <Rm>
  • <Rd>:目标寄存器,用于存放减法运算的结果。

  • <Rn>:第一个操作数所在的寄存器。

  • <Rm>:第二个操作数所在的寄存器,该操作数会从 <Rn> 中减去。

寄存器 - 立即数形式

SUB <Rd>, <Rn>, #<immediate>
  • <Rd>:目标寄存器,用于存放减法运算的结果。

  • <Rn>:第一个操作数所在的寄存器。

  • #<immediate>:立即数,该立即数会从 <Rn> 中减去。

寄存器移位形式

SUB <Rd>, <Rn>, <Rm>, <shift>
  • <Rd>:目标寄存器,用于存放减法运算的结果。

  • <Rn>:第一个操作数所在的寄存器。

  • <Rm>:第二个操作数所在的寄存器。

  • <shift>:移位操作,对 <Rm> 进行移位操作后再从 <Rn> 中减去。常见的移位操作有 LSL(逻辑左移)、LSR(逻辑右移)等。

使用场景

  • 数值计算:在进行数值计算时,若不需要根据减法运算结果更新标志位,就可以使用 SUB 指令。例如,计算两个变量的差值。

  • 地址计算:在进行地址计算时,可能需要对地址进行减法操作,这时使用 SUB 指令能方便地实现。

代码示例

以下是几个使用 SUB 指令的示例:

示例 1:寄存器 - 寄存器形式

    MOV R0, #10         ; 将立即数 10 赋值给寄存器 R0MOV R1, #3          ; 将立即数 3 赋值给寄存器 R1SUB R2, R0, R1      ; R2 = R0 - R1,即 R2 = 10 - 3 = 7

上述代码中,把 10 赋值给 R0,3 赋值给 R1,然后用 SUB 指令计算 R0 - R1 的结果,将结果 7 存到 R2 中。

示例 2:寄存器 - 立即数形式

    MOV R0, #20         ; 将立即数 20 赋值给寄存器 R0SUB R1, R0, #5      ; R1 = R0 - 5,即 R1 = 20 - 5 = 15

上述代码中,把 20 赋值给 R0,使用 SUB 指令计算 R0 - 5 的结果,将结果 15 存到 R1 中。

示例 3:寄存器移位形式

    MOV R0, #16         ; 将立即数 16 赋值给寄存器 R0MOV R1, #2          ; 将立即数 2 赋值给寄存器 R1SUB R2, R0, R1, LSL #2  ; 先将 R1 逻辑左移 2 位(R1 = 2 << 2 = 8),然后 R2 = R0 - 8,即 R2 = 16 - 8 = 8

上述代码中,把 16 赋值给 R0,2 赋值给 R1,先将 R1 逻辑左移 2 位得到 8,再用 SUB 指令计算 R0 - 8 的结果,将结果 8 存到 R2 中。

注意事项

  • 操作数范围:对于立即数形式的 SUB 指令,立即数的取值范围是有限制的,要保证使用的立即数在合法范围内,不然可能会导致指令无法正确执行。

  • 寄存器的选择:要选择合适的寄存器来存放操作数和结果,避免寄存器冲突造成数据丢失或错误。

SUBS - Subtract

SUBS 指令属于算术运算指令,本质上是减法指令 SUB 的变体。

基本功能

SUBS 指令的主要功能是执行减法运算,将一个操作数从另一个操作数中减去,并且会根据运算结果更新程序状态寄存器(CPSR)中的标志位。这些标志位可以反映运算结果的各种特性,例如结果是否为零、是否产生进位或借位等,后续的条件分支指令可以根据这些标志位来决定是否执行相应的操作。

语法结构

SUBS 指令有几种不同的语法形式,常见的如下:

寄存器 - 寄存器形式
SUBS <Rd>, <Rn>, <Rm>
  • <Rd>:目标寄存器,用于存放减法运算的结果。

  • <Rn>:第一个操作数所在的寄存器。

  • <Rm>:第二个操作数所在的寄存器,该操作数将从 <Rn> 中减去。

寄存器 - 立即数形式
SUBS <Rd>, <Rn>, #<immediate>
  • <Rd>:目标寄存器,用于存放减法运算的结果。

  • <Rn>:第一个操作数所在的寄存器。

  • #<immediate>:立即数,该立即数将从 <Rn> 中减去。

使用场景

  • 数值计算:在进行数值计算时,需要进行减法运算并根据结果的状态来进行后续操作,就可以使用 SUBS 指令。例如,判断两个数是否相等,可以用一个数减去另一个数,然后根据结果是否为零(通过 Z 标志位判断)来确定。

  • 条件分支:结合条件分支指令(如 BEQ、BNE 等)使用,根据 SUBS 指令更新的标志位来决定程序的执行流程。比如,在循环中判断计数器是否减到零,从而决定是否退出循环。

示例代码

以下是几个使用 SUBS 指令的示例:

示例 1:寄存器 - 寄存器形式

    MOV R0, #5          ; 将立即数 5 赋值给寄存器 R0MOV R1, #3          ; 将立即数 3 赋值给寄存器 R1SUBS R2, R0, R1     ; R2 = R0 - R1,即 R2 = 5 - 3 = 2; 根据结果更新标志位,这里 Z 标志位为 0(结果不为零)

示例 2:结合条件分支指令

    MOV R0, #10         ; 将立即数 10 赋值给寄存器 R0MOV R1, #10         ; 将立即数 10 赋值给寄存器 R1SUBS R2, R0, R1     ; R2 = R0 - R1,即 R2 = 10 - 10 = 0BEQ EQUAL           ; 如果 Z 标志位为 1(结果为零),跳转到 EQUAL 标签处B NOT_EQUAL         ; 否则,跳转到 NOT_EQUAL 标签处EQUAL:; 处理相等的情况MOV R3, #1          ; 可以在这里进行一些操作,比如将 R3 赋值为 1B END_PROGRAMNOT_EQUAL:; 处理不相等的情况MOV R3, #0          ; 将 R3 赋值为 0B END_PROGRAMEND_PROGRAM:B .                 ; 进入无限循环

注意事项

  • 标志位的使用:要清楚 SUBS 指令更新的标志位(如 N、Z、C、V 标志位)的含义,并且在后续使用条件分支指令时,要根据具体需求正确使用这些标志位。

  • 操作数范围:对于立即数形式的 SUBS 指令,立即数的取值范围是有限制的,需要确保使用的立即数在合法范围内,否则可能会导致指令无法正确执行。

  • 寄存器的选择:要确保选择合适的寄存器来存放操作数和结果,避免寄存器冲突导致数据丢失或错误。

3.分支跳转指令

B - Branch

B 指令用于实现程序跳转。

基本概念

B 指令的主要功能是改变程序的执行流程,使程序跳转到指定的目标地址继续执行。它属于无条件跳转指令,也就是说,一旦执行 B 指令,程序就会立即跳转到指定地址,而不会考虑其他条件。

语法格式

B 指令的语法格式较为简单:

B <label>

其中,<label> 是一个标号,代表要跳转的目标地址。标号在汇编代码中用于标记特定的位置,通过 B 指令可以直接跳转到该位置。

代码示例:

    MOV R0, #10B subroutine  ; 跳转到子程序; 子程序返回后不会执行到这里,因为没有保存返回地址MOV R1, #20subroutine:ADD R0, R0, #5  ; 子程序代码B end_program   ; 跳转到程序结束处end_program:MOV R7, #1SWI 0  ; 退出程序

使用场景

  • 子程序调用:在程序中调用子程序时,可以使用 B 指令跳转到子程序的入口地址。不过需要注意的是,B 指令本身不会保存返回地址,所以在使用 B 指令调用子程序后,需要额外的操作来实现返回原程序的功能。

  • 条件分支:结合条件判断指令(如 CMP),可以实现条件分支。例如,先进行条件判断,根据判断结果决定是否执行 B 指令进行跳转。

  • 循环结构:在实现循环结构时,使用 B 指令可以使程序跳转到循环体的起始位置,从而实现循环执行的功能。

注意事项

  • 返回地址处理:由于 B 指令不会保存返回地址,在使用 B 指令调用子程序时,需要手动保存和恢复返回地址,否则程序无法正确返回原位置继续执行。如果需要自动保存返回地址,可以使用 BL 指令。

  • 标号作用域:要确保跳转的标号在当前作用域内是有效的。如果是全局标号,要保证在整个程序中是唯一的;如果是局部标号,要注意其作用域仅限于当前文件或代码段。

  • 跳转范围:B 指令的跳转范围是有限的,通常只能在相对较近的地址范围内进行跳转。如果需要跳转到较远的地址,可以使用其他跳转指令或采用间接跳转的方式。

BX - Branch and Exchange

BX(Branch and Exchange)指令用于实现程序分支跳转,同时还能完成指令集状态的切换。

基本功能

  • 程序跳转:BX 指令最主要的功能是改变程序的执行流程,使程序跳转到指定的地址继续执行。这类似于其他架构中的跳转指令,比如 x86 架构的 JMP 指令。

  • 指令集切换:BX 指令还可以在 ARM 指令集和 Thumb 指令集之间进行切换。在 ARM 架构中,有两种指令集模式,ARM 指令集使用 32 位指令,而 Thumb 指令集使用 16 位指令,BX 指令可以根据目标地址的最低位来决定是否切换指令集。

语法结构

BX 指令的基本语法格式如下:

BX <Rm>

其中,<Rm> 是一个通用寄存器,该寄存器的值就是跳转的目标地址。

指令集切换规则

  • 当 <Rm> 的最低位(即 bit[0])为 0 时,处理器会以 ARM 指令集模式执行目标地址处的代码。

  • 当 <Rm> 的最低位(即 bit[0])为 1 时,处理器会切换到 Thumb 指令集模式,并在目标地址处开始执行代码。同时,该位在跳转时会被忽略,实际跳转的地址是 <Rm> 去掉最低位后的地址。

使用场景

  • 子程序调用返回:在子程序调用结束后,通常会使用 BX 指令返回到调用处继续执行。例如,在汇编语言编写的函数中,函数执行完毕后会将返回地址存储在某个寄存器中,然后使用 BX 指令跳转到该地址。

  • 指令集模式切换:当需要在 ARM 指令集和 Thumb 指令集之间进行切换时,可以使用 BX 指令。例如,在某些对代码密度要求较高的场景下,可能会使用 Thumb 指令集;而在需要执行复杂操作的场景下,可能会使用 ARM 指令集。

代码示例

以下是一个简单的 ARM 汇编代码示例,展示了 BX 指令的使用:

    ; 主程序MOV R0, #10          ; 将立即数 10 赋值给寄存器 R0BL SUBROUTINE        ; 调用子程序B END_PROGRAM        ; 跳转到程序结束处SUBROUTINE:ADD R0, R0, #1       ; R0 = R0 + 1MOV PC, LR           ; 保存返回地址到 PC,这里相当于简单的返回操作BX LR                ; 跳转到返回地址,同时可进行指令集切换(如果需要)END_PROGRAM:B .                  ; 进入无限循环

代码解释

  1. 主程序部分:将立即数 10 赋值给寄存器 R0,然后使用 BL 指令调用子程序 SUBROUTINE。

  2. 子程序部分:在子程序中,将 R0 的值加 1,然后使用 MOV PC, LR 保存返回地址到程序计数器 PC,接着使用 BX LR 指令跳转到返回地址,同时如果 LR 的最低位为 1,还会进行指令集切换。

  3. 程序结束部分:跳转到 END_PROGRAM 处,然后进入无限循环。

注意要点

  • 在使用 BX 指令进行跳转时,要确保目标地址是合法的,否则可能会导致程序崩溃。

  • 当进行指令集切换时,要确保目标地址处的代码是使用相应指令集编写的,否则会产生错误的执行结果。

BL - Branch with Link calls

BL(Branch with Link)指令用于实现子程序(函数)调用

基本概念

BL 指令本质上是一种特殊的跳转指令,它不仅能让程序跳转到指定的子程序入口地址开始执行子程序,还会自动保存返回地址,以便子程序执行完毕后能返回到原程序继续执行。

语法格式

BL 指令的语法较为简单:

BL <label>

其中,<label> 是一个标号,代表要跳转的子程序的入口地址。标号在汇编代码里用于标记特定的位置,BL 指令会使程序跳转到该位置开始执行子程序。

工作原理

  1. 保存返回地址:在执行 BL 指令时,处理器会将当前 PC(程序计数器)的值加上一个偏移量(通常是 4 字节,因为 ARM 指令通常是 4 字节对齐),得到下一条指令的地址,然后将该地址保存到链接寄存器 LR(Link Register,即 R14)中。

  2. 跳转执行:程序跳转到 <label> 所指定的地址,开始执行子程序的代码。

  3. 返回原程序:在子程序执行完毕后,通过 BX 指令将 LR 寄存器中的返回地址加载到 PC 中,使程序返回到原程序中 BL 指令的下一条指令处继续执行。

使用场景

  • 模块化编程:大型程序开发中,为了提高代码的可维护性和复用性,通常将不同的功能封装成子程序。BL 指令可以方便地调用这些子程序,实现模块化编程。

  • 函数调用:编写汇编程序时,经常需要调用各种函数来完成特定的任务。BL 指令是实现函数调用的关键指令。

示例代码

    MOV R0, #10       ; 传递参数,假设子程序需要一个参数BL subroutine     ; 调用子程序MOV R1, R0        ; 子程序返回后,将返回值存到 R1B end_program     ; 跳转到程序结束处subroutine:ADD R0, R0, #5    ; 子程序代码,将参数加 5BX LR             ; 返回原程序end_program:MOV R7, #1        ; 系统调用号,表示退出程序SWI 0             ; 执行系统调用,退出程序

在这个示例中,主程序将参数 10 存入 R0 寄存器,然后使用 BL 指令调用 subroutine 子程序。子程序将 R0 中的值加 5,最后使用 BX LR 指令返回主程序。主程序将子程序的返回值存到 R1 寄存器,然后结束程序。

注意事项

  • 返回地址管理:在子程序中,要确保在合适的位置使用 BX LR 指令返回原程序。如果在子程序中修改了 LR 寄存器的值,需要在返回前恢复其原始值,否则程序将无法正确返回。

  • 参数传递和返回值:在使用 BL 指令调用子程序时,需要遵循一定的参数传递和返回值约定。通常,前几个参数通过寄存器 R0 - R3 传递,返回值也通过 R0 寄存器返回。

  • 栈的使用:如果子程序需要保存更多的寄存器值或者使用局部变量,可能需要使用栈来进行存储。在子程序开始时,将需要保存的寄存器值压入栈中,在子程序结束前,将这些值从栈中弹出恢复。

BLX - Branch with Link and Exchange

BLX(Branch with Link and Exchange)指令主要用于子程序调用,同时还能实现 ARM 状态和 Thumb 状态之间的切换。

基本功能

  • BLX 指令将下一条指令的地址保存到链接寄存器 LR(R14)中,这是为了子程序执行完后能返回到调用处。

  • 它会跳转到指定的目标地址去执行子程序。

  • 该指令能够根据目标地址的最低位来决定是否进行 ARM 状态和 Thumb 状态的切换。

    • 若目标地址最低位为 0,就继续保持 ARM 状态;

    • 若为 1,则从 ARM 状态切换到 Thumb 状态,或者从 Thumb 状态切换到 ARM 状态。

语法格式(寻址方式)

BLX 指令有两种语法格式(寻址方式):

  • 立即数寻址;

  • 寄存器寻址;

立即数寻址
BLX <target_address>

其中,<target_address> 是目标地址,一般是一个标号。指令会根据该地址的最低位来判断是否要切换状态。

寄存器寻址
BLX <Rm>

其中,<Rm> 是一个通用寄存器,寄存器中的值为目标地址。同样,会依据该值的最低位决定是否进行状态切换。

使用示例

下面是一段简单的 ARM 汇编代码示例,展示了 BLX 指令的使用:

    ; 主程序MOV R0, #10      ; 将立即数 10 存入 R0BLX Subroutine  ; 调用子程序,可能会切换状态; 子程序返回后继续执行这里MOV R7, #1       ; 设置系统调用号为 1(退出程序)SWI 0            ; 执行系统调用; 子程序
SubroutineADD R0, R0, #5   ; R0 = R0 + 5BX LR            ; 返回主程序

指令用途

  • 子程序调用:BLX 是实现子程序调用的关键指令,能够在不同状态的代码间进行切换调用。

  • 状态切换:在 ARM 架构里,程序可以在 ARM 状态(32 位指令集)和 Thumb 状态(16 位指令集)之间切换,BLX 指令能依据目标地址最低位来实现这种状态切换。

4.协处理器指令

MRC - Move Register from Coprocessor

MRC(Move Register from Coprocessor)指令用于从协处理器向 ARM 处理器传送数据。

指令功能

MRC 指令的主要功能是让 ARM 处理器从协处理器那里读取数据。

在 ARM 架构里,协处理器能辅助主处理器完成特定任务,像浮点运算、内存管理等。

借助 MRC 指令,主处理器可以获取协处理器内部寄存器的值,从而了解协处理器的状态或者获取计算结果。

语法结构

MRC 指令的语法格式如下:

MRC{<cond>} <p#, <opcode_1>, <Rd>, <CRn>, <CRm>{, <opcode_2>}
  • 参数解释:

    • <cond>:这是可选的条件码,用于指定指令执行的条件。只有当条件满足时,指令才会执行。常见的条件码有 EQ(相等)、NE(不相等)等。

    • <p#>:表示协处理器编号,范围是 p0 - p15。它用来指定要与哪个协处理器进行通信。

    • <opcode_1>:是第一个操作码,为一个 4 位的无符号整数,用于指定协处理器操作的类型。

    • <Rd>:是 ARM 处理器的目标寄存器,从协处理器读取的数据会被存到这个寄存器中。

    • <CRn>:是协处理器的寄存器编号,指定要从协处理器的哪个主寄存器读取数据。

    • <CRm>:是协处理器的附加寄存器编号,用于进一步指定协处理器操作的参数。

    • <opcode_2>:是可选的第二个操作码,同样为 4 位无符号整数,用于对协处理器操作进行更详细的指定。

使用场景

  • 获取协处理器状态:主处理器可以通过 MRC 指令读取协处理器的状态寄存器,以此了解协处理器的工作状态,例如是否出现错误、是否完成特定计算等。

  • 读取计算结果:当协处理器完成特定计算后,主处理器可以使用 MRC 指令从协处理器的结果寄存器中读取计算结果。

代码示例

以下是一个简单的示例,展示了如何使用 MRC 指令从协处理器 p15 读取寄存器 c1 的值:

; 从协处理器 p15 的 c1 寄存器读取数据到 ARM 处理器的 R0 寄存器
MRC p15, 0, R0, c1, c0, 0; 后续可以对 R0 中的数据进行处理
MOV R1, R0          ; 将 R0 的值复制到 R1

代码解释

  1. MRC p15, 0, R0, c1, c0, 0:从协处理器 p15 的 c1 寄存器读取数据,并将其存储到 ARM 处理器的 R0 寄存器中。这里的 opcode_1 为 0,opcode_2 也为 0。

  2. MOV R1, R0:将 R0 中的数据复制到 R1 寄存器,以便后续处理。

注意事项

  • 要保证协处理器已经正确初始化,并且支持所使用的操作码和寄存器访问。

  • 在使用 MRC 指令时,要确保协处理器编号、操作码和寄存器编号的设置正确,否则可能会导致读取的数据不正确或者产生错误。

MCR - Move to Coprocessor Register

MCR(Move to Coprocessor Register)指令用于将数据从 ARM 处理器传送到协处理器。

指令功能

MCR 指令的核心功能是让 ARM 处理器向协处理器发送数据。

在 ARM 系统中,协处理器可以辅助主处理器完成特定的任务,如浮点运算、内存管理、向量处理等。

通过 MCR 指令,主处理器能够将控制信息、数据等传递给协处理器,以控制协处理器的操作或者为其提供计算所需的数据。

语法结构

MCR 指令的语法格式如下:

MCR{<cond>} <p#>, <opcode_1>, <Rd>, <CRn>, <CRm>{, <opcode_2>}
  • 参数解释:

    • <cond>:可选的条件码,用于指定指令执行的条件。只有当条件满足时,指令才会执行。常见的条件码如 EQ(相等)、NE(不相等)、GT(大于)等。

    • <p#>:协处理器编号,范围是 p0 - p15,用于指定要与哪个协处理器进行通信。

    • <opcode_1>:第一个操作码,是一个 4 位的无符号整数,用于指定协处理器操作的类型。

    • <Rd>:ARM 处理器的源寄存器,要传送给协处理器的数据就存放在这个寄存器中。

    • <CRn>:协处理器的寄存器编号,指定要将数据写入协处理器的哪个主寄存器。

    • <CRm>:协处理器的附加寄存器编号,用于进一步指定协处理器操作的参数。

    • <opcode_2>:可选的第二个操作码,同样是 4 位无符号整数,用于对协处理器操作进行更详细的指定。

使用场景

  • 协处理器初始化:在使用协处理器之前,需要对其进行初始化设置。通过 MCR 指令,主处理器可以将初始化参数传递给协处理器的相应寄存器,使协处理器进入合适的工作状态。

  • 控制协处理器操作:协处理器工作过程中,主处理器可使用 MCR 指令向协处理器发送控制命令,如启动计算、停止计算、设置计算模式等。

代码示例

以下是一个简单的示例,展示如何使用 MCR 指令将 ARM 处理器寄存器 R0 中的数据传送到协处理器 p15 的寄存器 c1 中:

; 将 R0 中的数据传送到协处理器 p15 的 c1 寄存器
MOV R0, #0x1234      ; 将立即数 0x1234 赋值给 R0
MCR p15, 0, R0, c1, c0, 0; 后续可以进行其他操作
B .                  ; 进入无限循环

代码解释

  1. MOV R0, #0x1234:将立即数 0x1234 赋值给 ARM 处理器的寄存器 R0,作为要传送给协处理器的数据。

  2. MCR p15, 0, R0, c1, c0, 0:使用 MCR 指令将 R0 中的数据传送到协处理器 p15 的 c1 寄存器。这里的 opcode_1 为 0,opcode_2 也为 0。

  3. B .:进入无限循环,程序继续执行其他操作。

注意事项

  • 要确保协处理器已经正确初始化,并且支持所使用的操作码和寄存器访问。

  • 在使用 MCR 指令时,要保证协处理器编号、操作码和寄存器编号的设置正确,否则可能会导致数据写入错误或者产生其他异常。

  • 不同的协处理器对操作码和寄存器的使用方式可能不同,需要参考相应协处理器的文档进行正确配置。

5.功能指令

CPSID - Change Processor State (Interrupt Disable)

CPSID(Change Processor State,Interrupt Disable)指令用于控制处理器中断屏蔽状态。

基本功能

CPSID 指令的核心功能是禁用特定类型的中断,让处理器在执行关键代码时不会被中断干扰,以此保证代码的原子性和执行的完整性。

执行该指令后,特定类型的中断请求会被处理器忽略,直至使用 CPSIE(Change Processor State,Interrupt Enable)指令重新启用中断。

语法结构

CPSID 指令的语法格式如下:

CPSID {<if>} [, #<mode>]
  • 参数解释:

    • <if>:这是一个必选参数,它有以下几种取值:

      • i:屏蔽 IRQ(Interrupt ReQuest)中断,也就是普通中断。在 ARM 系统里,大多数外部设备产生的中断都属于 IRQ 中断。

      • f:屏蔽 FIQ(Fast Interrupt ReQuest)中断,即快速中断。FIQ 中断具有比 IRQ 中断更高的优先级,通常用于对响应时间要求极高的场合。

      • if:同时屏蔽 IRQ 和 FIQ 中断。

    • #<mode>:这是一个可选参数,用于指定处理器模式。不过在实际运用中,一般不指定该参数。

使用场景

  • 临界区保护:在对共享资源进行操作时,为了防止多个中断服务程序或者任务同时访问这些资源从而引发数据不一致的问题,可使用 CPSID 指令屏蔽中断,保证操作的原子性。

  • 实时任务执行:在实时系统中,部分任务对时间要求极为严格,不允许被中断打断。在执行这类任务时,就可以使用 CPSID 指令暂时屏蔽中断,等任务执行完毕后再恢复中断。

代码示例

以下是一段 ARM 汇编代码示例,展示了如何使用 CPSID 指令屏蔽中断:

; 屏蔽 IRQ 和 FIQ 中断
CPSID if; 关键代码段开始
; 这里进行对共享资源的操作
LDR R0, =0x55AA     ; 将数据 0x55AA 加载到寄存器 R0
STR R0, [R1]        ; 把 R0 中的数据存储到内存地址 R1 处
; 关键代码段结束; 恢复 IRQ 和 FIQ 中断
CPSIE if; 程序继续执行
B .                 ; 进入无限循环

代码解释

  1. CPSID if:屏蔽 IRQ 和 FIQ 中断,确保后续关键代码段的执行不会被中断打断。

  2. 关键代码段:把数据 0x55AA 加载到寄存器 R0 中,然后将其存储到内存地址 R1 处。这部分代码是需要保护的关键操作。

  3. CPSIE if:恢复 IRQ 和 FIQ 中断,允许处理器响应中断请求。

  4. B .:进入无限循环,程序继续执行。

注意事项

  • 在使用 CPSID 指令屏蔽中断后,要及时使用 CPSIE 指令恢复中断,不然系统将无法响应中断请求,可能会致使系统失去实时性。

  • 在多任务系统中,频繁使用 CPSID 指令可能会对系统的性能和稳定性产生影响,所以需要谨慎使用。

CPSIE - Change Processor State(Interrupt Enable)

CPSIE(Change Processor State, Interrupt Enable)指令用于控制处理器中断使能状态,与 CPSID 指令相对,CPSID 用于禁用中断,而 CPSIE 用于启用中断。

基本功能

CPSIE 指令的主要功能是允许处理器响应特定类型的中断。当使用 CPSID 指令屏蔽中断后,可通过 CPSIE 指令恢复中断的响应,使得系统能够继续处理外部设备或内部事件产生的中断请求。

语法结构

CPSIE 指令的语法格式如下:

CPSIE {<if>} [, #<mode>]
  • 参数解释:

    • <if>:这是必选参数,有以下几种取值:

      • i:启用 IRQ(Interrupt ReQuest)中断,即普通中断。大多数外部设备(如定时器、串口等)产生的中断属于 IRQ 中断。

      • f:启用 FIQ(Fast Interrupt ReQuest)中断,即快速中断。FIQ 中断具有比 IRQ 中断更高的优先级,通常用于对响应时间要求极高的场景,如高速数据采集。

      • if:同时启用 IRQ 和 FIQ 中断。

    • #<mode>:可选参数,用于指定处理器模式。在实际应用中,通常不指定该参数。

使用场景

  • 临界区结束:在使用 CPSID 指令屏蔽中断来保护临界区(对共享资源的操作)后,当临界区代码执行完毕,需要使用 CPSIE 指令恢复中断,以允许系统继续响应外部事件。

  • 实时任务完成:在实时系统中,若某个任务在执行期间不允许被中断打断,使用 CPSID 屏蔽中断;任务完成后,使用 CPSIE 恢复中断,使系统恢复正常的中断处理机制。

代码示例

以下是一个 ARM 汇编代码示例,展示了 CPSID 和 CPSIE 指令的配合使用:

; 屏蔽 IRQ 和 FIQ 中断
CPSID if; 关键代码段开始
; 这里进行对共享资源的操作
LDR R0, =0xABCD     ; 将数据 0xABCD 加载到寄存器 R0
STR R0, [R2]        ; 把 R0 中的数据存储到内存地址 R2 处
; 关键代码段结束; 恢复 IRQ 和 FIQ 中断
CPSIE if; 程序继续执行
MOV R3, #0          ; 将立即数 0 赋值给寄存器 R3
B .                 ; 进入无限循环

代码解释

  1. CPSID if:屏蔽 IRQ 和 FIQ 中断,确保关键代码段执行时不会被中断干扰。

  2. 关键代码段:将数据 0xABCD 加载到寄存器 R0 中,并存储到内存地址 R2 处,这部分代码是需要保护的操作。

  3. CPSIE if:恢复 IRQ 和 FIQ 中断,使处理器能够继续响应中断请求。

  4. 后续代码:将立即数 0 赋值给寄存器 R3,然后进入无限循环,程序继续执行。

注意事项

  • 在使用 CPSIE 恢复中断时,要确保关键代码段已经执行完毕,否则可能会导致数据不一致或程序出错。

  • 频繁地启用和禁用中断可能会影响系统的性能和稳定性,因此需要合理安排中断的屏蔽和恢复操作。

CPS - Change PE State

CPS(Change Processor State)指令是 ARM 架构里用于更改处理器状态的指令,它能对处理器的模式、中断屏蔽状态等进行控制。

指令功能

CPS 指令的主要功能是对处理器的状态进行改变,具体涵盖以下方面:

  • 中断屏蔽状态控制:可以屏蔽或者使能 IRQ(普通中断)和 FIQ(快速中断)。

  • 处理器模式切换:能够让处理器在不同的工作模式间进行切换,像用户模式、系统模式、管理模式等。

语法结构

CPS 指令的语法格式如下:

CPS{<cond>} <#op><#I><#F><#A> [, <mode>]
  • 参数解释:

    • <cond>:这是可选的条件码,用于指定指令执行的条件。只有当条件满足时,指令才会执行。常见的条件码有 EQ(相等)、NE(不相等)等。

    • <#op>:操作类型,有以下两种取值:

      • I:表示修改中断屏蔽状态。

      • M:表示修改处理器模式。

    • <#I>:控制 IRQ 中断屏蔽状态,有以下两种取值:

      • I:屏蔽 IRQ 中断。

      • i:使能 IRQ 中断。

    • <#F>:控制 FIQ 中断屏蔽状态,有以下两种取值:

      • F:屏蔽 FIQ 中断。

      • f:使能 FIQ 中断。

    • <#A>:控制异步异常(如调试异常)屏蔽状态,有以下两种取值:

      • A:屏蔽异步异常。

      • a:使能异步异常。

    • <mode>:可选参数,用于指定要切换到的处理器模式。常见的模式有:

      • #16:用户模式(User)。

      • #17:快速中断模式(FIQ)。

      • #18:普通中断模式(IRQ)。

      • #19:管理模式(Supervisor)。

      • #22:中止模式(Abort)。

      • #23:未定义指令模式(Undefined)。

      • #31:系统模式(System)。

使用场景

  • 中断管理:在执行关键代码时,为避免中断干扰,可以使用 CPS 指令屏蔽中断;关键代码执行完毕后,再使能中断。

  • 特权模式切换:在某些情况下,需要从用户模式切换到特权模式(如管理模式)来执行一些特权操作,这时可以使用 CPS 指令进行模式切换。

代码示例

以下是几个简单的示例,展示了 CPS 指令的使用:

示例 1:屏蔽 IRQ 和 FIQ 中断

    CPSID IF  ; 屏蔽 IRQ 和 FIQ 中断; 关键代码段; ...CPSIE IF  ; 使能 IRQ 和 FIQ 中断

示例 2:从用户模式切换到管理模式

    MRS R0, CPSR  ; 将当前程序状态寄存器(CPSR)的值读取到 R0BIC R0, R0, #0x1F  ; 清除模式位ORR R0, R0, #0x13  ; 设置为管理模式MSR CPSR_c, R0  ; 将修改后的值写回 CPSR; 或者使用 CPS 指令直接切换CPS #19  ; 切换到管理模式

代码解释

  • 示例 1:

    • CPSID IF 指令用于屏蔽 IRQ 和 FIQ 中断,保证关键代码段的执行不会被中断干扰;

    • CPSIE IF 指令用于使能 IRQ 和 FIQ 中断,让系统恢复正常的中断处理。

  • 示例 2:

    • 第一种方法通过 MRS、BIC、ORR 和 MSR 指令来修改程序状态寄存器(CPSR)的值,从而实现模式切换;

    • 第二种方法直接使用 CPS 指令将处理器模式切换到管理模式(模式编号为 19)。

注意事项

  • 在使用 CPS 指令进行模式切换时,要确保了解不同模式的权限和用途,避免因模式切换不当而导致系统异常。

  • 频繁地屏蔽和使能中断可能会影响系统的性能和稳定性,需要合理使用。

DSB - Data Synchronization Barrier

DSB(Data Synchronization Barrier)指令用于确保内存操作顺序和数据一致性的重要同步指令。

指令功能

在 ARM 处理器中,为了提高性能,内存操作(如读、写操作)可能会被乱序执行,即实际执行顺序可能与程序中编写的顺序不同。此外,不同的处理器核心或者硬件单元在访问内存时也可能存在缓存不一致等问题。

DSB 指令的主要功能就是作为一个同步屏障,确保在 DSB 指令之前的所有内存访问操作(包括数据读、写操作)都完成之后,才会执行 DSB 指令之后的内存访问操作。它可以保证数据的一致性和内存操作的顺序性,防止因内存操作乱序而导致的错误。

语法结构

DSB 指令的语法比较简单,其基本格式为:

DSB {<option>}
  • <option>:是可选参数,用于指定同步的范围和条件。常见的选项有:

    • SY:表示系统范围的同步,确保所有的内存访问操作(包括普通内存和设备内存)都完成。这是最常用的选项,如果不指定 <option>,默认就是 SY。

    • ISH:表示内部共享范围的同步,确保在同一个内部共享域(通常是同一个多核处理器中的所有核心)内的内存访问操作完成。

    • ISHST:表示内部共享范围的存储同步,只确保存储(写)操作完成。

使用场景

  • 设备驱动编程:在与硬件设备进行交互时,需要确保对设备寄存器的写操作已经完成,才能进行后续的操作。例如,在向设备发送控制命令后,使用 DSB 指令确保命令已经写入设备寄存器,然后再读取设备的状态寄存器。

  • 多核系统编程:在多核处理器系统中,不同核心之间可能会共享内存。当一个核心对共享内存进行写操作后,为了让其他核心能够及时看到更新后的数据,需要使用 DSB 指令确保写操作完成,然后再通过其他同步机制(如内存屏障指令)通知其他核心。

  • 中断处理:在中断处理程序中,可能会对共享数据进行操作。为了确保中断处理程序中的内存操作与主程序中的内存操作顺序正确,需要使用 DSB 指令进行同步。

代码示例

以下是一个简单的 ARM 汇编代码示例,展示了 DSB 指令在设备驱动编程中的使用:

    ; 向设备寄存器写入控制命令LDR R0, =0x40000000  ; 设备寄存器地址MOV R1, #0x01        ; 控制命令STR R1, [R0]         ; 将控制命令写入设备寄存器; 使用 DSB 指令确保写操作完成DSB SY; 读取设备状态寄存器LDR R2, [R0, #4]     ; 读取设备状态寄存器的值CMP R2, #0x02        ; 比较状态值BEQ SUCCESS          ; 如果状态值等于 0x02,跳转到 SUCCESS 标签; 错误处理B ERRORSUCCESS:; 处理成功情况B END_PROGRAMERROR:; 处理错误情况B END_PROGRAMEND_PROGRAM:B .                  ; 进入无限循环

代码解释

  1. 写操作:将控制命令 0x01 写入设备寄存器 0x40000000。

  2. DSB SY:使用 DSB 指令确保写操作已经完成,这样后续读取设备状态寄存器时,能够得到正确的结果。

  3. 读操作:读取设备状态寄存器的值,并与 0x02 进行比较。

  4. 后续处理:根据比较结果跳转到相应的处理标签进行处理。

注意事项

  • DSB 指令会带来一定的性能开销,因为它需要等待之前的内存操作完成。因此,在使用时需要权衡性能和数据一致性的需求,避免不必要的使用。

  • 不同的 option 选项适用于不同的场景,需要根据具体的系统架构和需求选择合适的选项。

ISB - Instruction Synchronization Barrier

ISB(Instruction Synchronization Barrier)指令用于确保指令执行顺序和指令缓存一致性的同步指令。

指令功能

在 ARM 处理器中,为了提高指令执行效率,会采用指令流水线、指令预取等技术,这可能会让指令的实际执行顺序和程序编写的顺序有所不同。另外,处理器的指令缓存(Instruction Cache)可能会存储旧的指令副本。

ISB 指令的主要功能是充当同步屏障,保证在 ISB 指令之后的指令从指令缓存或者内存中重新获取,并且按顺序执行,也就是确保 ISB 之后的指令不会受 ISB 之前指令执行顺序的影响。

语法结构

ISB 指令的语法较为简单,基本格式为:

ISB {<option>}
  • <option>:是可选参数,用于指定同步的范围和条件。常见选项有:

    • SY:表示系统范围的同步,确保所有指令都从指令缓存或内存中重新获取,这是最常用的选项。若不指定 <option>,默认就是 SY。

    • ISH:表示内部共享范围的同步,保证在同一个内部共享域(通常是同一个多核处理器里的所有核心)内指令的同步。

使用场景

  • 指令集切换:当从 ARM 指令集切换到 Thumb 指令集,或者反之,使用 ISB 指令可以确保新指令集的指令能正确获取和执行。

  • 程序流改变:在执行如 BX、BLX 这类改变程序执行流程的指令后,使用 ISB 指令能保证新的指令序列按顺序执行。

  • 内存映射寄存器更新:对内存映射的控制寄存器进行写操作后,若该操作会影响指令的执行,就需要使用 ISB 指令确保后续指令能正确响应这些改变。

代码示例

以下是一个简单的 ARM 汇编代码示例,展示了 ISB 指令在指令集切换时的使用:

    ; 假设当前处于 ARM 指令集模式MOV R0, #1           ; 加载立即数 1 到 R0ORR R0, R0, #1       ; 设置 R0 的最低位为 1,用于切换到 Thumb 模式BX R0                ; 切换到 Thumb 指令集; 使用 ISB 指令确保后续指令从新的指令集获取ISB SY; 以下是 Thumb 指令代码MOVS R1, #2          ; Thumb 指令:加载立即数 2 到 R1ADDS R1, R1, #1      ; Thumb 指令:R1 = R1 + 1B END_PROGRAM        ; 跳转到程序结束处END_PROGRAM:B .                  ; 进入无限循环

代码解释

  1. 指令集切换:借助 BX 指令,把 R0 的最低位设置为 1,从而切换到 Thumb 指令集。

  2. ISB SY:使用 ISB 指令确保后续的 Thumb 指令能从指令缓存或内存中重新获取,按顺序执行。

  3. Thumb 指令执行:执行 Thumb 指令,将立即数 2 加载到 R1,然后让 R1 的值加 1。

  4. 程序结束:跳转到 END_PROGRAM 标签,进入无限循环。

注意事项

  • ISB 指令会带来一定的性能开销,因为它需要清空指令流水线并重新获取指令。所以在使用时要权衡性能和指令执行顺序的需求,避免不必要的使用。

  • 不同的 <option> 选项适用于不同的场景,要根据具体的系统架构和需求选择合适的选项。

相关文章:

[ARM][汇编] 02.ARM 汇编常用简单指令

目录 1.数据传输指令 MRS - Move from Status Register 指令用途 指令语法 代码示例 读取 CPSR 到通用寄存器 在异常处理程序中读取 SPSR 使用场景 MSR - Move to Status Register 指令语法 使用场景 示例代码 改变处理器模式为管理模式 设置条件标志位 异常处理…...

系统架构设计(十七):微服务数据一致性和高可用策略

数据一致性问题 问题本质 由于每个微服务拥有独立数据库&#xff0c;跨服务操作不能用传统的数据库事务&#xff0c;面临“分布式事务”一致性挑战。 数据一致性策略 策略核心思想应用场景优缺点强一致性&#xff08;Strong Consistency&#xff09;所有操作实时同步成功&a…...

[Harmony]获取设备参数

获取屏幕宽度/屏幕高度/状态栏高度/导航栏高度/刘海高度/设备型号/系统版本号... DevicesUtil import window from ohos.window; import { common } from kit.AbilityKit; import display from ohos.display; import deviceInfo from ohos.deviceInfo; import i18n from ohos.…...

Python60日基础学习打卡D31

如何把一个文件&#xff0c;拆分成多个具有着独立功能的文件&#xff0c;然后通过import的方式&#xff0c;来调用这些文件&#xff1f;这样具有几个好处&#xff1a; 可以让项目文件变得更加规范和清晰可以让项目文件更加容易维护&#xff0c;修改某一个功能的时候&#xff0…...

命名常量集合接口INamedConstantCollection<T>实现

public interface INamedConstantCollection<TObject, TName> : IEnumerable<TObject>, IEnumerable where TName : IComparable{TObject this[TName name] { get; }TObject this[int index] { get; }int Count { get; }int Capacity { get; }} 这是一个泛型接口&…...

TYUT-企业级开发教程-第6章

这一章 考点不多 什么是缓存&#xff1f;为什么要设计出缓存&#xff1f; 企业级应用为了避免读取数据时受限于数据库的访问效率而导致整体系统性能偏低&#xff0c;通 常会在应用程序与数据库之间建立一种临时的数据存储机制&#xff0c;该临时存储数据的区域称 为缓存。缓存…...

反射在spring boot自动配置的应用

目录 一&#xff0c;背景 二&#xff0c;知识回顾 2.1 理解使用反射技术&#xff0c;读取配置文件创建目标对象&#xff08;成员变量&#xff0c;方法&#xff0c;构造方法等&#xff09; 三&#xff0c;springboot自动配置 3.1 反射在自动配置中的工作流程 3.2 浏览源码…...

项目进度延误,如何按时交付?

项目进度延误可以通过加强计划管理、优化资源分配、强化团队沟通、设置关键里程碑和风险管理机制等方式来实现按时交付。加强计划管理、优化资源分配、强化团队沟通、设置关键里程碑、风险管理机制。其中&#xff0c;加强计划管理尤为关键&#xff0c;因为明确而详细的计划能提…...

内网穿透:轻松实现外网访问本地服务

异步通知的是需要通过外网的域名地址请求到的&#xff0c;由于我们还没有真正上线&#xff0c;那支付平台如何请求到我们本地服务的呢&#xff1f; 这里可以使用【内网穿透】技术来实现&#xff0c;通过【内网穿透软件】将内网与外网通过隧道打通&#xff0c;外网可以读取内网…...

缺乏进度跟踪机制,如何掌握项目状态?

要有效掌握项目状态&#xff0c;必须建立明确的进度跟踪机制、使用专业的项目管理工具、定期召开沟通会议、设立清晰的关键里程碑和实施风险监控。其中&#xff0c;建立明确的进度跟踪机制是关键&#xff0c;通过系统地追踪项目各个阶段的完成情况&#xff0c;及时发现问题并采…...

ES 调优帖:关于索引合并参数 index.merge.policy.deletePctAllowed 的取值优化

最近发现了 lucene 9.5 版本把 merge 策略的默认参数改了。 * GITHUB#11761: TieredMergePolicy now allowed a maximum allowable deletes percentage of down to 5%, and the defaultmaximum allowable deletes percentage is changed from 33% to 20%. (Marc DMello)也就是…...

基于 STM32 单片机的实验室多参数安全监测系统设计与实现

一、系统总体设计 本系统以 STM32F103C8T6 单片机为核心,集成温湿度监测、烟雾检测、气体泄漏报警、人体移动监测等功能模块,通过 OLED 显示屏实时显示数据,并支持 Wi-Fi 远程传输。系统可对实验室异常环境参数(如高温、烟雾、燃气泄漏)及非法入侵实时报警,保障实验室安…...

Spring Boot-Swagger离线文档(插件方式)

Swagger2Markup简介 Swagger2Markup是Github上的一个开源项目。该项目主要用来将Swagger自动生成的文档转换成几种流行的格式以便于静态部署和使用&#xff0c;比如&#xff1a;AsciiDoc、Markdown、Confluence。 项目主页&#xff1a;https://github.com/Swagger2Markup/swagg…...

Linux下Docker使用阿里云镜像加速器

在中国大陆环境中配置 Docker 使用阿里云镜像加速器&#xff0c;并确保通过 Clash 代理访问 Docker Hub 我这里用的Debian12。 步骤 1&#xff1a;获取阿里云镜像加速器地址 登录阿里云容器镜像服务控制台&#xff1a;(qinyang.wang) 网址&#xff1a;阿里云登录 - 欢迎登录阿…...

每日c/c++题 备战蓝桥杯(洛谷P1440 求m区间内的最小值 详解(单调队列优化))

洛谷P1440 求m区间最小值&#xff1a;单调队列优化详解&#xff08;从暴力到O(n)的蜕变&#xff09; tags: [算法, 数据结构, 滑动窗口, 洛谷, C] 引言 在处理序列数据的区间查询问题时&#xff0c;暴力枚举往往难以应对大规模数据。本文以洛谷P1440为切入点&#xff0c;深入…...

从代码学习深度学习 - 预训练word2vec PyTorch版

文章目录 前言辅助工具1. 绘图工具 (`utils_for_huitu.py`)2. 数据处理工具 (`utils_for_data.py`)3. 训练辅助工具 (`utils_for_train.py`)预训练 Word2Vec - 主流程1. 环境设置与数据加载2. 跳元模型 (Skip-gram Model)2.1. 嵌入层 (Embedding Layer)2.2. 定义前向传播3. 训练…...

OpenCV图像边缘检测

1.概念 图像边缘检测是计算机视觉和图像处理中的基础任务&#xff0c;用于识别图像中像素值发生剧烈变化的区域&#xff0c;这些区域通常对应物体的边界、纹理变化或噪声。 1.1原理 图像中的边缘通常表现为灰度值的突变&#xff08;如从亮到暗或从暗到亮的急剧变化&#xff09…...

AI能源危机:人工智能发展与环境可持续性的矛盾与解决之道

AI对能源的渴求正在演变成一个巨大的挑战。这不仅仅关乎电费支出&#xff0c;其环境影响也十分严重&#xff0c;包括消耗宝贵的水资源、产生大量电子垃圾&#xff0c;以及增加温室气体排放。 随着AI模型变得越来越复杂并融入我们生活的更多领域&#xff0c;一个巨大的问题悬而…...

基于flask+vue的电影可视化与智能推荐系统

基于flaskvue爬虫的电影数据的智能推荐与可视化系统&#xff0c;能展示电影评分、评论情感分析等直观的数据可视化图表&#xff0c;还能通过协同过滤算法为用户提供个性化电影推荐&#xff0c;帮助用户发现更多感兴趣的电影作品&#xff0c;具体界面如图所示。 本系统主要技术架…...

初步认识HarmonyOS NEXT端云一体化开发

视频课程学习报名入口:HarmonyOS NEXT端云一体化开发 1、课程设计理念 本课程采用"四维能力成长模型"设计理念,通过“能看懂→能听懂→能上手→能实战”的渐进式学习路径,帮助零基础开发者实现从理论认知到商业级应用开发的跨越。该模型将学习过程划分为四个维度…...

基于单片机的车辆防盗系统设计与实现

标题:基于单片机的车辆防盗系统设计与实现 内容:1.摘要 随着汽车保有量的不断增加&#xff0c;车辆被盗问题日益严峻&#xff0c;车辆防盗成为人们关注的焦点。本研究的目的是设计并实现一种基于单片机的车辆防盗系统。采用单片机作为核心控制单元&#xff0c;结合传感器技术、…...

LSM Tree算法原理

LSM Tree(Log-Structured Merge Tree)是一种针对写密集型场景优化的数据结构,广泛应用于LevelDB、RocksDB等数据库引擎中。其核心原理如下: ‌1. 写入优化:顺序写代替随机写‌ ‌内存缓冲(MemTable)‌:写入操作首先被写入内存中的数据结构(如跳表或平衡树),…...

通过 API 获取 1688 平台店铺所有商品信息的完整流程

在电商运营和数据分析中&#xff0c;获取 1688 平台店铺的商品信息是一项重要的任务。1688 作为国内领先的 B2B 电商平台&#xff0c;提供了丰富的开放平台 API 接口&#xff0c;方便开发者获取店铺商品的详细信息。本文将详细介绍如何通过 Python 调用 1688 的 API 接口&#…...

Python代码加密与发布方案详解

更多内容请见: python3案例和总结-专栏介绍和目录 文章目录 一、基础加密方案二、商业级加密方案三、高级混淆方案四、商业化发布方案五、反逆向技术六、最佳实践建议七、常见问题解决Python作为解释型语言,其源代码容易被查看和修改。本文将详细介绍多种Python代码保护方案,…...

Tractor S--二维转一维,然后最小生成树

P3073 [USACO13FEB] Tractor S - 洛谷 转成一维点图&#xff0c;然后最小生成树&#xff0c;最后的最大值就是最后一个点&#xff0c;记得记录维护连通块 同样的二维转一维---Cow Ski Area G---二维图转一维tarjan缩点-CSDN博客 #include<bits/stdc.h> using namespac…...

5月20日day31打卡

文件的规范拆分和写法 知识点回顾 规范的文件命名规范的文件夹管理机器学习项目的拆分编码格式和类型注解 作业&#xff1a;尝试针对之前的心脏病项目&#xff0c;准备拆分的项目文件&#xff0c;思考下哪些部分可以未来复用。 补充介绍&#xff1a; pyc文件的介绍 知识点回顾 …...

基于Spring Boot + Vue的教师工作量管理系统设计与实现

一、项目简介 随着高校信息化管理的发展&#xff0c;教师工作量管理成为教务系统中不可或缺的一部分。为此&#xff0c;我们设计并开发了一个基于 Spring Boot Vue 的教师工作量管理系统&#xff0c;系统结构清晰&#xff0c;功能完备&#xff0c;支持管理员和教师两个角色。…...

海康工业相机白平衡比选择器对应的值被重置后,如何恢复原成像

做项目的时候&#xff0c;有时候手抖&#xff0c;一不小心把一个成熟稳定的项目的相机配置&#xff0c;重置了&#xff0c;如何进行恢复呢&#xff0c;在不知道之前配置数据的情况下。 我在做项目的时候&#xff0c;为了让这个相机成像稳定一点&#xff0c;尤其是做颜色检测时…...

VMWare清理后,残留服务删除方案详解

VMWare清理后&#xff0c;残留服务删除方案详解 在虚拟化技术日益普及的今天&#xff0c;VMWare作为行业领先的虚拟化软件&#xff0c;广泛应用于企业和服务器的管理中。然而&#xff0c;由于其复杂的架构和深层次的系统集成&#xff0c;VMWare的卸载过程往往并不顺利。即使通…...

STM32定时器简单采集编码器脉冲

MCU&#xff1a;STM32H723ZGT6 编码器&#xff1a;&#xff08;欧姆龙&#xff09;E6B2-CWZ1X&#xff1b;1000P/R&#xff1b;8根线信号线分别为 A A- B B- Z Z- 以及5V和GND&#xff1b; A 脉冲输出 B 脉冲输出 Z 零点信号 当编码器旋转到零点时&#xff0c;Z信号会发出一个脉…...

第 4 章:网络与总线——CAN / Ethernet / USB-OTG

本章目标: 深入理解三种关键通信总线(CAN、Ethernet、USB-OTG)的协议架构、硬件接口与软件驱动 掌握 STM32(或同类 MCU)中各总线的寄存器配置、中断/DMA 驱动框架 通过实战案例,实现基于 CAN 总线的节点通信、基于 Ethernet 的 TCP/IP 通信,以及基于 USB-OTG 的虚拟串口…...

【python进阶知识】Day 31 文件的规范拆分和写法

知识点 规范的文件命名规范的文件夹管理机器学习项目的拆分编码格式和类型注解 机器学习流程 - 数据加载&#xff1a;从文件、数据库、API 等获取原始数据。 - 命名参考&#xff1a;load_data.py 、data_loader.py - 数据探索与可视化&#xff1a;了解数据特性&#xff0c;初期…...

leetcode 162. Find Peak Element

题目描述 如果nums[i-1]<nums[i]并且nums[i]>nums[i1]&#xff0c;那么nums[i]就是峰值。除此情况之外&#xff0c;nums[i-1]和nums[i1]至少有一个大于nums[i]&#xff0c;因为题目已经保证相邻的元素不相等。坚持向上坡方向走一定能达到一个峰值&#xff0c;如果往两边走…...

2025系统架构师---案例题(押题)

1. 微服务相关的概念: 微服务是一种架构风格,它将单体应用划分为一组小服务,服务之间相互协作,实现业务功能每个服务运行在独立的进程中,服务间采用轻量级的通信机制协作(通常是HTTP/JSON),每个服务围绕业务能力进行构建,并且能够通过自动化机制独立的部署。 微服务有…...

t检验详解:原理、类型与应用指南

t检验详解&#xff1a;原理、类型与应用指南 t检验&#xff08;t-test&#xff09;是一种用于比较两组数据均值是否存在显著差异的统计方法&#xff0c;适用于数据近似正态分布且满足方差齐性的场景。以下从核心原理、检验类型、实施步骤到实际应用进行系统解析。 一、t检验的…...

使用 OpenCV 实现万花筒效果

万花筒效果&#xff08;Kaleidoscope Effect&#xff09;是一种图像处理效果&#xff0c;通过对图像进行对称旋转或镜像处理&#xff0c;产生具有多重反射和对称的艺术效果。它常用于视频编辑、视觉艺术、游戏设计等领域&#xff0c;为图像添加富有创意和视觉冲击力的效果。 在…...

Rocketmq broker 是主从架构还是集群架构,可以故障自动转移吗

RocketMQ Broker的架构与故障转移机制 RocketMQ的Broker架构同时采用了主从架构和集群架构&#xff0c;并且支持故障自动转移。下面详细说明&#xff1a; 一、架构类型 1. 集群架构 RocketMQ天然支持分布式集群部署 一个RocketMQ集群包含多个Broker组(每组有主从) 不同Bro…...

MySQL中添加一个具有创建数据库权限的用户

要在MySQL中添加一个具有创建数据库权限的用户&#xff0c;可按以下步骤操作&#xff1a; 1. 登录MySQL 使用拥有足够权限&#xff08;一般是root用户 &#xff09;的账号登录到MySQL数据库。在命令行输入&#xff1a; mysql -u root -p然后输入对应的密码&#xff0c;即可进…...

Go语言使用通义灵码辅助开发 - AI编程助手提升效率

一、引言 Go 语言以其高效性能和简洁语法&#xff0c;成为构建微服务、分布式系统及高性能后端的首选。对于有其他语言编程经验的开发者和初学者&#xff0c;入门 Go 语言时&#xff0c;如何快速开发第一个程序是关键。传统方式如慢慢摸索、向老师请教或查找资料&#xff0c;效…...

演示:【WPF-WinCC3D】 3D工业组态监控平台源代码

一、目的&#xff1a;分享一个应用WPF 3D开发的3D工业组态监控平台源代码 二、功能介绍 WPF-WinCC3D是基于 WPF 3D研发的工业组态软件&#xff0c;提供将近200个预置工业模型&#xff08;机械手臂、科幻零部件、熔炼生产线、机加生产线、管道等&#xff09;&#xff0c;支持组态…...

Oracle资源管理器

14.8资源管理器 14.8.1资源管理器的功能和控制种类 传统意义上&#xff0c;系统的资源分配是由 OS 来完成的&#xff0c;但是对于数据库资源&#xff0c;OS 分配资源会带来一些问题。以 Linux 为例&#xff0c;最为突出的一个问题是&#xff1a;Linux 的资源调度是基于进程的&…...

下载Ubuntu 64 位

学习目标&#xff1a; 下载 学习内容&#xff1a; 学习时间&#xff1a; 学习时间为学习时间 学习时间筋肉人为学习时间future 内容为笔记【有时比较抽象&#xff0c;有时比较过于详细&#xff0c;请宽恕。作者可能写的是仅个人笔记&#xff0c;筋肉人future】 学习产出&…...

ubuntu14.04/16.06 安装vscode(实测可以用)

地址&#xff1a;https://code.visualstudio.com/updates/v1_38 选择deb 这个版本还支持ubuntu14.04和16.06 sudo dpkg -i code_1.38.1-1568209190_amd64.deb sudo apt-get install -f安装成功&#xff0c;正常使用...

Linux命令大全

前言&#xff1a;工作中或多或少都会用到Linux服务器&#xff0c;我为大家分享一下常用命令 一丶文件与目录操作 命令作用示例ls列出目录内容ls -l&#xff08;详细列表&#xff09;cd切换目录cd /homepwd显示当前目录路径pwdmkdir创建目录mkdir -p dir1/dir2&#xff08;递归…...

spark的缓存提升本质以及分区数量和task执行时间的先后

文章目录 示例代码缓存效果分析第1次 user.count第2次 user.count——这里解释了spark缓存提升的本质原因关于分区数量和task数量以及task的执行流程有多少个分区就有多少线程task并发执行不同分区数量对计算效率的提升 示例代码 import org.apache.spark.storage.StorageLeve…...

SQL次日留存率计算精讲:自连接与多字段去重的深度应用

一、问题拆解&#xff1a;理解次日留存率的计算逻辑 1.1 业务需求转换 题目&#xff1a;运营希望查看用户在某天刷题后第二天还会再来刷题的留存率。 关键分析点&#xff1a; 留存率 &#xff08;第一天刷题且第二天再次刷题的用户数&#xff09; / 第一天刷题的总用户数需…...

PostgreSQL初体验

目录 一&#xff1a;PostgreSQL 1.简介 3.优势 4.架构 5.应用场景 6.结论 二&#xff1a;安装PostgreSQL 1.编译安装 三&#xff1a;PostgreSQL架构 1.PG的逻辑结构 2.PG的物理结构 前言 在数据驱动的时代&#xff0c;掌握 PostgreSQL 这一全球顶尖的开源关系型数据…...

Vue 3.0 Transition 组件使用详解

Vue 3.0 的 Transition 组件提供了一种简单的方式来为元素或组件的进入/离开添加动画效果。下面是使用<script setup>语法糖的实现方式。 1. 基本用法 使用场景&#xff1a;当需要为元素的显示/隐藏添加简单的淡入淡出效果时&#xff0c;这是最基础的过渡实现方式。 &…...

深入浅出IIC协议 - 从总线原理到FPGA实战开发 -- 第三篇:Verilog实现I2C Master核

第三篇&#xff1a;Verilog实现I2C Master核 副标题 &#xff1a;从零构建工业级I2C控制器——代码逐行解析与仿真实战 1. 架构设计 1.1 模块分层设计 三层架构 &#xff1a; 层级功能描述关键信号PHY层物理信号驱动与采样sda_oe, scl_oe控制层协议状态机与数据流控制state…...

通义灵码助力JavaScript开发:快速获取API与智能编码技巧

一、引言 JavaScript 拥有丰富的 API 生态&#xff0c;从浏览器的 Web API 到 Node.js 的环境生态&#xff0c;为开发者提供了强大的工具和库。然而&#xff0c;面对如此庞大的生态系统&#xff0c;开发者常常需要花费大量时间翻阅文档来查找和学习如何使用这些 API。通义灵码…...