【ARM-汇编】

■ 概述:

ARM微处理器支持加载/存储指令用于在寄存器和存储器之间传送数据,
加载指令用于将存储器中的数据传送到寄存器,
存储指令则完成相反的操作。
常用的加载存储指令如下:

—  LDR      字数据加载指令
—  LDRB     字节数据加载指令
—  LDRH     半字数据加载指令
—  STR      字数据存储指令
—  STRB     字节数据存储指令
—  STRH     半字数据存储指令

■ 加载指令

1、LDR指令 : 字数据加载指令

LDR指令的格式为:LDR{条件} 目的寄存器,<存储器地址>
LDR指令用于从存储器中将一个32位的字数据传送到目的寄存器中。
该指令通常用于从存储器中读取32位的字数据到通用寄存器,然后对数据进行处理。
当程序计数器PC作为目的寄存器时,指令从存储器中读取的字数据被当作目的地址,从而可以实现程序流程的跳转。
该指令在程序设计中比较常用,且寻址方式灵活多样,请读者认真掌握。
指令示例:

LDR   R0,[R1]                  ;将存储器地址为R1的字数据读入寄存器R0。
LDR   R0,[R1,R2]             ;将存储器地址为R1+R2的字数据读入寄存器R0。
LDR   R0,[R1,#8]             ;将存储器地址为R1+8的字数据读入寄存器R0。
LDR   R0,[R1,R2] !           ;将存储器地址为R1+R2的字数据读入寄存器R0,并将新地址R1+R2写入R1。
LDR   R0,[R1,#8] !          ;将存储器地址为R1+8的字数据读入寄存器R0,并将新地址R1+8写入R1。
LDR   R0,[R1],R2              ;将存储器地址为R1的字数据读入寄存器R0,并将新地址R1+R2写入R1。
LDR   R0,[R1,R2,LSL#2]!   ;将存储器地址为R1+R2×4的字数据读入寄存器R0,并将新地址R1+R2×4写入R1。
LDR   R0,[R1],R2,LSL#2     ;将存储器地址为R1的字数据读入寄存器R0,并将新地址R1+R2×4写入R1。

2、LDRB指令:字节数据加载指令

LDRB指令的格式为:
LDR{条件}B 目的寄存器,<存储器地址>
LDRB指令用于从存储器中将一个8位的字节数据传送到目的寄存器中,同时将寄存器的高24位清零。该指令通常用于从存储器中读取8位的字节数据到通用寄存器,然后对数据进行处理。当程序计数器PC作为目的寄存器时,指令从存储器中读取的字数据被当作目的地址,从而可以实现程序流程的跳转。
指令示例:

LDRB R0,[R1]         ;将存储器地址为R1的字节数据读入寄存器R0,并将R0的高24位清零。
LDRB R0,[R1,#8]    ;将存储器地址为R1+8的字节数据读入寄存器R0,并将R0的高24位清零。

3、LDRH指令:半字数据加载指令

LDRH指令的格式为:
LDR{条件}H 目的寄存器,<存储器地址>
LDRH指令用于从存储器中将一个16位的半字数据传送到目的寄存器中,同时将寄存器的高16位清零。该指令通常用于从存储器中读取16位的半字数据到通用寄存器,然后对数据进行处理。当程序计数器PC作为目的寄存器时,指令从存储器中读取的字数据被当作目的地址,从而可以实现程序流程的跳转。
指令示例:

LDRH R0,[R1]         ;将存储器地址为R1的半字数据读入寄存器R0,并将R0的高16位清零。
LDRH R0,[R1,#8]    ;将存储器地址为R1+8的半字数据读入寄存器R0,并将R0的高16位清零。
LDRH R0,[R1,R2]    ;将存储器地址为R1+R2的半字数据读入寄存器R0,并将R0的高16位清零。

4、LDM指令:

L的含义仍然是LOAD,即是Load from memory into register。
虽然貌似是LDR的升级,但是,千万要注意,这个指令运行的方向和LDR是不一样的,是从左到右运行的。该指令是将内存中堆栈内的数据,批量的赋值给寄存器,即是出栈操作;其中堆栈指针一般对应于SP,注意SP是寄存器R13,实际用到的却是R13中的内存地址,只是该指令没有写为[R13],同时,LDM指令中寄存器和内存地址的位置相对于前面两条指令改变了,下面的例子:
LDMFD SP! , {R0, R1, R2}
实际上可以理解为: LDMFD [SP]!, {R0, R1, R2}
意思为:把sp指向的3个连续地址段(应该是3*4=12字节(因为为r0,r1,r2都是32位))中的数据拷贝到r0,r1,r2这3个寄存器中去。

■ 存储指令

1、STR指令:字数据存储指令

STR指令的格式为:
STR{条件} 源寄存器,<存储器地址>
STR指令用于从源寄存器中将一个32位的字数据传送到存储器中。该指令在程序设计中比较常用,且寻址方式灵活多样,使用方式可参考指令LDR。
指令示例:

STR   R0,[R1],#8    ;将R0中的字数据写入以R1为地址的存储器中,并将新地址R1+8写入R1。
STR   R0,[R1,#8]    ;将R0中的字数据写入以R1+8为地址的存储器中。

2、STRB指令:字节数据存储指令

STRB指令的格式为:
STR{条件}B 源寄存器,<存储器地址>
STRB指令用于从源寄存器中将一个8位的字节数据传送到存储器中。该字节数据为源寄存器中的低8位。
指令示例:

STRB R0,[R1]         ;将寄存器R0中的字节数据写入以R1为地址的存储器中。
STRB R0,[R1,#8]    ;将寄存器R0中的字节数据写入以R1+8为地址的存储器中。

3、STRH指令:半字数据存储指令

STRH指令的格式为:
STR{条件}H 源寄存器,<存储器地址>
STRH指令用于从源寄存器中将一个16位的半字数据传送到存储器中。该半字数据为源寄存器中的低16位。
指令示例:

STRH R0,[R1]         ;将寄存器R0中的半字数据写入以R1为地址的存储器中。
STRH R0,[R1,#8]    ;将寄存器R0中的半字数据写入以R1+8为地址的存储器中。

4、STM指令:

S的含义仍然是STORE,与LDM是配对使用的,其指令格式上也相似,即区别于STR,是将堆栈指针写在左边,而把寄存器组写在右边。
STMFD SP!, {R0}
同样的,该指令也可理解为: STMFD [SP]!, {R0}
意思是:把R0保存到堆栈(sp指向的地址)中。

■ 数据传输指令

指令目的描述
MOVR0R1将 R1 里面的数据复制到 R0 中。
MRSR0CPSR将特殊寄存器 CPSR 里面的数据复制到 R0 中。
MSRCPSRR1将 R1 里面的数据复制到特殊寄存器 CPSR 里中。

1、 MOV指令: 将数据从一个寄存器拷贝到另外一个寄存器

MOV R0, R1 @将寄存器 R1 中的数据传递给 R0,即 R0=R1
MOV R0, #0X12 @将立即数 0X12 传递给 R0 寄存器,即 R0=0X12

2、 MRS 指令: 特殊寄存器(如 CPSR 和 SPSR)中的数据传递给通用寄存器

MRS R0, CPSR @将特殊寄存器 CPSR 里面的数据传递给 R0,即 R0=CPSR

3、 MSR 指令: MSR 指令用来将普通寄存器的数据传递给特殊寄存器

MSR CPSR, R0 @将 R0 中的数据复制到 CPSR 中,即 CPSR=R0

■ 存储器访问指令

指令描述
LDR Rd, [Rn , #offset]从存储器 Rn+offset 的位置读取数据存放到 Rd 中。
STR Rd, [Rn, #offset]将 Rd 中的数据写入到存储器中的 Rn+offset 位置。

1、 LDR 指令: 从存储加载数据到寄存器 Rx

LDR R0, =0X0209C004    @将寄存器地址 0X0209C004 加载到 R0 中,即 R0=0X0209C004
LDR R1, [R0]           @读取地址 0X0209C004 中的数据到 R1 寄存器中

2、 STR 指令 : 将数据写入到存储器

LDR R0, =0X0209C004  @将寄存器地址 0X0209C004 加载到 R0 中,即 R0=0X0209C004
LDR R1, =0X20000002  @R1 保存要写入到寄存器的值,即 R1=0X20000002
STR R1, [R0]         @将 R1 中的值写入到 R0 中所保存的地址中

字进行读取和写入的,也就是操作的 32 位数据,如果要按照字节、半字进行操作的话可以在指令“LDR”后面加上 B 或 H,
字节操作的指令就是 LDRB 和 STRB
半字操作的指令就是 LDRH 和 STRH

■ 压栈(PUSH),出栈(POP)指令

我们通常会在 A 函数中调用 B 函数,当 B 函数执行完以后再回到 A 函数继续执行。
要想再跳回 A 函数以后代码能够接着正常运行,那就必须在跳到 B 函数之前将当前处理器状态保存起来(就是保存 R0~R15 这些寄存器值),
当 B 函数执行完成以后再用前面保存的寄存器值恢复R0~R15 即可。
保存 R0~R15 寄存器的操作就叫做现场保护,恢复 R0~R15 寄存器的操作就叫做恢复现场。

PUSH 和 POP 是一种多存储和多加载指令,即可以一次操作多个寄存器数据,

指令描述
PUSH 将寄存器列表存入栈中。
POP 从栈中恢复寄存器列表。

1、 压栈 PUSH

堆栈是向下增长的
PUSH {R0~R3, R12}  @将 R0~R3 和 R12  压栈
PUSH {LR}          @将 LR 进行压栈

在这里插入图片描述

2、 出栈 POP

POP {LR}          @先恢复 LR
POP {R0~R3,R12}   @在恢复 R0~R3,R12

3、 PUSH 和 POP 的另外一种写法是“STMFD SP!”和“LDMFD SP!”

STMFD 可以分为两部分: STM 和 FD,同理, LDMFD 也可以分为 LDM 和 FD。
FD 是 Full Descending 的缩写,即满递减的意思

STMFD SP!,{R0~R3, R12}  @R0~R3,R12 入栈
STMFD SP!,{LR} 			@LR 入栈

LDMFD SP!, {LR} 		@先恢复 LR
LDMFD SP!, {R0~R3, R12} @再恢复 R0~R3, R12

■ 跳转指令

①、直接使用跳转指令 B、 BL、 BX 等。
②、直接向 PC 寄存器里面写入数据。

指令描述
B 跳转到 label,如果跳转范围超过了+/-2KB,可以指定 B.W
BX 间接跳转,跳转到存放于 Rm 中的地址处,并且切换指令集
BL 跳转到标号地址,并将返回地址保存在 LR 中。
BLX 结合 BX 和 BL 的特点,跳转到 Rm 指定的地址,并将返回地址保存在 LR 中,切换指令集。

1、 B 指令

B 指令会将 PC 寄存器的值设置为跳转目标地址。
调用的函数不会再返回到原来的执行处,那就可以用 B 指令。

_start:

	ldr sp,=0X80200000  @设置栈指针
	b main 				@跳转到 main 函数

2、 BL 指令

BL 指令相比 B 指令,在跳转之前会在寄存器 LR(R14)中保存当前 PC 寄存器值,所以可以通过将 LR 寄存器中的值重新加载到 PC 中来继续从跳转之前的代码处运行,
比如 Cortex-A 处理器的 irq 中断服务函数都是汇编写的,主要用汇编来实现现场的保护和恢复、获取中断号等。
在这里插入图片描述
第 5 行就是执行 C 语言版的中断处理函数,当处理完成以后是需要返回来继续执行下面的程序,所以使用了 BL 指令。

■ 算术运算指令

在这里插入图片描述

■ 逻辑运算指令

在这里插入图片描述

  • 2
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

光芒Shine

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值