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)”这一行上 在第一条装配线上,w0ldmia正确处理(执行该生产线时,数据在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,因为当您第一次尝试它时,它可能工作得很好,然后当您更改程序中一些(显然)不相关的部分时,它会破坏寄存器分配器。