是否可以使用?自动递增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)
对于商店和加载,您可以这样做:
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读取.