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)的关系,是掌握它的关键。

相关推荐
一池秋_5 小时前
arm低配linux设备,桌面应用冷启动提速方法
linux·运维·arm开发
qq_4029957518 小时前
诊断协议栈配置Agent
arm开发·人工智能·stm32·单片机·mcu
一木 之林3 天前
三.C++ 内存管理(进阶)(二)
开发语言·arm开发·c++
hongmai6668883 天前
MP2348GTL-Z:这颗24V/4A同步降压芯片,把性能和体积平衡得恰到好处
c语言·开发语言·arm开发·单片机·5g
隔窗听雨眠5 天前
ARM架构下Logstash与Elasticsearch集群部署完全指南:从环境适配到生产验证
arm开发·elasticsearch·架构
郭老师-嵌入式5 天前
arm linux 移植 udhcp 与 使用
linux·服务器·arm开发
kyle~5 天前
x86 汇编LOCK前缀 --- 硬件架构向软件提供的核心同步原语
汇编·c++·性能优化·硬件架构·实时系统
深念Y5 天前
登录日志与管理员审计日志存储决策
前端·arm开发·后端·微服务·云原生·架构
典典分享指南5 天前
飞书 + 企业微信 + 微信文档多端协同实践指南
汇编·flask·intellij-idea·fastapi
深念Y6 天前
微服务抽取路线图:从胖单体到 ARM 集群
前端·arm开发·数据库·后端·微服务·云原生·架构