ARM 汇编指令:LDM

ARM 汇编指令:LDM

本文来自于我关于 ARM 汇编指令系列文章。欢迎阅读、点评与交流~
1、汇编指令在不同架构中的联系与区别
2、ARM 汇编指令:MOV
3、ARM 汇编指令:LDR
4、ARM 汇编指令:STR
5、ARM 汇编指令:MRS 和 MSR
6、ARM 汇编指令:ORRS
7、ARM 汇编指令:BEQ
8、ARM 汇编指令:TST
9、ARM 汇编指令:B
10、ARM 汇编指令:BX
11、ARM 汇编指令:ERET
12、ARM 汇编指令:STP\LDP
13、ARM 汇编指令:UBFX
14、ARM 汇编指令:STM
15、ARM 汇编指令:LDM

1. 核心定义

LDMLoad Multiple 的缩写,意为"加载多个寄存器"。它是 ARM 汇编中用于从连续的内存地址中一次性加载数据到多个寄存器的指令。

它通常与 STM 指令配对使用,后者用于将多个寄存器的值存储到连续的内存中。

2. 基本语法

复制代码
LDM{addr_mode}{cond} Rn{!}, reglist{^}
  • LDM:指令本身。
  • {addr_mode}地址模式后缀 。这是关键部分,决定了地址的增长方式和数据的加载顺序。常见的有:
    • IA : Increment After (默认,可省略)。每次加载后地址增加。
    • IB : Increment Before。每次加载前地址增加(仅用于 ARM 特权模式)。
    • DA : Decrement After。每次加载后地址减少。
    • DB : Decrement Before。每次加载前地址减少。
  • {cond} :可选的条件码,如 EQ, NE, GT 等。
  • Rn基址寄存器,其中保存着内存起始地址。
  • {!} :可选的回写后缀。如果加上 !,则指令执行后,会将计算得到的最终地址写回 Rn 基址寄存器。这在堆栈操作和数据块移动中非常有用。
  • reglist寄存器列表 。用大括号 {} 括起来,包含要加载数据的寄存器。例如 {R0, R4-R7, R10}。寄存器在列表中的顺序不重要加载总是按照寄存器编号从小到大的顺序进行 ,而地址的递增/递减方向由 addr_mode 决定。
  • {^} :可选的特权后缀。有两个含义:
    • 如果 reglist包含 PC 寄存器^ 表示除了正常加载数据外,还会将 SPSR 的内容复制到 CPSR(用于从异常处理返回)。
    • 如果 reglist不包含 PC 寄存器^ 表示加载的是用户模式下的寄存器,而不是当前特权模式的寄存器。

3. 工作原理(以最常见的 LDMIA 为例)

假设执行指令:LDMIA R0!, {R1, R3, R5}

  • 内存起始地址是 R0 中的值。
  • 虽然列表写的是 {R1, R3, R5},但 ARM 硬件会按编号排序为 R1, R3, R5
  • **IA(后增)**模式:
    1. [R0] 处的 4 字节数据加载到 R1
    2. [R0+4] 处的 4 字节数据加载到 R3
    3. [R0+8] 处的 4 字节数据加载到 R5
  • 因为使用了 !,指令执行后,R0 = R0 + 12(3个寄存器 * 4字节)。

4. 与堆栈操作的关系

ARM 为堆栈操作(后进先出 LIFO)定义了更直观的别名。堆栈由**堆栈指针 SP(R13)**管理,可以向下增长(满递减)或向上增长(空递增)。

标准指令 堆栈别名 含义 常见用途
LDMDB LDMFD Full Descending 堆栈的弹出操作 ARM 默认堆栈类型(向下增长,满栈)
LDMIA LDMEA Empty Ascending 堆栈的弹出操作 较少使用
STMDB STMFD Full Descending 堆栈的压入操作 ARM 默认堆栈的压栈
STMIA STMEA Empty Ascending 堆栈的压入操作 较少使用

记住这个口诀:PUSH = STMFDPOP = LDMFD

5. 经典用例

a) 块数据复制

armasm 复制代码
; 将 R1 指向的源地址处的 4 个字,复制到 R2 指向的目标地址
LDMIA R1!, {R4-R7} ; 从源地址加载4个寄存器
STMIA R2!, {R4-R7} ; 存储到目标地址

b) 子程序进入/退出(保护与恢复寄存器)

armasm 复制代码
; 进入子程序时,将工作寄存器压栈保护
STMFD SP!, {R4-R12, LR} ; 压栈,LR (R14) 是返回地址

; ... 子程序主体 ...

; 退出子程序时,从堆栈恢复寄存器并返回
LDMFD SP!, {R4-R12, PC} ; 弹出,直接将返回地址加载到 PC (R15),实现跳转
; 等同于 POP {R4-R12, PC}

c) 异常返回

armasm 复制代码
; 从 IRQ 异常处理程序返回
SUBS PC, LR, #4          ; 简单方法

; 或使用 LDM 从堆栈恢复所有上下文(包括 PC 和 CPSR)
LDMFD SP!, {R0-R12, LR}  ; 恢复通用寄存器和链接寄存器
RFEFD SP!                ; 使用 RFE 指令返回(现代方式)
; 或者使用带 ^ 的 LDM(传统方式)
; LDMFD SP!, {R0-R12, PC}^ ; ^ 表示同时将 SPSR 复制到 CPSR

6. 重要注意事项

  1. 加载顺序固定 :无论 reglist 如何书写,总是 R0(如果存在)从最低地址加载,R1 从下一个地址加载,以此类推。
  2. 基址寄存器对齐:地址通常是字对齐的(4字节边界)。
  3. PC 的特殊性 :如果 reglist 包含 PC(R15),它总是最后被加载。加载到 PC 的值将导致程序跳转。
  4. 效率 :一条 LDM 指令可以加载多个寄存器,这比用多条 LDR 指令更高效,因为它减少了指令取指和解码的开销。

总结

LDM 是 ARM 架构中一个强大且高效的批量数据加载指令,尤其在与 STM 配对用于堆栈操作内存块复制 时,是 ARM 汇编编程的基石之一。理解其地址模式(特别是 IA/DB)和与堆栈别名(FD/EA)的关系,是掌握它的关键。

相关推荐
华清远见IT开放实验室9 小时前
实验室建设案例 | 石家庄科技信息职业学院嵌入式实验室——从底层硬件到系统应用,一所应用型高校的嵌入式人才培养这样落地
linux·arm开发·stm32·嵌入式硬件·高校·实验室建设
执迷不悟82314 小时前
ARM--按键/中断
arm开发
维基框架15 小时前
汽车座舱开发上云 Google的Arm实例解决了什么实际问题
arm开发·人工智能·汽车
Discipline~Hai2 天前
ARM01-ARM体系架构
linux·c语言·arm开发·架构
weixin_446260853 天前
ARM++:面向深度伪造检测器的多域智能体协同可迁移对抗攻击框架
arm开发·人工智能
执迷不悟8233 天前
ARM--启动实现LED
arm开发
linux修理工4 天前
在 ARM 架构的 Armbian 系统上搭建 Strudel 开发环境
arm开发
程序员JerrySUN4 天前
Jetson 刷机深度解析:flash.sh vs l4t_initrd_flash.sh(含安全与磁盘加密对比)
linux·网络·arm开发·安全·系统安全
执迷不悟8234 天前
ARM--汇编指令
汇编·arm开发
2601_954706495 天前
算力上云革新移动终端:ARM 虚拟化云手机底层原理、API 自动化实战与 2026 选型全解
arm开发·智能手机·自动化