2012-02-15 149 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