gcc中的arm内联组装
我有一些内联汇编代码的问题。我知道该怎么做,但我错过了“怎么做” 我有一个“几乎”工作的校验和函数:gcc中的arm内联组装,c,gcc,arm,inline-assembly,C,Gcc,Arm,Inline Assembly,我有一些内联汇编代码的问题。我知道该怎么做,但我错过了“怎么做” 我有一个“几乎”工作的校验和函数: static unsigned long cksum_unroll( unsigned short **w, int *mlen) { int len; unsigned short *w0; unsigned long sum=0; len = *mlen; w0 = *w; while( len >= 8) { asm volatile (
static unsigned long cksum_unroll( unsigned short **w, int *mlen)
{
int len;
unsigned short *w0;
unsigned long sum=0;
len = *mlen;
w0 = *w;
while( len >= 8) {
asm volatile (
"ldmia %[w0]!, {v1, v2}\n\t"
"adds %[sum], %[sum], v1\n\t"
"adcs %[sum], %[sum], v2\n\t"
"adcs %[sum], %[sum], #0"
: [sum] "+r" (sum) : [w0] "r" (w0)
);
len -= 8;
}
*mlen = len;
*w = w0;
return (sum);
}
我相信我的问题出在“:[sum]“+r”(sum):[w0]“r”(w0)”这一行上
在第一条装配线上,w0由ldmia正确处理(执行该生产线时,数据在r4、r5中,w0递增)。但是w0的增量值不会保存在某个地方,当代码循环时,w0的原始值会再次加载(请参见下面的汇编代码)。
我的猜测是,我应该将w0的值存储在行“:[sum]“+r”(sum):[w0]“r”(w0)”上,但我不知道如何
以下是函数内联汇编部分的反汇编代码:
请注意:
len is stored at r11, #-16
w0 is stored at r11, #-20
sum is stored at r11, #-24
编译后的代码如下:
asm volatile (
"ldmia %[w0]!, {v1, v2}\n\t"
"adds %[sum], %[sum], v1\n\t"
"adcs %[sum], %[sum], v2\n\t"
"adcs %[sum], %[sum], #0"
: [sum] "+r" (sum) : [w0] "r" (w0)
);
len -= 8;
生成:
00031910: ldr r3, [r11, #-20]
00031914: ldr r2, [r11, #-24]
00031918: mov r4, r2
0003191c: ldm r3!, {r4, r5}
00031920: adds r4, r4, r4
00031924: adcs r4, r4, r5
00031928: adcs r4, r4, #0
0003192c: str r4, [r11, #-24]
00031930: ldr r3, [r11, #-16]
00031934: sub r3, r3, #8
00031938: str r3, [r11, #-16]
如您所见,我想在31928行和3192c行之间添加类似于“str r3,[r11,#-20]”的内容,因为当程序循环到31910行时,r3会加载初始值r3
我认为这对于堆栈溢出社区的内联汇编专家来说是一个简单的问题
顺便说一下,我正在使用ARM7TDMI处理器(但这可能与这个问题无关…)
提前谢谢
编辑:
为了验证我的想法,我测试了以下内容:
asm volatile (
"ldmia %[w0]!, {v1, v2}\n\t"
"adds %[sum], %[sum], v1\n\t"
"adcs %[sum], %[sum], v2\n\t"
"adcs %[sum], %[sum], #0\n\t"
"str %[w0], [r11, #-20]"
: [sum] "+r" (sum) : [w0] "r" (w0)
);
这是有效的。也许这就是解决方案,但是如果我修改函数,我应该用什么来替换可能会改变的“r11,#20”?问题似乎是您指定
w0
作为输入操作数,而实际上它应该是读写输出操作数,如sum
。此外,您需要指定在使用这些寄存器时它会关闭v1和v2(否则,gcc可能会将一些其他变量放入这些寄存器中,并期望它们被保留)
因此,你应该:
asm volatile (
"ldmia %[w0]!, {v1, v2}\n\t"
"adds %[sum], %[sum], v1\n\t"
"adcs %[sum], %[sum], v2\n\t"
"adcs %[sum], %[sum], #0"
: [sum] "+r" (sum) , [w0] "+r" (w0) : : "v1", "v2"
);
也就是说,两个读写输入/输出操作数,没有独占输入操作数,还有两个寄存器缓冲符为了验证我的想法,我测试了以下内容:
asm volatile(“ldmia%[w0]!,{v1,v2}\n\t”“adds%[sum],%[sum],%[sum],[v2\n\t”“adcs%[sum],[sum],[sum],[str%[w0],[r11,#-20]。”:[sum]“+r”(sum):[w0]“r”(w0))代码>这是有效的。也许这就是解决方案,但是如果我修改函数,我应该用什么来替换可能会改变的“r11,#20”?GCC的内联程序集让我头疼(我已经启动了一个程序集,因为在附近的改造中正在粘地毯),所以我不能给你任何直接的帮助。。。但我可以告诉你我读过的关于如何处理GCC的内联asm的最好的文档之一,以防你还没有遇到它:作为奖励,该文档专门针对ARM。感谢链接。当我写这个问题时,这个网页已经打开了!哇,非常感谢,看起来效果不错。最初(在我开始调试这部分代码之前),行是:[w0]“+r”(w0),[sum]“+r”(sum)
,除了clobbers部分,这是您给出的答案,但是sum和w0的顺序相反。。。我尝试了你的解决方案,没有受到任何冲击(正如你说的,我“应该”,而不是“必须”使用它;-),它的行为就像一开始一样。使用clobbers部分,它可以完美地工作,因为它强制编译器保存w0的状态@马丁:好的,我加强了措辞。忽略掉clobbers是一个特别隐蔽的bug,因为当您第一次尝试它时,它可能工作得很好,然后当您更改程序中一些(显然)不相关的部分时,它会破坏寄存器分配器。