有人可以帮助我理解stmdb,ldmia,以及如何用arm汇编语言实现这个C++代码吗?

Can someone help me understand stmdb, ldmia, and how I can go about implementing this C++ code in arm assembly language?

本文关键字:实现 汇编语言 arm C++ 代码 何用 帮助 ldmia stmdb      更新时间:2023-10-16

所以我有这段代码,其中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}在"递减前"寻址模式1 中存储 6 个寄存器,因此有效基址sp-24 - 它将v1的内容存储在 sp-24 v2 sp-20 ,...最多 lrsp-4 .由于存在基本寄存器写回的!语法,它将从sp中减去 24,使其指向 v1 的存储值。ldmia是完全相反的 - "Increment After"表示有效基址sp,因此它将加载寄存器从spsp+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 架构参考手册的说明部分,或者阅读 Cortex-A 系列程序员指南,以获取不太详尽但更易于访问的介绍。

<小时 />

[1] 这意味着一个降序堆栈 - 存在相应的"递减后"和"递增之前"寻址模式,用于运行升序堆栈。