ARM指令汇总

学习ARM指令汇编时,发现很多博客的都不全,因此在学习过程中完善一下,没有按照任何顺序,本文会在接下来一段时间内不定期更新。

ARM指令集

AREA:

伪操作,用来标识一个段的起始、段名和段的读写属性。
eg:
AREA COPY,CODE,READONLY ;段名为COPY,属性为代码段,只读
AREA COPYDATA,DATA,READWRITE ;段名为DCOPYDATA,属性为数据段,读写

S:

指令后面加S,表示影响标志位
eg: SUBS R2,R2.#1 ;R2的值减1后存入R2,S代表影响标志位

ENTRY / END:

ENTRY 伪操作用来标识汇编程序的运行入口, END伪操作用来标识汇编程序的结束。 使用 ; 注释代码

局部标号

引用格式:%{F|B|A|T} N{routname}
%: 引用符号,对一个局部标号产生引用。
F:指示编译器只向前搜索。B:指示编译器只向后搜索
A:指示编译器搜索宏的所有宏命令层。T:指示编译器搜索宏的当前层
N:局部标号的名字。routename:局部标号的作用范围名称,使用ROUT定义

eg: BNE %B0 ;跳转到局部标号0处

GBLA / GBLL / GBLS /LCLA / LCLL / LCLS

定义数据
eg:
GBLA a ;定义一个全局算术变量a, 并初始化为0
GBLL a ;定义一个全局逻辑变量a, 并初始化为{false}
GBLS a ;定义一个全局字符串变量a,并初始化为0
LCLA a ;定义一个局部算术变量a,并初始化为0
LCLL a ;定义一个局部逻辑变量a,并初始化为{false}
LCLS a ;定义一个局部字符串变量a,并初始化为0

SETA /SETL /SETS

赋值
eg:
a SETA 10 ;给算术变量a赋值为10
a SETL 10 ;给逻辑变量a赋值为10
a SETS “ss” ;给字符串变量a赋值为“ss”

DCD / DCB / SPACE / DATA

数据定义
DATA1 DCB 10,20,30,40 ;分配一片连续的字节存储单元并初始化
DATA2 DCD 10,20,30,40 ;分配一片连续的字存储单元并初始化
BUF SPACE 100 ;给BUF分配100字节的存储单元并初始化为0

=

LDR 伪指令的操作数前一般会有一个 = ,用来表示该指令是个伪指令
eg : LDR R0,=200 ;往寄存器传递一个立即数
注意:MOV指令不能传递内存地址是32位的立即数。
因此LDR伪指令主要是用来将一个32位的内存地址保存到寄存器中。

ALIGN

地址对齐

CODE16 / CODE32

指示编译器后面的指令为THUMB/ARM指令

EXPORT

声明一个全局符号,可以被其他文件引用

IMPORT

引用其他文件的全局符号前,要先IMPORT声明

参考的别人的文章

原文链接:https://blog.csdn.net/Luckiers/article/details/128221506

