ARM汇编之加载寄存器

2021-11-22 14:14:17 浏览数 (1)

ARM汇编

代码语言:txt复制
- [将常数加载到寄存器](https://cloud.tencent.com/developer)
        - [用 MOV 和 MVN 直接加载](https://cloud.tencent.com/developer)
        - [用 MOV32 加载](https://cloud.tencent.com/developer)
        - [用 LDR Rd, =const 加载](https://cloud.tencent.com/developer)
        - [加载浮点常数](https://cloud.tencent.com/developer)
- [将地址加载到寄存器中](https://cloud.tencent.com/developer)
        - [ADR 和 ADRL 直接加载](https://cloud.tencent.com/developer)
        - [用 ADR 加载跳转表地址](https://cloud.tencent.com/developer)
        - [用 LDR Rd, =label 加载地址](https://cloud.tencent.com/developer)
- [加载和存储多个寄存器指令](https://cloud.tencent.com/developer)
- [LDR 补充:](https://cloud.tencent.com/developer)
        - [LDR指令的格式:](https://cloud.tencent.com/developer)
        - [LDR R,label 和 LDR R,=label的区别](https://cloud.tencent.com/developer)

寄存器是CPU的组成部分,是有限存贮容量的高速存贮部件,它们可用来暂存 数据、地址、指令

更多介绍可查看: ARM寄存器。

将常数加载到寄存器

只有在执行从内存加载数据时,才能用单个指令将任何 32 位立即数加载到寄存器中。这是因为 ARM 和 Thumb-2 指令的长度仅是 32 位。在使用 16 位 Thumb 指令时,可生成的常数范围要小得多。

可以用一次数据加载来将任何 32 位值加载到寄存器中,但也可以使用其他方式来加载许多常用的常数。

Arm指令中,操作码(opcode)、目的操作数(Rd)、源操作数1(Rn)是必须的字段。 条件码(cond)、符号位标记(s)源操作数2(oprand2)是可选的。 其中Rd和Rn必须是寄存器,因此Arm的“立即数”只能存储在oprand2。 Arm指令中的“立即数”是常数表达式。

用 MOV 和 MVN 直接加载

在高版本中,可以先后用 MOV 和 MOVT 这两个指令将任何 32 位值加载到寄存器中。

MOV : 传送一个32位数到寄存器 MON : 把一个32位数的逻辑“非”送到寄存器 MVN : 传送取反的值

  • 16 位Thumb MOV 指令可以加载位于范围 0 到 255 内的任何常数。不能使用 16 位 MVN 指令加载常数。
  • 在 ARM 状态下,在范围 0x0-0xFF (0-255) 内,MOV 可加载任何 8 位常数值。MVN 可加载这些值的按位补码
用 MOV32 加载

在 ARMv6 中,ARM 和 Thumb-2 指令集均包含:

• MOV 指令,它可以将位于范围 0x00000000 到 0x0000FFFF 内的任何值加载到寄存器中

• MOVT 指令,它可将位于范围 0x0000 到 0xFFFF 内的任何值加载到寄存器的最高有效半部。

可使用这两个指令在寄存器中构造任何 32 位常数。也可使用 MOV32 伪指令。

用 LDR Rd, =const 加载

LDR : 从虚拟地址取一个单个的32位值 Rd : 目的操作数,寄存器 const : 常量

LDR Rd,=const 伪指令可在单个指令中构造任何 32 位数字常数。使用此伪指令可生成超出 MOV 和 MVN 指令允许范围的常数。

加载浮点常数

在 NEON 和 VFPv3 指令集内,有一些指令可将有限范围的浮点常数作为立即数加载

将地址加载到寄存器中

通常需要将地址加到寄存器中。可能需要加载变量、字符串常数或跳转表的起 始位置的地址。

地址通常表示为相对当前 pc 或其他寄存器的偏移量。

ADR 和 ADRL 直接加载

利用 ADR 指令和 ADRL 伪指令,无需执行数据加载即可生成位于某一范围内的地 址。ADR 和 ADRL 接受程序相对表达式,这是一个带有可选偏移量的标签,其中标签地址是相对于当前 pc 的。

用于 ADR 或 ADRL 的标签必须位于同一代码节中 在 Thumb 状态下,16 位 ADR 指令只能生成字对齐的地址。 在没有 Thumb-2 的处理器上的 Thumb 状态下,ADRL 将不可用

用 ADR 加载跳转表地址

在程序中常常需要根据一定的参数选择执行不同的子程序。

跳转表中存放的是各子函数的地址,选择不同的子程序的参数是该子程序在跳转表中的偏移量。

跳转表通过下列指令和汇编程序指令来执行:

EQU 是一个汇编程序指令,用于为某一符号赋值。

DCD 声明一个或多个存储字。

LDR LDR pc,r3,r0,LSL#2 指令将跳转表所需子句的地址加载到 pc 中,

用 LDR Rd, =label 加载地址

LDR Rd,= :该伪指令可将任何 32 位常数加载到寄存器中,此外它还接受程序相对表达式,如标签以及带偏移量的标签。

汇编程序通过下列方式转换 LDR r0, =label 伪指令:

  • 将 label 的地址放入文字池(在代码中嵌入的一部分内存,用于存放常数值)
  • 生成程序相对的 LDR 指令,以便从文字池读取该地址

用一个字符串覆盖另一个字符串的 ARM 代码例程:

DCB 指令定义一个或多个存储字节

LDR 和 STR 指令使用后变址寻址来更新其地址寄存器

加载和存储多个寄存器指令

ARM、Thumb 和 Thumb-2 指令集包含用于从内存加载和在内存中存储多个寄存器的指令。

下列指令都可在 ARM 和 Thumb 指令集内使用:

  • LDM 加载多个寄存器。
  • STM 存储多个寄存器。
  • PUSH 将多个寄存器存储到堆栈中并更新堆栈指针。
  • POP 从堆栈中加载多个寄存器,并更新堆栈指针。

加载和存储多个指令可以更新基址寄存器。对于堆栈操作来说,基址寄存器通 常是堆栈指针 R13。这就意味着,可以在单个指令中使用这些指令对任何数量的 寄存器执行推入和弹出操作。

LDR 补充:

以下部分转发于: https://www.jianshu.com/p/66d801c85ee9

LDR指令的格式:

LDR {条件} 目的寄存器 <存储器地址>

作用:将存储器地址所指地址处连续的4个字节(1个字)的数据传送到目的寄存器中。

LDR指令寻址方式实例:

LDR R0,R1 ;将存储器地址为R1的字数据读入寄存器R0。

LDR R0,R1,R2 ;将存储器地址为R1 R2的字数据读入寄存器R0。

LDR R0,R1,#8 ;将存储器地址为R1 8的字数据读入寄存器R0。

LDR R0,R1,R2 ;将存储器地址为R1的字数据读入寄存器R0,然后R1=R1 8。

LDR R0,R1,#8 ;将存储器地址为R1的字数据读入寄存器R0,并将R1 8的值存入R1。

LDR R0,R1,R2! ;将存储器地址为R1 R2的字数据读入寄存器R0,并将R1 R2的值存入R1。

LDR R0,R1,LSL #3 ;将存储器地址为R18的字数据读入寄存器R0。

LDR R0,R1,R2,LSL #2 ;将存储器地址为R1 R24的字数据读入寄存器R0。

LDR R0,R1,R2,LSL #2! ;将存储器地址为R1 R24的字数据读入寄存器R0,并将R1 R24的值存入R1。

LDR R0,R1,R2,LSL #2 ;将存储器地址为R1的字数据读入寄存器R0,并将R1 R2*4的值存入R1。

LDR R0,Label ;Label为程序标号,Label必须是当前指令的-4~4KB范围内。

LDR R,label 和 LDR R,=label的区别

当用 LDR r, =imd // r 为寄存器, imd为立即数

LDR 是一条伪指令。编译器会根据立即数的大小,决定用 ldr 指令或者是mov或mvn指令。

当imd能用mov或者mvn操作时,就将它翻译成一条mov或mvn指令。当imd大于mov或mvn能够操作的数时,编译器会将imd存在一个内存单元中,然后再用一条ldr指令加载这个内存单元的的值到寄存器中。

LDR r, label 和 LDR r, =label的区别:

LDR r, =label 会把label表示的值加载到寄存器中,而LDR r, label会把label当做地址,把label指向的地址中的值加载到寄存器中。

譬如 label的值是 0x8000, LDR r, =label会将 0x8000加载到寄存器中,而LDR r, label则会将内存0x8000处的值加载到寄存器中。

0 人点赞