2013-06-03 98 views
1

內聯彙編中的輸出寄存器必須用「=」約束聲明,意思是「只寫」[1]。這意味着什麼 - 它是否真的被禁止在大會內部讀取和修改它們?例如,請考慮以下代碼:在avr-gcc內聯彙編中使用輸出寄存器有哪些限制?

uint8_t one() 
{ 
    uint8_t res; 
    asm("ldi %[res],0\n" 
     "inc %[res]\n" 
     : [res] "=r" (res) 
    ); 
    return res; 
} 

程序集將輸出寄存器設置爲0,然後遞增它。這是否打破了「只寫」約束?

UPDATE

我看到在我的內聯彙編休息時,我把它改爲直接在輸出寄存器的工作,而不是使用R16的計算,最後mov'ing R16到輸出問題寄存器。代碼在這裏:http://ideone.com/JTpYma。它將結果打印到串行,你只需要定義F_CPU和BAUD。只有使用gcc-4.8.0而不使用gcc-4.7.2時纔會出現該問題。

[1] http://www.nongnu.org/avr-libc/user-manual/inline_asm.html

回答

2

編譯器不關心你是否讀它與否,它只是不會把變量的初始值到寄存器。你舉的例子是完全合法的,但人們往往錯誤地期望得到源於此代碼2

uint8_t one() 
{ 
    uint8_t res = 1; 
    asm("inc %[res]\n" 
     : [res] "=r" (res) 
    ); 
    return res; 
} 

因爲它只是一個輸出的制約,中res初始值不能保證被加載到寄存器。事實上,假設asm塊會覆蓋它,甚至可以優化初始化器。上面的代碼是由我的版本AVR-GCC編譯這樣:

inc r24 
ret 

正如你所看到的,確實編譯取出裝載1res,因此進入r24從而產生不確定的結果。


更新

與問題的更新程序的問題是,它也有一個輸入寄存器操作數。默認情況下,編譯器假定在分配輸出之前所有輸入都被消耗,因此分配重疊寄存器是安全的。你的例子顯然不是這種情況。您應該使用「早期披肩」修飾符(&)作爲輸出。這是手動不得不說有關:

&手段(在一個特定的替代物),這操作數是一個 earlyclobber操作數,之前的指令是 使用輸入操作數完成被修飾。因此,該操作數可能不在 的某個寄存器中,該寄存器用作輸入操作數或任何內存地址的一部分。

沒有人說GCC內聯彙編很簡單:d

+0

你可能是錯在這裏,看到我的編輯。或者它只是一個編譯器錯誤。 –

+0

編輯答案也是。 – Jester

+0

確實修復了它,謝謝! –

相關問題