2017-07-25 305 views
1

我想重用我的C項目中一些彙編代碼的函數體。假設我有一個指令序列,我想組織他們作爲一個函數:GCC彙編內聯:與只有內聯彙編代碼

void foo() { 
    __asm__ (
    "mov %eax, %ebx" 
    "push %eax" 
    ... 
    ); 
} 

然而,一個障礙是,在功能foo編譯彙編代碼,除了內聯彙編代碼,編譯器也將產生這個功能有些序幕指令,整個彙編程序將成爲類似:

foo: 
    push %ebp   <---- routine code generated by compilers 
    mov %ebp, %esp <---- routine code generated by compilers 
    mov %eax, %ebx 
    push %eax 

由於我使用的情況下,這樣的常規代碼實際上打破了內聯彙編的原始語義。

因此,這裏是我的問題,有沒有什麼辦法,我可以阻止編譯器生成的函數序幕和尾聲指令,並且僅包括內聯彙編代碼?

+3

不,你不能使用內聯彙編的方式。只需在C項目中使用正常的程序集,這樣就不會生成任何額外的指令。 –

+1

最好在程序集文件中創建函數,分別進行組裝,然後將程序集對象鏈接到_C_文件。有人說這是可能做你在問什麼。有一個[幾個答案](https://stackoverflow.com/q/43310704/3857942)涉及到用這種方式寫入中斷處理程序的相關問題。您可以對任何您打算完全用匯編寫入的_C_函數執行此操作。我強烈**推薦單獨的程序集文件。 –

+1

@old_timer:有時用匯編代碼(或至少是函數的一部分)編寫裸C函數是有用的。我同意,但是,這是什麼初學者(或某人不RTM)應該使用和明確什麼對所有的代碼要寫入的方式.. – Olaf

回答

2

內聯asm代碼的全部要點是通過給你一種方法來指定如何將彙編代碼連接到編譯器的約束解決機器,以一種理智的方式與C編譯器的調度程序和註冊分配器進行交互。這就是爲什麼具有內置asm代碼和特定寄存器的情況很少有意義;你反而想使用約束來分配一些寄存器,並讓編譯器告訴你它們是什麼。

如果您確實想編寫與系統ABI程序通信的獨立asm代碼,請將該代碼寫入您的項目中包含的獨立.s(或.S)文件中,而不是比試圖使用內聯彙編代碼。

+0

我真的不確定這是好還是不好的答案。沒有pre/postamble的情況下,有用例可以擁有單個函數。但是,當然像OP這樣編寫一個完整的程序集項目似乎意圖是一個非常糟糕的主意。如果你想要ABI,前/後導是必要的。 – Olaf

+0

@Olaf:然後將這個單一的函數寫入一個單獨的小的.s文件並將其鏈接到結果中。沒有必要將所有東西放在一個甚至只是幾個源文件中。 –

+0

您應該意識到,如果該函數僅用於單個編譯單元,則會不必要地混淆全局命名空間並違反了局部性原則。這種做法是非常有爭議的,即有見地。沒有單一的,簡單的答案。調用這種印象是沒有更多信息的單一,普遍接受的解決方案是不光彩的。 (或許你沒有注意到我試圖區分不同的用例, – Olaf

2

你提到你使用gcc編譯。 在這種情況下,您可以使用-O2優化級別。這將導致編譯器進行堆棧優化,並且如果內聯程序集很簡單,它將不會插入序言和結尾。儘管這可能無法保證在任何情況下,因爲優化不斷變化。 (我的gcc用-O2做到了)。

另一種選擇是,你可以把整個函數(包括foo:)組裝塊內的

__asm__ (
    "foo:\n" 
    "mov ..." 
); 

有了這個選項,你需要知道的名字改編規格(如有)。如果您希望函數是非靜態的,您還必須在函數啓動之前添加.globl foo

最後你可以檢查函數聲明海合會__attribute__ ((naked))屬性。但正如MichaelPetch所述,這不適用於X86目標。

+3

__attribute __((naked))'_GCC_不適用於x86目標。雖然這個問題沒有用x86標記,但是顯示的代碼是x86。你應該在當前版本的_GCC_ –

+0

@MichaelPetch上得到'warning:'naked'attribute directive ignored ignored'的警告。謝謝,我將這一點轉移到了最後,並添加了關於X86不可用的暗示。 –