Linux 中 x86 的內聯匯編
將各個部分組合起來
developerWorks
文檔選項
將此頁作為電子郵件發送
最新推薦
Java 應用開發源動力 - 下載免費軟件,快速啟動開發
級別: 初級
Bharata B. RaoIBM Linux 技術中心,IBM 軟件實驗室,印度
Bharata B. Rao 提供了在 Linux 平臺上使用和構造 x86 內聯匯編的概括性介紹。他介紹了內聯匯編及其各種用法的基礎知識,提供了一些基本的內聯匯編編碼指導,并解釋了在 Linux 內核中內聯匯編代碼的一些實例。
如果您是 Linux 內核的開發人員,您會發現自己經常要對與體系結構高度相關的功能進行編碼或優化代碼路徑。您很可能是通過將匯編語言指令插入到 C 語句的中間(又稱為內聯匯編的一種方法)來執行這些任務的。讓我們看一下 Linux 中內聯匯編的特定用法。(我們將討論限制在 IA32 匯編。)
GNU 匯編程序簡述
讓我們首先看一下 Linux 中使用的基本匯編程序語法。GCC(用于 Linux 的 GNU C 編譯器)使用 AT&T 匯編語法。下面列出了這種語法的一些基本規則。(該列表肯定不完整;只包括了與內聯匯編相關的那些規則。)
寄存器命名
寄存器名稱有 % 前綴。即,如果必須使用 eax,它應該用作 %eax.
源操作數和目的操作數的順序
在所有指令中,先是源操作數,然后才是目的操作數。這與將源操作數放在目的操作數之后的 Intel 語法不同。
mov %eax, %ebx, transfers the contents of eax to ebx.
作數大小
根據操作數是字節 (byte)、字 (word) 還是長型 (long),指令的后綴可以是 b、w 或 l.這并不是強制性的;GCC 會嘗試通過讀取操作數來提供相應的后綴。但手工指定后綴可以改善代碼的可讀性,并可以消除編譯器猜測不正確的可能性。
movb %al, %bl —— Byte move
movw %ax, %bx —— Word move
movl %eax, %ebx —— Longword move
立即操作數
通過使用 $ 指定直接操作數。
movl $0xffff, %eax —— will move the value of 0xffff into eax register.
間接內存引用
任何對內存的間接引用都是通過使用 ( ) 來完成的。
movb (%esi), %al —— will transfer the byte in the memory
pointed by esi into al
register
內聯匯編
GCC 為內聯匯編提供特殊結構,它具有以下格式:
GCG 的 "asm" 結構
asm ( assembler template
?。?output operands (optional)
?。?input operands (optional)
?。?list of clobbered registers
?。╫ptional)
?。?;
本例中,匯編程序模板由匯編指令組成。輸入操作數是充當指令輸入操作數使用的 C 表達式。輸出操作數是將對其執行匯編指令輸出的 C 表達式。
內聯匯編的重要性體現在它能夠靈活操作,而且可以使其輸出通過 C 變量顯示出來。因為它具有這種能力,所以 "asm" 可以用作匯編指令和包含它的 C 程序之間的接口。
一個非?;镜苤匾膮^別在于 簡單內聯匯編只包括指令,而 擴展內聯匯編包括操作數。要說明這一點,考慮以下示例:
內聯匯編的基本要素
{
int a=10, b;
asm ("movl %1, %%eax;
movl %%eax, %0;"
?。?quot;=r"(b) /* output */
?。?quot;r"(a) /* input */
?。?quot;%eax"); /* clobbered register */
}
在上例中,我們使用匯編指令使 "b" 的值等于 "a".請注意以下幾點:
* "b" 是輸出操作數,由 %0 引用,"a" 是輸入操作數,由 %1 引用。
* "r" 是操作數的約束,它指定將變量 "a" 和 "b" 存儲在寄存器中。請注意,輸出操作數約束應該帶有一個約束修飾符 "=",指定它是輸出操作數。
* 要在 "asm" 內使用寄存器 %eax,%eax 的前面應該再加一個 %,換句話說就是 %%eax,因為 "asm" 使用 %0、%1 等來標識變量。任何帶有一個 % 的數都看作是輸入/輸出操作數,而不認為是寄存器。
* 第三個冒號后的修飾寄存器 %eax 告訴將在 "asm" 中修改 GCC %eax 的值,這樣 GCC 就不使用該寄存器存儲任何其它的值。
* movl %1, %%eax 將 "a" 的值移到 %eax 中, movl %%eax, %0 將 %eax 的內容移到 "b" 中。
* 因為 "b" 被指定成輸出操作數,因此當 "asm" 的執行完成后,它將反映出更新的值。換句話說,對 "asm" 內 "b" 所做的更改將在 "asm" 外反映出來。