2016-07-21 111 views
0

有一些問題/內聯彙編我不明白。手臂;內聯asm;使用臨時寄存器;

我有一個嵌入式彙編程序的功能。在ASM塊內,我需要使用一些臨時寄存器來修改某些系統值。

void setHW(uint32_t val) { 
    asm volatile (
     mrc 15, 0, r0, ... 
     orr r0, r0, %0 
     mcr 15, 0, r0, ... 
     : :"r"(val) :"r0" 
    ); 
} 

實際上函數是由編譯器內聯的,它沒問題,代碼仍然工作正常。

當我嘗試用一​​些存根變量替換硬編碼r0時出現問題,因此編譯器可以選擇最好的寄存器來使用。它看起來像這樣

void setHW(uint32_t val) { 
    uint32_t reg; 
    asm volatile (
     mrc 15, 0, %[reg], ... 
     orr %[reg], %[reg], %0 
     mcr 15, 0, %[reg], ... 
     :[reg]"=r"(reg) :"r"(val) : 
    ); 
} 

現在的編譯器選擇通過自己註冊,但實際上腐敗setHW調用函數的值。 在反彙編,它看起來像

 add r2, r4, r5  ; caller part, r2 contain some intermedia result 
     mrc 15, 0, r2, ... ; inlined setHW(), r2 is choosen as scratch reg 
     orr r2, r2, r0 
     mcr 15, 0, r2, ... 
     ; caller continue 

正如你可以看到r2已損壞,一切都只是土崩瓦解。

我應該如何定義scratch寄存器來避免這種情況?

+1

當您添加'[reg]'時,val停止爲'%0'併成爲'%1'。 –

+0

@DavidWohlferd,謝謝。順便說一句'[reg]「= r」(reg)'仍然無法正常工作。在某些情況下,編譯器對'val'和'reg'使用相同的寄存器,所以我得到'mrc r3 ...; orr r3,r3,r3; mcr r3 ...;'。 '[reg]「+ r」(reg)'實際上解決了這個問題,但是現在編譯器顯示錯誤''reg'被使用了未初始化...'並且需要爲'reg'指定一個轉儲值並且出現額外的指令。它可以修復嗎? – user3124812

+0

我知道你已經解決了它,但是在第一個代碼塊中,我認爲你遇到的問題是根據ARM EABI調用約定,函數的第一個參數將在'r0'中,這樣代碼可能會用'mrc 15,0,r0,...'來破壞'uint32_t val'。同樣,在ARM EABI中,'r4-8,r10,r11'被認爲是「可變寄存器」,所以我認爲如果你使用了其中一個,那麼你會很好。 – rjp

回答

3

怎麼是這樣的:

void setHW(uint32_t val) { 
    uint32_t reg; 
    asm volatile (
     mrc 15, 0, %[reg], ... 
     orr %[reg], %[reg], %[val] 
     mcr 15, 0, %[reg], ... 
     :[reg]"=&r"(reg) :[val] "r"(val) : 
    ); 
} 

注意=&r修復早期撞問題(見https://gcc.gnu.org/onlinedocs/gcc/Modifiers.html&的描述)。

+0

這是!謝謝大衛 – user3124812