2012-02-15 147 views
4

我在使用某些内联汇编代码时遇到了一些麻烦。我知道该怎么做,但我想念“如何”!arm gcc中的内联汇编

我有这样的校验功能,那就是 “差不多” 的工作:

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); 
} 

我的问题,我相信,是上线“:[和] ”+ R“(总和):[W0] “R”(W0)“ 在第一组装线,W0LDMIA正确处理(执行线时,数据是在R4,R5和W 0递增)。但w0的增量值并未保存在某处,当代码循环时,w0的原始值再次被加载(请参见下面的汇编代码)。 我的猜测是我应该将w0的值存储在“:”+ 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] 

正如你可以看到,我想补充一些像“海峡R3,[R11,#-20]”行31928和3192c之间,因为当程序循环到行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”,如果我修改了这个函数,这个可能会改变呢?

+0

为了验证我的想法,我测试了以下: 'ASM易失性( \t \t \t “LDMIA%[W0]!{V1,V2} \ n \ t” 的 \t \t \t “增加了%[总和],%[总和],V1 \ n \ t” 的 \t \t \t “的ADC%[总和],%[总和],V2 \ n \ t” 的 \t \t \t “的ADC%[总和],%[总和],#0 \ n \ t” 的 \t \t \t“STR% [W0],[R 11,#-20]” \t \t \t:[总和] “+ R”(和):[W0] “R”(W0) \t);' 而工作的。也许这是解决方案,但是我用什么来取代“r11,#20”,如果我修改了这个函数,这个可能会改变呢? – 2012-02-15 23:05:52

+1

海湾合作委员会的内联组装让我的头部受伤(而且我已经有一个人开始了,因为在附近的一个改造中发生了一些地毯粘合),所以我不能给你任何直接的帮助......但是我可以指给你一个我已经阅读过关于如何处理海湾合作委员会内联汇编的最佳文档,如果您还没有遇到它:http://www.ethernut.de/en/documents/arm-inline-asm.html奖金,该文件专门针对ARM。 – 2012-02-15 23:42:54

+0

感谢您的链接。当我写这个问题时,这个网页已经打开了! – 2012-02-16 13:51:58

回答

4

这个问题似乎是你指定w0作为一个INPUT操作数,当它实际上应该是一个读写输出操作数,如sum。另外,你需要指定它在你使用这些寄存器的时候使用v1和v2(否则,gcc可能会把一些其他的var放到这些regs中,并期望它们被保留下来。)

所以,你应该有:

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" 
    ); 

就是两种读写输入/输出操作数,没有专门的输入操作数,以及两个寄存器则会覆盖

+0

非常感谢,它似乎很好。最初(在我开始调试这部分代码之前)该行是:[w0]“+ r”(w0),+“+ r”(sum)',除了clobbers部分外,你给了,但与sum和w0在相反的顺序...我尝试了你的解决方案没有clobbers(正如你所说我“应该”,而不是“必须”使用它;-),它的行为就像一开始。有了clobbers的一部分,它可以很好地工作,因为它会迫使编译器保存w0的状态! – 2012-02-16 15:45:25

+1

@Martin:好的,我加强了一下措辞。将clobbers排除是一个特别隐蔽的bug,因为它可能在您第一次尝试时运行得很好,然后当您更改某个(显然)不相关的扰乱了寄存器分配器的程序部分时,会再次中断。 – 2012-02-16 17:45:03