簡體   English   中英

在avr-gcc內聯匯編中使用輸出寄存器有哪些限制?

[英]What are the limitations on the use of output registers in avr-gcc inline assembly?

內聯匯編中的輸出寄存器必須使用“ =”約束聲明,表示“只寫” [1]。 這到底是什么意思-真正禁止在程序集中讀取和修改它們嗎? 例如,考慮以下代碼:

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

程序集將輸出寄存器設置為0,然后將其遞增。 這是否打破了“只寫”約束?

UPDATE

我看到的問題是,將內聯匯編更改為直接在輸出寄存器上工作時,內聯匯編會中斷,這與使用r16進行計算並將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

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

由於這只是輸出約束,因此不能保證res的初始值會被加載到寄存器中。 實際上,甚至可以假設asm塊仍然會覆蓋初始化器,從而優化初始化器。 上面的代碼由我的avr-gcc版本編譯為此:

inc r24
ret

如您所見,編譯器確實將加載1刪除到res ,因此也刪除了r24從而產生不確定的結果。


更新

問題中更新程序的問題在於它還具有輸入寄存器操作數。 默認情況下,編譯器假定所有輸入都在分配輸出之前被消耗掉,因此可以安全地分配重疊的寄存器。 您的示例顯然不是這種情況。 您應該為輸出使用“ Early Clobber ”修飾符( & )。 這是手冊對此要說的:

& (在特定替代方案中)此操作數是早期用戶操作數,在使用輸入操作數完成指令之前對其進行了修改。 因此,此操作數不能位於用作輸入操作數或任何存儲器地址一部分的寄存器中。

沒有人說gcc inline asm很容易:D

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM