2016-03-26 24 views
0

隨着內聯彙編在GCC,您可以用"i"約束指定立即彙編操作數,像這樣:如何在gcc中使用英特爾語法的即時約束?

void set_to_five(int* p) 
{ 
    asm 
    (
     "movl %1, (%0);" 
     :: "r" (p) 
     , "i" (5) 
    ); 
} 

int main() 
{ 
    int i; 
    set_to_five(&i); 
    assert(i == 5); 
} 

沒有錯,到目前爲止,除了它在可怕的AT & T語法。因此,讓我們用.intel_syntax noprefix再試一次:

void set_to_five(int* p) 
{ 
    asm 
    (
     ".intel_syntax noprefix;" 
     "mov [%0], %1;" 
     ".att_syntax prefix;" 
     :: "r" (p) 
     , "i" (5) 
    ); 
} 

但是,這並不工作,因爲編譯器插入即時值,彙編器不再明白之前$前綴。

如何在英特爾語法中使用"i"約束?

+1

嘗試使用'%c1'(請參閱https://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html#x86Operandmodifiers)。另外,請考慮使用-masm = intel而不是僞操作。 –

+0

我一定讀過那個頁面10次,但不知何故我錯過了那一點。謝謝!你應該發佈這個答案。 – user5434231

+0

儘管我希望使用'-masm = intel',但在使用AT&T語法asm包含頭文件時會造成麻煩。 – user5434231

回答

1

您應該可以使用%c1(請參閱modifiers)。

請注意,如果您使用符號名稱(我發現它更易於閱讀/維護),則可以使用%c [五]。

最後,我認識到這只是一個「對象」的代碼,但是你不修改內存而不告訴編譯器。這是一件「壞事」。考慮使用內存輸出約束("=m")或添加「內存」clobber。

+0

這提出了第二個問題;我是否應該使用''memory'clobber來處理非內存副作用(如I/O端口訪問)? – user5434231

+0

內存clobber的要點是讓編譯器知道您的asm是否將讀取「除輸入和輸出操作數中列出的內存以外的內存」。這讓編譯器知道如果它有任何緩存在寄存器中的值,它們應該在/重新加載後綴之前刷新到內存。如果I/O操作確實是「非內存」(即不是將內存塊寫入磁盤,從磁盤讀取塊等),那麼編譯器可能(可能)沒有任何操作。很難說絕對沒​​有具體細節。 –

+0

我在考慮硬件I/O端口('in' /'out'指令)。這些東西不會保存在C/C++變量中,所以我不認爲這裏需要「內存」,只需要'asm volatile'來確保它們按照正確的順序執行。 – user5434231