gcc中的ARM内嵌汇编

4
我在一些内联汇编代码上遇到了一些问题。我知道应该做什么,但我不知道怎么做!
我有一个几乎能够工作的校验和函数:
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又被加载了(请参见下面的汇编代码)。 我猜想,我应该在“:[sum]+r(sum):[w0]”上存储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的初始值...
我认为这对于Stack Overflow社区内联汇编专家来说是一个简单的问题!
顺便说一下,我正在使用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"呢?


为了验证我的想法,我测试了以下代码: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”呢? - Martin Allard
1
GCC的内联汇编让我头疼(而且我已经因为附近装修的地毯粘合而开始有点头疼了),所以我无法直接为你提供帮助......但是我可以指向我读过的处理GCC内联汇编的最佳文档之一,以防你还没有遇到它:http://www.ethernut.de/en/documents/arm-inline-asm.html 作为奖励,该文档特别针对ARM。 - Michael Burr
谢谢提供链接。当我写这个问题时,这个网页已经打开了! - Martin Allard
1个回答

4
问题似乎在于你把 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"
      );

也就是说,有两个读写输入/输出操作数,没有专门的输入操作数,还有两个寄存器清除器。

哇,非常感谢,看起来运行得很好。最初(在我开始调试这部分代码之前),该行是 :[w0] "+r" (w0), [sum] "+r" (sum),除了 clobbers 部分外,它与您给出的答案相同,但 sum 和 w0 的顺序相反... 我尝试了您的解决方案,没有使用 clobbers(因为您说我“应该”,而不是“必须”使用它;-),它的行为就像一开始一样。有了 clobbers 部分,它完美地工作,因为它强制编译器保存 w0 的状态! - Martin Allard
1
@Martin:好的,我加强了措辞。省略clobber是一种特别阴险的错误,因为当你第一次尝试它时,它可能会正常工作,然后在稍后更改程序的某些(表面上)不相关部分并扰动寄存器分配器时突然出现问题。 - Chris Dodd

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接