• 博客园logo
  • 会员
  • 众包
  • 新闻
  • 博问
  • 闪存
  • 赞助商
  • HarmonyOS
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录

SOC/IP验证工程师

  • 博客园
  • 联系
  • 订阅
  • 管理

公告

View Post

arm v8r中汇编指令ldrd的详细用法

ARMv8-R 架构中的 LDRD 指令是一条非常实用的指令,用于从内存中一次性加载两个 32 位字(Word)到两个通用寄存器中。这相当于把两个 LDR 指令合并为一条,可以提高代码效率。由于 ARMv8-R 主要支持 AArch32 状态,这里的说明将聚焦于此。

以下是 LDRD 指令的要点,我用一个表格来汇总:

项目 说明
指令功能 从连续的内存地址加载两个 32 位字到两个寄存器中
语法格式 LDRD{<c>} <Rt>, <Rt2>, [<Rn> {, #+/-<imm>}]{!}
LDRD{<c>} <Rt>, <Rt2>, [<Rn>], #+/-<imm>
典型应用场景 一次性加载64位数据、处理结构体或数组元素、优化代码效率和性能
重要约束 寄存器必须为通用寄存器,Rt 和 Rt2 不能是 PC,Rt 的编号必须小于 Rt2 的编号
偏移量限制 立即数偏移 imm 通常必须是 4 的倍数,范围有限(例如,±1020 或 ±255)
地址对齐 地址最好64位对齐,非对齐访问可能影响性能或触发异常

🖋 语法格式详解

LDRD 指令的基本语法格式如下:

LDRD{<c>} <Rt>, <Rt2>, [<Rn> {, #+/-<imm>}]{!}
LDRD{<c>} <Rt>, <Rt2>, [<Rn>], #+/-<imm>
  • {<c>}:可选的条件码(如 EQ, NE, GT 等),用于条件执行。
  • <Rt>, <Rt2>:目标寄存器对。LDRD 会将内存中的第一个字(较低地址)加载到 Rt,将第二个字(较高地址)加载到 Rt2。
    • 约束:Rt 和 Rt2 必须是通用寄存器,且 Rt 的编号必须小于 Rt2 的编号(例如 R1, R2 有效,R2, R1 无效)。它们不能是 PC (R15)。
  • <Rn>:基址寄存器,包含内存访问的基地址。
  • #+/-<imm>:可选的有符号立即数偏移量。该偏移量通常必须是 4 的倍数(因为访问的是字),并且其取值范围有限(例如,在 ARMv7/AArch32 中,LDRD 的偏移量范围通常为 ±1020)。
  • ! :用于前变基模式。如果使用 !,则会在内存访问之后,将计算后的新地址(Rn + offset)写回基址寄存器 Rn。
  • [<Rn>], #+/-<imm> :用于后变基模式。这种格式下,先使用 Rn 的原始值作为内存地址进行加载操作,然后再将 Rn 的值更新为 Rn + imm。

🔍 寻址模式

LDRD 支持三种主要的寻址模式,这与其他的加载存储指令类似。

  1. 偏移模式 (Offset)
    内存地址是 Rn 的值加上或减去一个立即数偏移量。Rn 寄存器本身的值不会改变。

    LDRD R1, R2, [R5, #16]  ; 从地址 (R5 + 16) 加载一个字到 R1,从 (R5 + 20) 加载一个字到 R2。R5 不变。
    
  2. 前变基模式 (Pre-indexed)
    内存地址是 Rn + offset。在内存访问之前,Rn 的值会先被更新为 Rn + offset。

    LDRD R1, R2, [R5, #16]! ; 先将 R5 更新为 (R5 + 16),然后从新 R5 (即原R5+16) 加载到 R1,从 (新R5 + 4) 加载到 R2。
    
  3. 后变基模式 (Post-indexed)
    内存地址是 Rn 的原始值。在内存访问之后,Rn 的值会被更新为 Rn + offset。

    LDRD R1, R2, [R5], #16  ; 先使用 R5 的原始值作为基地址:从 R5 加载到 R1,从 (R5+4) 加载到 R2。然后将 R5 更新为 (R5 + 16)。
    

⚠️ 重要约束和使用注意

使用 LDRD 时,需要注意以下几点:

  • 寄存器对限制:Rt 和 Rt2 必须是通用寄存器,并且 Rt 的编号必须小于 Rt2(例如 R1, R2 有效,R2, R1 无效)。它们不能是 PC (R15)。
  • 偏移量范围:立即数偏移 imm 的值范围是有限的,具体限制取决于ARM架构版本和指令变种。例如,在 ARMv7-A/R 中,LDRD 的立即数偏移通常必须是 4 的倍数,范围在 -1020 到 +1020 之间。请查阅具体的架构参考手册以获取精确值。
  • 地址对齐:虽然 LDRD 可以处理非对齐的地址访问(取决于系统配置),但为了获得最佳性能,建议确保内存地址是 64 位对齐的(即地址是 8 的倍数)。非对齐访问可能导致性能下降或触发对齐异常。

🛠 使用示例

假设我们有一段内存,起始地址为 0x8000,其中存储了多个 64 位数据(每个 64 位数据由两个连续的 32 位字构成)。我们想将这些数据加载到寄存器中进行处理。

.data
my_data:
.word 0x11223344   @ 64位数据的低32位 (地址 0x8000)
.word 0x55667788   @ 64位数据的高32位 (地址 0x8004)
.word 0xAABBCCDD   @ 下一个64位数据的低32位 (地址 0x8008)
.word 0xEEFF0011   @ 下一个64位数据的高32位 (地址 0x800C)

.text
.global _start

_start:
    MOV R5, #0x8000   @ 将数据区的起始地址加载到 R5

    @ 示例 1: 使用偏移模式加载第一个64位数据到 R0 和 R1
    LDRD R0, R1, [R5]   @ 从 R5 (0x8000) 加载到 R0 (得到 0x11223344),
                        @ 从 R5+4 (0x8004) 加载到 R1 (得到 0x55667788)

    @ 示例 2: 使用前变基模式加载第二个64位数据,并更新基址
    @ 假设 R5 现在还是 0x8000
    LDRD R2, R3, [R5, #8]! @ 先将 R5 更新为 R5+8 = 0x8008,
                           @ 然后从新 R5 (0x8008) 加载到 R2 (得到 0xAABBCCDD),
                           @ 从新 R5+4 (0x800C) 加载到 R3 (得到 0xEEFF0011)
    @ 此时 R5 的值已经是 0x8008

    @ 示例 3: 使用后变基模式加载数据(假设地址已重新设置),并自动递增基址
    MOV R5, #0x8000        @ 重新设置 R5 为 0x8000
    LDRD R4, R5, [R5], #8  @ (!注意: 这里用 R5 同时做基址寄存器和目标寄存器,需谨慎)
                           @ 先操作: 从 R5(0x8000) 加载到 R4 (得到 0x11223344),
                           @         从 R5+4(0x8004) 加载到 R5 (得到 0x55667788) – 这会覆盖原基址值!
                           @ 然后操作: 将基址寄存器(已经是新值0x55667788)再加8 -> 结果不可预知,错误用法!

    @ 更安全的後变基示例:使用不同的寄存器
    MOV R6, #0x8000        @ 基址寄存器使用 R6
    LDRD R4, R5, [R6], #8  @ 从 R6(0x8000) 加载到 R4 (0x11223344), 从 R6+4(0x8004) 加载到 R5 (0x55667788)
                           @ 然后将 R6 更新为 R6 + 8 = 0x8008

注意:在後变基模式示例中,试图使用 R5 同时作为基址寄存器和目标寄存器(Rt2)会导致不可预期的结果,因为基址寄存器在加载过程中被覆盖了。这是一个常见的错误,应避免让目标寄存器与基址寄存器相同(除非你非常清楚其后果)。

💡 进阶应用:与 STRD 配对使用

LDRD 通常与它的“搭档”指令 STRD(Store Register Dual,存储双寄存器)一起使用,后者用于将两个寄存器的值存储到连续的内存地址中。

@ 假设我们要将 R0 和 R1 中的值(构成一个64位数据)存储到内存中地址 0x9000 开始的地方
MOV R4, #0x9000
STRD R0, R1, [R4] @ 将 R0 的值存储到 [0x9000], 将 R1 的值存储到 [0x9004]

@ 同样,STRD 也支持偏移、前变基和后变基模式。

⚠️ 与 LDP 指令的区别

在 ARMv8-A AArch64 状态中,有 LDP(Load Pair)指令,其功能与 LDRD 类似,但更加强大和灵活(支持64位寄存器,偏移量范围更大)。然而,在 ARMv8-R(主要运行 AArch32 状态)中,LDRD/STRD 仍然是加载存储双字的主要方式。

希望这些解释和示例能帮助你更好地理解和使用 ARMv8-R 中的 LDRD 指令。

posted on 2025-09-08 20:56  SOC验证工程师  阅读(19)  评论(0)    收藏  举报

刷新页面返回顶部
 
博客园  ©  2004-2025
浙公网安备 33010602011771号 浙ICP备2021040463号-3