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

相关推荐
ShiMetaPi3 小时前
GM-3568JHF丨ARM+FPGA异构开发板系列教程:外设教程 09 CAN
arm开发·fpga开发·fpga·rk3568
未来之窗软件服务3 小时前
幽冥大陆(八十)Win7环境下ARM架构开发—东方仙盟练气期
arm开发·架构·仙盟创梦ide·东方仙盟
未来之窗软件服务1 天前
国产化系统(一)ARM轻量化系统开发与试用全指南—东方仙盟练气期
arm开发·仙盟创梦ide·东方仙盟·阿雪技术观·国产化操作系统
林政硕(Cohen0415)1 天前
ARM Linux Qt Widget 虚拟键盘输入法移植
linux·arm开发·qt·键盘·输入法
山峰哥2 天前
SQL调优核心战法——索引失效场景与Explain深度解析
大数据·汇编·数据库·sql·编辑器·深度优先
100编程朱老师2 天前
Linux 下互联网络编程的基础知识
arm开发
番茄灭世神3 天前
32位ARM单片机视频教程第一篇
arm开发·单片机·嵌入式·gd32·pn学堂
驱动探索者3 天前
[缩略语大全]之[ARM CPU]篇
arm开发
ArrebolJiuZhou4 天前
00 arm开发环境的搭建
linux·arm开发·单片机·嵌入式硬件