2.1 32位数据操作指令
名字 功能
ADC 带进位加法
ADD 加法
ADDW 宽加法(可以加 12 位立即数)
AND 按位与
ASR 算术右移
BIC 位清零(把一个数按位取反后,与另一个数逻辑与)
BFC 位段清零
BFI 位段插入
CMN 负向比较(把一个数和另一个数的二进制补码比较,并更新标志位)
CMP 比较两个数并更新标志位
CLZ 计算前导零的数目
EOR 按位异或
LSL 逻辑左移
LSR 逻辑右移
MLA 乘加
MLS 乘减
MOVW 把 16 位立即数放到寄存器的底16位,高16位清0
MOV 加载16位立即数到寄存器(其实汇编器会产生MOVW——译注)
MOVT 把 16 位立即数放到寄存器的高16位,低 16位不影响
MVN 移动一个数的补码
MUL 乘法
ORR 按位或
ORN 把源操作数按位取反后,再执行按位或(
RBIT 位反转(把一个 32 位整数先用2 进制表达,再旋转180度——译注)
REV 对一个32 位整数做按字节反转
REVH/REV16 对一个32 位整数的高低半字都执行字节反转
REVSH 对一个32 位整数的低半字执行字节反转,再带符号扩展成32位数
ROR 圆圈右移
RRX 带进位的逻辑右移一格(最高位用C 填充,且不影响C的值——译注)
SFBX 从一个32 位整数中提取任意的位段,并且带符号扩展成 32 位整数
SDIV 带符号除法
SMLAL 带符号长乘加(两个带符号的 32 位整数相乘得到 64 位的带符号积,再把积加到另一个带符号 64位整数中)
SMULL 带符号长乘法(两个带符号的 32 位整数相乘得到 64位的带符号积)
SSAT 带符号的饱和运算
SBC 带借位的减法
SUB 减法
SUBW 宽减法,可以减 12 位立即数
SXTB 字节带符号扩展到32位数
TEQ 测试是否相等(对两个数执行异或,更新标志但不存储结果)
TST 测试(对两个数执行按位与,更新标志但不存储结果)
UBFX 无符号位段提取
UDIV 无符号除法
UMLAL 无符号长乘加(两个无符号的 32 位整数相乘得到 64 位的无符号积,再把积加到另一个无符号 64位整数中)
UMULL 无符号长乘法(两个无符号的 32 位整数相乘得到 64位的无符号积)
USAT 无符号饱和操作(但是源操作数是带符号的——译注)
UXTB 字节被无符号扩展到32 位(高24位清0——译注)
UXTH 半字被无符号扩展到32 位(高16位清0——译注)
2.2 32位存储器数据传送指令
名字 功能
LDR 加载字到寄存器
LDRB 加载字节到寄存器
LDRH 加载半字到寄存器
LDRSH 加载半字到寄存器,再带符号扩展到 32位
LDM 从一片连续的地址空间中加载多个字到若干寄存器
LDRD 从连续的地址空间加载双字(64 位整数)到2 个寄存器
STR 存储寄存器中的字
STRB 存储寄存器中的低字节
STRH 存储寄存器中的低半字
STM 存储若干寄存器中的字到一片连续的地址空间中
STRD 存储2 个寄存器组成的双字到连续的地址空间中
PUSH 把若干寄存器的值压入堆栈中
POP 从堆栈中弹出若干的寄存器的值
2.3 32位转移指令
名字 功能
B 无条件转移
BL 转移并连接(呼叫子程序)
TBB 以字节为单位的查表转移。从一个字节数组中选一个8位前向跳转地址并转移
TBH 以半字为单位的查表转移。从一个半字数组中选一个16 位前向跳转的地址并转移
2.4 其它32位指令
名字 功能
LDREX 加载字到寄存器,并且在内核中标明一段地址进入了互斥访问状态
LDREXH 加载半字到寄存器,并且在内核中标明一段地址进入了互斥访问状态
LDREXB 加载字节到寄存器,并且在内核中标明一段地址进入了互斥访问状态
STREX 检查将要写入的地址是否已进入了互斥访问状态,如果是则存储寄存器的字
STREXH 检查将要写入的地址是否已进入了互斥访问状态,如果是则存储寄存器的半字
STREXB 检查将要写入的地址是否已进入了互斥访问状态,如果是则存储寄存器的字节
CLREX 在本地的处理上清除互斥访问状态的标记(先前由 LDREX/LDREXH/LDREXB做的标记)
MRS 加载特殊功能寄存器的值到通用寄存器
MSR 存储通用寄存器的值到特殊功能寄存器
NOP 无操作
SEV 发送事件
WFE 休眠并且在发生事件时被唤醒
WFI 休眠并且在发生中断时被唤醒
ISB 指令同步隔离(与流水线和 MPU等有关——译注)
DSB 数据同步隔离(与流水线、MPU 和cache等有关——译注)
DMB 数据存储隔离(与流水线、MPU 和cache等有关——译注)
DMB 数据存储器隔离。DMB 指令保证: 仅当所有在它前面的存储器访问操作都执行完毕后,才提交(commit)在它后面的存储器访问操作。
DSB 数据同步隔离。比 DMB 严格: 仅当所有在它前面的存储器访问操作都执行完毕后,才执行在它后面的指令(亦即任何指令都要等待存储器访 问操作——译者注)
ISB 指令同步隔离。最严格:它会清洗流水线,以保证所有它前面的指令都执行完毕之后,才执行它后面的指令。
三、实例讲解
3.1 MRS

将CPSR或SPSR的内容移动到一个通用寄存器

MRS R0,CPSR //传送CPSR的内容到R0
MRS R0,SPSR //传送 SPSR的内容到R0

1
2

3.2 MSR

将立即数或通用寄存器的内容加载到CPSR或SPSR的指定字段中

MSR CPSR,R0 //传送R0的内容到CPSR
MSR SPSR,R0 //传送R0的内容到SPSR
MSR CPSR_c,R0 //传送R0的内容到SPSR,但仅仅修改CPSR中的控制位域

1
2
3

3.3 PRIMASK

用于disable NMI和硬 fault之外的所有异常,它有效地把当前优先级改为 0(可编程 优先级中的最高优先级)。
CPS指令会更改CPSR中的一个或多个模式以及A、I和F位,但不更改其他CPSR位。CPSID就是中断禁止,CPSIE中断允许,

A:表示启用或禁止不精确的中止;I:表示启用或禁止IRQ中断;F:表示启用或禁止FIQ中断
3.4 FAULTMASK

CPSIE f; / CPSID f;

MSR FAULTMASK,R0

1
2
3

FAULTMASK更绝,它把当前优先级改为-1。这么一来,连硬fault都被掩蔽了。使用方案与
PRIMASK的相似。但要注意的是,FAULTMASK会在异常退出时自动清零。
3.5 BX指令

BX{条件} 目标地址
BX 指令跳转到指令中所指定的目标地址,目标地址处的指令既可以是ARM 指令,也可以是Thumb指令。
3.6 零寄存器 wzr、xzr

因为我们在使用 str 的是没法使用立即数 0 给寄存器赋值,所以 wzr xzr就是干这个事情的。是一个比较特殊又常常见到的寄存器。
3.7 立即寻址指令

SUBS R0,R0,#1 //R0 减 1 ,结果放入 R0 ,并且影响标志位
MOV R0,#0xFF000 //将立即数 0xFF000 装入 R0 寄存器 寄存器寻址指令举例如下:
MOV R1,R2 //将 R2 的值存入 R1
SUB R0,R1,R2 //将 R1 的值减去 R2 的值,结果保存到 R0

1
2
3
4

3.8 寄存器间接寻址指令

LDR R1,[R2] //将 R2 指向的存储单元的数据读出保存在 R1 中
SWP R1,R1,[R2] //将寄存器 R1 的值和 R2 指定的存储单元的内容交换,将R2的数值作为一个地址,将此地址处的数值与R1中的内容交换

1
2

3.9 寄存器移位寻址指令

MOV R0,R2,LSL #3 //R2 的值左移 3 位,结果放入R0 ,即是R0=R2×8
ANDS R1,R1,R2,LSL R3 //R2 的值左移 R3 位,然后和R1相“与”操作,结果放入R1

1
2

3.10 基址寻址指令

LDR R2,[R3,#0x0C] //读取 R3+0x0C 地址上的存储单元的内容,放入 R2
STR R1,[R0,#-4]! //先 R0=R0-4 ,然后把 R1 的值寄存到 R0 指定的存储单元

1
2

3.11 多寄存器寻址指令

LDMIA R1!,{R2-R7,R12} //将 R1 指向的单元中的数据读出到R2 ~R7、R12 中 (R1自动加1)
STMIA R0!,{R2-R7,R12} //将寄存器 R2 ~ R7 、 R12 的值保存到 R0 指向的存储单元中(R0自动加1)

1
2

3.12 无条件转移B,BAL

举例: B LABEL ; LABEL为某个位置

CMP x3,x4
B.CS {pc}+0x10 ; 0xc000800094

1
2

BCC是指CPSR寄存器条件标志位为0时的跳转。结合CMP R3, R1,意思是比较R3 R1寄存器,当相等时跳转到环测试。因为CMP指令减去两个值并在CPSR中设置条件标志位。
3.13 条件转移

BEQ 相等
BNE 不等
BPL 非负
BMI 负
BCC 无进位
BCS 有进位
BLO 小于(无符号数)
BHS 大于等于(无符号数)
BHI 大于(无符号数)
BLS 小于等于(无符号数)
BVC 无溢出(有符号数)
BVS 有溢出(有符号数)
BGT 大于(有符号数)
BGE 大于等于(有符号数)
BLT 小于(有符号数)
BLE 小于等于(有符号数)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

blr Xm:跳转到由Xm目标寄存器指定的地址处,同时将下一条指令存放到X30寄存器中。例如:blr x20.
br Xm:跳转到由Xm目标寄存器指定的地址处。不是子程序返回
ret {Xm}:跳转到由Xm目标寄存器指定的地址处。是子程序返回。Xm可以不写,默认是X30.

1
2
3

3.14 WFE 和 WFI 对比

wfi 和 wfe 指令都是让ARM核进入standby睡眠模式。wfi是直到有wfi唤醒事件发生才会唤醒CPU,wfe是直到wfe唤醒事件发生,这两类事件大部分相同。唯一不同之处在于wfe可以被其他CPU上的sev指令唤醒,sec指令用于修改event寄存器的指令。

WFE
Wait For Event,是否实现此指令是可选的。如果此指令未实现,它将作为NOP指令来执行。如果指令作为NOP在目标处理器上执行,汇编程序将生成诊断消息。

SEV
Set Event,其是否实现是可选的。如果未实现,它将作为NOP执行。如果指令作为NOP在目标上执行,汇编程序将生成诊断消息。
SEV在ARMv6T2中作为NOP指令执行。

IMPORT |Image R W I R A M 1 RW_IRAM1 RWIRAM1Base| //从别处导入data段的链接地址
IMPORT |Image R W I R A M 1 RW_IRAM1 RWIRAM1Length| //从别处导入data段的长度
IMPORT |Load R W I R A M 1 RW_IRAM1 RWIRAM1Base| //从别处导入data段的加载地址
IMPORT |Image R W I R A M 1 RW_IRAM1 RWIRAM1ZI B a s e ∣ / / 从别处导入 Z I 段的链接地址 I M P O R T ∣ I m a g e Base| //从别处导入ZI段的链接地址 IMPORT |Image Base∣//从别处导入ZI段的链接地址IMPORTImageRW_IRAM1 Z I ZI ZILength| //从别处导入ZI段的长度
Load r e g i o n n a m e region_name regionnameBase //Load address of the region.
Load r e g i o n n a m e region_name regionnameLength //Region length in bytes.
Load r e g i o n n a m e region_name regionnameLimit //Address of the byte beyond the end of the execution region.

1
2
3
4
5
6
7
8

//复制数据段
LDR R0, = |Load R W I R A M 1 RW_IRAM1 RWIRAM1Base| //将data段的加载地址存入R0寄存器
LDR R1, = |Image R W I R A M 1 RW_IRAM1 RWIRAM1Base| //将data段的链接地址存入R1寄存器
LDR R2, = |Image R W I R A M 1 RW_IRAM1 RWIRAM1Length| //将data段的长度存入R2寄存器
CopyData
SUB R2, R2, #4 //每次复制4个字节的data段数据
LDR R3, [R0, R2] //把加载地址处的值取出到R3寄存器
STR R3, [R1, R2] //把取出的值从R3寄存器存入到链接地址
CMP R2, #0 //将计数和0相比较
BNE CopyData //如果不相等,跳转到CopyData标签处,相等则往下执行

//清除BSS段
LDR R0, = |Image R W I R A M 1 RW_IRAM1 RWIRAM1ZI B a s e ∣ / / 将 b s s 段的链接地址存入 R 1 寄存器 L D R R 1 , = ∣ I m a g e Base| //将bss段的链接地址存入R1寄存器 LDR R1, = |Image Base∣//bss段的链接地址存入R1寄存器LDRR1,=ImageRW_IRAM1 Z I ZI ZILength| //将bss段的长度存入R2寄存器
CleanBss
SUB R1, R1, #4 //每次清除4个字节的bss段数据
MOV R3, #0 //将0存入r3寄存器
STR R3, [R0, R1] //把R3寄存器存入到链接地址
CMP R1, #0 //将计数和0相比较
BNE CleanBss //如果不相等,跳转到CleanBss标签处,相等则往下执行

IMPORT mymain //通知编译器要使用的标号在其他文件
BL mymain //跳转去执行main函数
B . //原地跳转,即处于循环状态
ENDP
ALIGN //填充字节使地址对齐
END //整个汇编文件结束

在C程序中内嵌汇编代码

_asm

使用_asm关键字,在c程序中内嵌ARM汇编代码
格式:
_asm
{
指令 /* 注释*/

指令
}
注意 :在内嵌的汇编代码中添加注释,仍要使用c语言的注释符

不同的编译器可能使用不同的关键字
如:GNU ARM编译器,asm 关键字
asm 关键字 还可以用_volatile_ 修饰,表示告诉编译器不用优化这段代码
eg:asm volatile

在汇编程序中调用c程序

调用时需要根据ATPCS规则来完成参数的传递,并配置好c程序传递参数和保存局部变量所依赖的堆栈环境,然后使用BL指令直接跳转

注意:通过R0-R3传递参数,当参数大于4个时,剩余的参数需要使用堆栈来传递
eg:
LDR R0, =0x3
LDR R1, =0x4
BL sum

//c 程序
int sum(int a,int b)

GNU ARM汇编语言

  • 0
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
### 回答1: msub指令ARM64体系结构中的一条指令,用于进行带符号整数的乘法和减法操作。 在ARM64体系结构中,msub指令的格式为msub Rd, Rn, Ra, Rm,其中Rd表示目标寄存器,Rn、Ra和Rm表示源寄存器。 msub指令的作用是将源寄存器Rm中的值与Rn中的值进行乘法运算,然后将结果与Ra中的值进行减法运算,最后将结果存储到目标寄存器Rd中。 这条指令在一些特定的运算场景下非常有用。例如,当我们需要计算一个多项式的值时,可以使用msub指令来进行高效的乘法和减法操作。此外,在一些计算密集型的算法中,使用msub指令可以提高计算性能。 需要注意的是,msub指令是带符号整数的运算指令,它将使用源寄存器中的值的符号进行运算。因此,在使用msub指令时要确保寄存器的值符合运算要求,否则可能会得到不正确的结果。 总而言之,msub指令ARM64体系结构中用于进行带符号整数乘法和减法操作的一条指令,可以在某些特定的运算场景下提高计算性能。 ### 回答2: msub 指令是在ARM64架构中的一条乘加指令。在ARM处理器中,乘加指令用于执行两个操作数的乘法运算,然后将乘法结果与第三个操作数相加。 msub指令的完整形式为 msub Rd, Rn, Rm, Ra,其中Rd表示目标寄存器,Rn表示第一个操作数,Rm表示第二个操作数,而Ra表示第三个操作数。 该指令的执行顺序为:先执行Rn与Rm的乘法运算,然后得到的乘法结果与Ra进行相加,最后的结果将存储在目标寄存器Rd中。 msub指令在一些特定的应用中非常有用,比如数字信号处理和一些科学计算中的数值计算。通过将乘法和加法操作的结果直接汇总在一条指令中执行,可以提高程序的运行效率,减少指令的执行次数,从而优化程序性能。 总之,msub指令ARM64架构中的一条乘加指令,用于执行两个操作数的乘法运算,然后将乘法结果与第三个操作数相加,最后将结果存储在目标寄存器中。它在一些特定的应用中具有重要的作用,可以提高程序的运行效率和性能。 ### 回答3: msub是ARM64指令集中的一条指令,它用于执行64位整数的乘法和减法操作。msub指令的格式为msub Rd, Rn, Rm, Ra,其中Rd是目标寄存器,Rn、Rm是源寄存器,而Ra是要减去的操作数。 msub指令的作用是计算乘法操作的结果并与原有的数值相减,然后将结果存储到目标寄存器Rd中。这实际上等价于执行(Rn * Rm) - Ra的计算。 ARM64架构的msub指令在处理需要同时进行乘法和减法操作的情况下非常高效,因为它可以在一个指令周期内完成这两个计算步骤。 使用msub指令可以减少指令的数量,提高程序的执行效率。尤其是在需要频繁进行乘法和减法操作的算法和应用中,msub指令可以大幅度提高运算效率。 总而言之,msub指令ARM64指令集中用于执行64位整数乘法和减法操作的一条指令。它能够通过一次指令完成乘法和减法计算,并将结果存储到指定的寄存器中,从而提高程序的执行效率。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值