ARM程序集:存储上的自动增量寄存器

Joh*_*n S 6 assembly arm

是否可以使用?自动递增STR上寄存器的基址[Rn]!.我已经浏览了文档,但未能找到明确的答案,主要是因为LDR和STR都提供了命令语法 - 理论上它应该适用于两者,但我找不到任何自动的例子 - 在商店增加(装载工作正常).

我做了一个小程序,在一个向量中存储两个数字.当它完成时,内容out应该是,{1, 2}但是存储会覆盖第一个字节,就像自动增量不起作用一样.

#include <stdio.h>

int main()
{
        int out[]={0, 0};
        asm volatile (
        "mov    r0, #1          \n\t"
        "str    r0, [%0]!       \n\t"
        "add    r0, r0, #1      \n\t"
        "str    r0, [%0]        \n\t"
        :: "r"(out)
        : "r0" );
        printf("%d %d\n", out[0], out[1]);
        return 0;
}
Run Code Online (Sandbox Code Playgroud)

编辑:虽然答案适合常规加载和存储,但我发现优化器会在向量指令(例如vldm/vstm)上自动增加.例如,以下程序

#include <stdio.h>

int main()
{
        volatile int *in = new int[16];
        volatile int *out = new int[16];

        for (int i=0;i<16;i++) in[i] = i;

        asm volatile (
        "vldm   %0!, {d0-d3}            \n\t"
        "vldm   %0,  {d4-d7}            \n\t"
        "vstm   %1!, {d0-d3}            \n\t"
        "vstm   %1,  {d4-d7}            \n\t"
        :: "r"(in), "r"(out)
        : "memory" );

        for (int i=0;i<16;i++) printf("%d\n", out[i]);
        return 0;
}
Run Code Online (Sandbox Code Playgroud)

用.编译

g++ -O2 -march=armv7-a -mfpu=neon main.cpp -o main
Run Code Online (Sandbox Code Playgroud)

将在最后8个变量的输出上产生乱码,因为优化器保持增量变量并将其用于printf.换句话说,out[i]实际上out[i+8],所以前8个打印值是向量中的最后8个,其余是超出边界的内存位置.

我已尝试在volatile整个代码中使用关键字的不同组合,但只有在使用-O0标志编译或者如果我使用volatile向量而不是指针和new时,行为才会更改,例如

volatile int out[16];
Run Code Online (Sandbox Code Playgroud)

old*_*mer 5

对于商店和加载,您可以这样做:

ldr r0,[r1],#4
str r0,[r2],#4
Run Code Online (Sandbox Code Playgroud)

无论你放在最后,4,在这种情况下,在寄存器用于地址之后但是在指令完成之前,它被添加到基址寄存器(ldr示例中的r1和str示例中的r2)非常像

unsigned int a,*b,*c;
...
a = *b++;
*c++ = a;
Run Code Online (Sandbox Code Playgroud)

编辑,您需要查看反汇编,看看发生了什么,如果有的话.我正在使用最新的代码源代码或现在只是来自mentor图形工具链的sourcery lite.

arm-none-linux-gnueabi-gcc(Sourcery CodeBench Lite 2011.09-70)4.6.1

#include <stdio.h>
int main ()
{
        int out[]={0, 0};
        asm volatile (
        "mov    r0, #1          \n\t"
        "str    r0, [%0], #4       \n\t"
        "add    r0, r0, #1      \n\t"
        "str    r0, [%0]        \n\t"
        :: "r"(out)
        : "r0" );
        printf("%d %d\n", out[0], out[1]);
        return 0;
}


arm-none-linux-gnueabi-gcc str.c -O2  -o str.elf

arm-none-linux-gnueabi-objdump -D str.elf > str.list


00008380 <main>:
    8380:   e92d4010    push    {r4, lr}
    8384:   e3a04000    mov r4, #0
    8388:   e24dd008    sub sp, sp, #8
    838c:   e58d4000    str r4, [sp]
    8390:   e58d4004    str r4, [sp, #4]
    8394:   e1a0300d    mov r3, sp
    8398:   e3a00001    mov r0, #1
    839c:   e4830004    str r0, [r3], #4
    83a0:   e2800001    add r0, r0, #1
    83a4:   e5830000    str r0, [r3]
    83a8:   e59f0014    ldr r0, [pc, #20]   ; 83c4 <main+0x44>
    83ac:   e1a01004    mov r1, r4
    83b0:   e1a02004    mov r2, r4
    83b4:   ebffffe5    bl  8350 <_init+0x20>
    83b8:   e1a00004    mov r0, r4
    83bc:   e28dd008    add sp, sp, #8
    83c0:   e8bd8010    pop {r4, pc}
    83c4:   0000854c    andeq   r8, r0, ip, asr #10
Run Code Online (Sandbox Code Playgroud)

所以

sub sp, sp, #8
Run Code Online (Sandbox Code Playgroud)

是将[0]和[1]中的两个本地整数分配

mov r4,#0
str r4,[sp]
str r4,[sp,#4]
Run Code Online (Sandbox Code Playgroud)

是因为它们被初始化为零,然后是内联汇编

8398:   e3a00001    mov r0, #1
839c:   e4830004    str r0, [r3], #4
83a0:   e2800001    add r0, r0, #1
83a4:   e5830000    str r0, [r3]
Run Code Online (Sandbox Code Playgroud)

然后是printf:

83a8:   e59f0014    ldr r0, [pc, #20]   ; 83c4 <main+0x44>
83ac:   e1a01004    mov r1, r4
83b0:   e1a02004    mov r2, r4
83b4:   ebffffe5    bl  8350 <_init+0x20>
Run Code Online (Sandbox Code Playgroud)

现在很明显为什么它没有用.你没有宣布为不稳定.你给了代码没有理由回到ram来获取printf的out [0]和out [1]的值,编译器知道r4包含out [0]和out [1]的值,那里在这个函数中是如此少的代码,它不必驱逐r4并重用它,因此它使用r4作为printf.

如果你改变它是不稳定的

    volatile int out[]={0, 0};
Run Code Online (Sandbox Code Playgroud)

然后你应该得到想要的结果:

83a8:   e59f0014    ldr r0, [pc, #20]   ; 83c4 <main+0x44>
83ac:   e59d1000    ldr r1, [sp]
83b0:   e59d2004    ldr r2, [sp, #4]
83b4:   ebffffe5    bl  8350 <_init+0x20>
Run Code Online (Sandbox Code Playgroud)

printf的准备从ram读取.