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

SOC/IP验证工程师

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

公告

View Post

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

经过查询相关资料,ARMv8-R 架构中的 STRD 指令用于将两个 32 位字(Word)或一个 64 位双字(Double-Word) 从两个寄存器存储到内存中。这在进行 64 位数据操作或者需要高效地存储一对寄存器时非常有用。由于搜索结果中相关信息较少,我会结合自己的知识为你详细解释。

📝 STRD 指令格式

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

STRD <Rt1>, <Rt2>, [<Rn>, #<offset>]!  ; 预先带写回的变址寻址
STRD <Rt1>, <Rt2>, [<Rn>], #<offset>    ; 事后带写回的变址寻址
STRD <Rt1>, <Rt2>, [<Rn>, #<offset>]     ; 不带写回的变址寻址(偏移模式)

或者更一般的形式:

STRD <Rt1>, <Rt2>, [<Xn|SP>{, #<imm>}]
  • <Rt1> 和 <Rt2>:这是你要存储到内存中的两个源寄存器。Rt1 中的值会被存储到较低的内存地址,Rt2 中的值会被存储到较高的内存地址。
  • [<Rn>]:这是基址寄存器,包含了存储操作的目标内存地址。
  • #<offset>:这是一个可选的立即数偏移量(通常有特定的范围限制,例如在 ARMv8 中常见的是 -1020 到 +1020 且是 4 的倍数)。它会被加到基址寄存器 Rn 上来形成有效地址。
  • !:如果存在 !,表示预先变址寻址(Pre-index) 并且将计算后的新地址写回基址寄存器 Rn。
    格式:[Rn, #offset]! -> 先计算 Rn + offset 作为地址,然后将 Rn 更新为 Rn + offset。
  • 如果没有 !,但有偏移量且写在括号内(如 [Rn, #offset]),这通常是偏移寻址(Offset),使用 Rn + offset 作为地址,但不写回 Rn。
  • 如果偏移量写在括号外(如 [Rn], #offset),表示事后变址寻址(Post-index):先使用 Rn 的值作为地址,然后将 Rn 更新为 Rn + offset。

🔍 STRD 指令的操作

STRD 指令的核心操作是将两个寄存器(Rt1 和 Rt2)的值存储到连续的内存单元中:

  1. 计算地址:根据使用的寻址模式(偏移、预先变址、事后变址)计算有效内存地址。
    • 设有效地址为 address。
  2. 存储数据:
    • 将寄存器 Rt1 的值存储到计算得到的有效地址 address 处(一个 word,4 字节)。
    • 将寄存器 Rt2 的值存储到地址 address + 4 处(下一个 word,4 字节)。
    • 这样就连续存储了 8 个字节(64 位)的数据。

⚠️ 重要注意事项

  • 地址对齐:STRD 指令要求目标内存地址是 64 位(8 字节)对齐的。这意味着地址值最好是 8 的倍数(即最低 3 位为 0)。如果地址非 8 字节对齐,执行 STRD 指令可能会引发对齐错误异常(Alignment Fault),具体行为取决于系统配置。
  • 寄存器对:Rt1 和 Rt2 通常是两个不同的通用寄存器。虽然有些架构可能允许 Rt1 和 Rt2 是同一个寄存器,但这通常没有实际意义,并且可能在某些情况下产生不可预知的行为,应避免这样使用。
  • 偏移量范围:立即数偏移量 #<imm> 的范围和缩放因子由架构定义。在 ARMv8 中,STRD 的偏移量通常是一个有符号的立即数,范围是 -1020 到 +1020,并且必须是 8 的倍数(因为要访问 8 字节)。编码时偏移量会被除以 8。
  • 写回(Write-back):使用 !(预先变址)或事后变址格式时,基址寄存器 Rn 会被更新。确保 Rn 不是 PC(程序计数器),并且注意不要意外覆盖仍在使用的基址值。
  • 访问权限:执行存储操作时,当前执行级别(EL)必须有权限写入目标内存地址,否则会产生权限错误异常。

🖥️ STRD 指令示例

假设寄存器 R1 的当前值是 0x8000,R2 中的值是 0xAABBCCDD,R3 中的值是 0x11223344。

1. 偏移模式(Offset)

STRD R2, R3, [R1, #16]   ; 将 R2 的值存储到 [R1+16] = 0x8010
                         ; 将 R3 的值存储到 [R1+16+4] = 0x8014
                         ; R1 的值保持不变 (0x8000)

2. 预先变址模式(Pre-index with write-back)

STRD R2, R3, [R1, #24]!  ; 先将 R1 更新为 R1 + 24 = 0x8018
                         ; 然后将 R2 的值存储到 [0x8018]
                         ; 将 R3 的值存储到 [0x8018+4] = 0x801C
                         ; 执行后 R1 = 0x8018

3. 事后变址模式(Post-index with write-back)

STRD R2, R3, [R1], #-8   ; 先将 R2 的值存储到 [R1] = [0x8000]
                         ; 将 R3 的值存储到 [0x8000+4] = 0x8004
                         ; 然后将 R1 更新为 R1 + (-8) = 0x7FF8

为了更直观地理解上述示例中内存和寄存器的变化,可以参考下面的表格:

示例模式 指令执行前 操作说明 指令执行后
偏移模式
R1 = 0x8000 基址寄存器 R1 初始值。 R1 = 0x8000 (不变)
STRD R2, R3, [R1, #16] R2 = 0xAABBCCDD 要存储的第一个源寄存器。 内存地址 0x8010 = 0xAABBCCDD (R2)
R3 = 0x11223344 要存储的第二个源寄存器。 内存地址 0x8014 = 0x11223344 (R3)
预先变址模式
R1 = 0x8000 基址寄存器 R1 初始值。 R1 = 0x8018 (更新)
STRD R2, R3, [R1, #24]! R2 = 0xAABBCCDD 要存储的第一个源寄存器。 内存地址 0x8018 = 0xAABBCCDD (R2)
R3 = 0x11223344 要存储的第二个源寄存器。 内存地址 0x801C = 0x11223344 (R3)
事后变址模式
R1 = 0x8000 基址寄存器 R1 初始值。 R1 = 0x7FF8 (更新)
STRD R2, R3, [R1], #-8 R2 = 0xAABBCCDD 要存储的第一个源寄存器。 内存地址 0x8000 = 0xAABBCCDD (R2)
R3 = 0x11223344 要存储的第二个源寄存器。 内存地址 0x8004 = 0x11223344 (R3)

🔄 相关指令

  • LDRD:与 STRD 相对应的加载指令,用于从内存中连续读取 64 位数据到两个寄存器中。
  • STR / LDR:用于存储/加载单一寄存器的指令。
  • STP / LDP:用于存储/加载一对寄存器的指令,功能与 STRD/LDRD 类似,是 ARMv8 中更现代和通用的写法,通常推荐使用。例如 STP R2, R3, [R1, #16]。

💎 总结

ARMv8-R 架构中的 STRD 指令主要用于将两个通用寄存器(共 64 位数据)存储到连续的内存地址中。它支持偏移、预先变址(带写回)和事后变址(带写回) 三种寻址模式,提供了灵活的内存访问方式。使用时需特别注意内存地址必须 8 字节对齐,并合理运用偏移量和写回功能来优化代码效率。

希望这些信息能帮助你全面理解 ARMv8-R 中 STRD 指令的用法。

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

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