ARM 汇编中关于 ldmdb 的困惑

Confusion about `ldmdb` in ARM assembly

ldmdb 指令的 ARM docs 似乎自相矛盾。

  1. addr_mode的描述下,文档说DB地址对应"Decrement address Before each access"。

  2. 在操作部分的更下方,文档指出“用于访问的内存地址以 4 字节为间隔,范围从 RnRn-4*(n-1)

我对这两个语句如何没有直接冲突感到困惑:如果地址(存储在 Rn 中)在每次访问之前递减,那么第一个(最高)访问地址不是Rn - 4?

根据我从 运行 一些代码中观察到的行为,似乎地址实际上在每次访问 后递减(与第二个行为一致)。

我是不是理解错了? ldm/stm 在 DB 寻址模式下的实际行为是什么?

我觉得很清楚:

LDMDB/LDMEA)

address = R[n] - 4*BitCount(registers);
for i = 0 to 14
  if registers<i> == '1' then
    R[i] = MemA[address,4]; address = address + 4;

if registers<15> == '1' then
  LoadWritePC(MemA[address,4]);

if wback && registers<n> == '0' then R[n] = R[n] - 4*BitCount(registers);

LDM(LDMIA/LDMFD)

address = R[n];
for i = 0 to 14
  if registers<i> == '1' then
    R[i] = MemA[address,4]; address = address + 4;

if registers<15> == '1' then
  LoadWritePC(MemA[address,4]);

if wback && registers<n> == '0' then R[n] = R[n] + 4*BitCount(registers);

所以如果 r5 = 0x1000

ldmdb r5,{r2,r1}

最终结果是:

r2 = mem[0x0FFC]
r1 = mem[0x0FF8]

来自伪代码

address = 0x1000 - (2*4) = 0x0FF8, then for each register flag in the list
mem[address] = r1, address += 4
mem[address] = r2, address += 4

我认为 DB 意味着不会向起始地址(本例中为 0x1000)写入任何内容。

如果 r5 = 0x1000

ldmia r5,{r1,r2}

最终结果是

r1 = mem[0x1000]
r2 = mem[0x1004]

来自伪代码

address = 0x1000
for each register flag enabled
r1 = mem[address] address += 4
r2 = mem[address] address += 4

我想到increment after意思是开始使用那个地址然后递增。之前递减,从先前的(字)地址开始,然后继续向下 运行 寄存器向后。

或者您可以简单地在处理器或模拟器上尝试指令,并检查内存。

如果没有任何意义,请查找 alternate/compatible ARM 体系结构参考手册之一,然后阅读该说明。 ARM 会不时重写他们的描述...

很有可能文档中有错误。


编辑

是的,这段文字看起来完全错误:

对于 LDMDB、LDMEA、STMDB 和 STMFD,用于访问的内存地址以 4 字节为间隔,范围从 Rn 到 Rn - 4 * (n-1),其中 n 是 reglist 中的寄存器数.访问按寄存器编号递减的顺序进行,编号最高的寄存器使用最高内存地址,编号最低的寄存器使用最低内存地址。如果指定writeback后缀,则将Rn - 4 * (n-1)的值写回Rn。

应该是 rn - 4 到 rn - (4 * n) 和 rn - (4*n)

请注意架构参考手册和技术参考手册非常好。最近他们一直在制作其他手册的风格,在这种情况下用户指南,还有一些程序员手册。看起来这些都不好,在人们的类似困惑导致我看着它导致我看到它有多糟糕导致我再也不会打扰后,我不再看它们了。