是否可以使用 [Rn]!
自动递增 STR 上寄存器的基址? ?我已经浏览了文档,但无法找到明确的答案,主要是因为 LDR 和 STR 都提供了命令语法 - 理论上它应该适用于两者,但我找不到任何 auto 示例- 在商店上递增(加载工作正常)。
我制作了一个小程序,它将两个数字存储在一个向量中。完成后 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;
}
编辑:
虽然答案对于常规加载和存储是正确的,但我发现优化器混淆了向量指令(例如 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;
}
编译与
g++ -O2 -march=armv7-a -mfpu=neon main.cpp -o main
将在最后 8 个变量的输出上产生乱码,因为优化器保持递增的变量并将其用于 printf。换句话说,
out[i]
实际上是 out[i+8]
,所以前 8 个打印值是向量中的最后 8 个,其余是超出范围的内存位置。我尝试了
volatile
的不同组合整个代码中的关键字,但只有当我使用 -O0
编译时行为才会改变标志或者如果我使用 volatile 向量而不是指针和新的,比如volatile int out[16];
最佳答案
对于存储和加载,您可以这样做:
ldr r0,[r1],#4
str r0,[r2],#4
无论你在最后放什么,在这种情况下是 4,都会在寄存器用于地址之后但在指令完成之前添加到基址寄存器(ldr 示例中的 r1 和 str 示例中的 r2),它非常像
unsigned int a,*b,*c;
...
a = *b++;
*c++ = a;
编辑,您需要查看反汇编以了解发生了什么(如果有)。我正在使用最新的代码源,或者现在只是来自导师图形工具链的源代码。
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
所以
sub sp, sp, #8
是分配两个本地ints out[0]和out[1]
mov r4,#0
str r4,[sp]
str r4,[sp,#4]
是因为它们被初始化为零,然后是内联程序集
8398: e3a00001 mov r0, #1
839c: e4830004 str r0, [r3], #4
83a0: e2800001 add r0, r0, #1
83a4: e5830000 str r0, [r3]
然后是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>
现在很清楚为什么它不起作用。你没有被声明为 volatile 。您没有让代码返回 ram 来获取 printf 的 out[0] 和 out[1] 的值,编译器知道 r4 包含 out[0] 和 out[1] 的值,有这个函数中的代码太少了,它不必驱逐 r4 并重用它,所以它使用 r4 作为 printf。
如果您将其更改为 volatile
volatile int out[]={0, 0};
然后你应该得到想要的结果:
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>
printf 的准备工作从 ram 中读取。
关于assembly - ARM 程序集 : auto-increment register on store,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9102113/