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处的值加载到寄存器中。