gpt4 book ai didi

c++ - 有人可以帮助我了解 stmdb、ldmia 以及如何用 arm 汇编语言实现此 C++ 代码吗?

转载 作者:塔克拉玛干 更新时间:2023-11-02 23:55:06 25 4
gpt4 key购买 nike

所以我有这段代码,其中 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 元素数组的前四个元素,所以我假设如果我将“#0”更改为“#4”,它会导致接下来的四个元素发生变化,但事实并非如此。为什么?

最佳答案

首先,正如您所展示的,加载/存储多条指令主要用于堆栈操作(尽管它们也可以生成高效的 memcpy)。简而言之,它们按顺序加载/存储指定的寄存器,从/到一个连续的内存块,从base addressbase address + (number of registers * 4) .

在给出的示例中,stmdb sp!, {v1-v5, lr} 以“Decrement Before”寻址模式1 存储 6 个寄存器,因此有效基地址是 sp-24 - 它会将 v1 的内容存储在 sp-24v2sp-20,... lr at sp-4。由于存在用于基址寄存器写回的 ! 语法,因此它将从 sp 中减去 24,使其指向 v1 的存储值。 ldmia 完全相反 - “Increment After”表示有效基地址为 sp,因此它将从 sp 加载寄存器直到sp+20,然后将 24 添加到 sp。请注意,它将堆叠的 lr 值直接加载到 pc - 这样您就可以在一条指令中恢复寄存器并执行函数返回。


对于常规的加载/存储指令,它们有 3 种寻址模式 - 偏移、预索引和后索引。 ldr v1, [a1], #0是后置索引的,意思是“从a1中的地址加载v1,然后将0加到a1”,因此将 #0 更改为 #4 不会影响使用的地址,只会影响写回的值之后到基址寄存器。如果您已经实现了循环,效果就会变得清晰可见。

考虑一些示例 C 表达式如何映射到这些寻址模式可能会有所帮助:

int a;       // r0
int *b; // r1

a = b[1]; // ldr r0, [r1, #4] (offset)
a = *(b+1); // similarly

a = *(++b); // ldr r0, [r1, #4]! (pre-indexed)

a = *(b++); // ldr r0, [r1], #4 (post-indexed)

请记住,偏移值也可以是寄存器而不是立即数,因此有几种可能的方法来实现与给定的循环类似的循环。

对于权威引用,我建议阅读 ARM Architecture Reference Manual 的说明部分,或者为了不那么详尽但更容易理解的介绍,Cortex-A Series Programmer's Guide .


[1] 这意味着递减堆栈 - 相应的“递减之后”和“递增之前”寻址模式存在用于运行递增堆栈。

关于c++ - 有人可以帮助我了解 stmdb、ldmia 以及如何用 arm 汇编语言实现此 C++ 代码吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23045702/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com