所以我有这段代码,其中N是两个数组的大小。
int i;
for (i = 0; i < N; i++)
{
if (listA[i] < listB[i])
{
listA[i] = listB[i];
}
}
我试图将其作为ARM程序集子程序实现,但我完全迷失了如何处理数组。到目前为止我有这个:
sort1:
stmdb sp!, {v1-v5, lr}
ldmia sp!, {v1-v5, pc}
我认为我必须使用cmp来比较这些值,但我甚至不确定要使用哪些寄存器。有人有任何指导吗?
编辑:
好的,我现在有了这段代码:
sort1:
stmdb sp!, {v1-v5, lr} @ Copy registers to stack
ldr v1, [a1], #0 @ Load a1
str v1, [a2], #0 @ Copy elements of a1 to a2
ldmia sp!, {v1-v5, pc} @ Copy stack back into registers
这会复制10个元素数组的前四个元素,所以我会假设我改变了#34;#0&#34;到&#34;#4&#34;,它会导致接下来的四个元素发生变化,但它并没有。为什么?
答案 0 :(得分:16)
首先,正如您所演示的那样,加载/存储多个指令主要用于堆栈操作(尽管它们也可以生成高效的memcpy
)。简单地说,它们按顺序从/ {加载/存储从base address
到base address + (number of registers * 4)
的连续内存块。
在给出的示例中,stmdb sp!, {v1-v5, lr}
在“递减之前”寻址模式 1 中存储6个寄存器,因此有效基址为sp-24
- 它将存储v1
的{{1}},sp-24
的{{1}},...... v2
的{{1}}的内容。由于存在基址寄存器写回的sp-20
语法,因此它将从lr
中减去24,使其指向存储的sp-4
值。 !
完全相反 - “后续增量”表示有效基址为sp
,因此它会将寄存器从v1
加载到ldmia
,然后再添加24到sp
。请注意,它会将堆叠的sp
值直接加载到sp+20
中 - 这样您就可以恢复寄存器并在单个指令中执行函数返回。
对于常规加载/存储指令,它们有3种寻址模式 - 偏移,预索引和后索引。 sp
已被后索引,意味着从lr
中的地址“加载pc
,然后将0添加到ldr v1, [a1], #0
”,从而将v1
更改为{{1 }}不会影响地址 used ,只会将值写回基址寄存器。如果你已经实现了循环那么效果就会变得清晰可见。
考虑一些示例C表达式如何映射到这些寻址模式可能会有所帮助:
a1
请记住,偏移值也可以是寄存器而不是立即数,因此有几种可能的方法来实现类似给定的循环。
对于权威参考,我建议您阅读ARM Architecture Reference Manual的说明部分,或者更简洁但更易于理解的介绍Cortex-A Series Programmer's Guide。
[1]这意味着下降的堆栈 - 对应的“递减后”和“递增前”寻址模式存在以运行升序堆栈。