GCC內聯匯編(INLINE ASSEMBLY)
什么是內聯匯編(Inline assembly)?
1、這是GCC對C語言的擴張,就是在C代碼里面去寫匯編代碼
2、可以直接在C的語句中插入匯編指令
有何用處?
1、C語言不足以完成所有CPU的指令, 特別是有一些特權指令,比如加載gdt表(Global Descriptor Table 全局描述符表),從而使用匯編代碼來完成
2、用匯編在C語言中手動優化,特別是在操作系統當中,使用匯編對操作系統的掌控更為精准,更加准確。
如何工作?
1、用給定的模板和約束來生成匯編指令
2、才C函數內形成匯編代碼
下面一個小例子,簡單看一下匯編代碼和內聯匯編的不同:
GCC內聯匯編-Example 1
匯編代碼 Assembly(*.S):
movl $0xffff, %eax //把0xffff給eax
內聯匯編 Inline assembly(*.c):
asm("movl $0xffff, %%eax\n") //1、加了一個內聯匯編關鍵字asm,把匯編代碼括起來然后用引號表示一個字符串 2、寄存器前變為%%
GCC內聯匯編-語法
asm("assmbler template" //assmbler template就是example 1 的那個字符串的內容(匯編語句)
:output operands (optional) //可選的輸出操作數(輸出寄存器)
:input operands (optional) //可選的輸入操作數(輸入寄存器)
:clobbers (optional) //會被修改的寄存器
);
GCC內聯匯編-Example2
Inline assembly(*.c)
uint32_t cr0; //一個叫cr0的變量
asm volatile("movl %%cr0, %0\n" :"=r"(cr0)); //把cr0里面的內容讀到%0這個寄存器當中, =r這個寄存器的內容會賦給cr0這個變量(輸出操作)
cr0 |= 0x80000000; //把某一個位設成1
asm volatile("movl %0, %%cr0\n" ::"r"(cr0)); //再把cr0變量里的內容寫回到cr0寄存器當中。把cr0給一個寄存器,然后這個寄存器再把他里面的內容賦給cr0寄存器(輸入操作)
一些關鍵字的含義
volatile:No reordering; No elimination. 不需要進一步的優化,不需要進一步的調整順序
%0 :The first constraint following. 第一個用到的寄存器
r :A constraint; GCC is free to use any register. 任意一個寄存器
上面的內聯匯編所對應的匯編代碼如下
Generated assembly code(*.s):
movl %cr0, %ebx //cr0 --> ebx
movl %ebx, 12(%esp) //ebx賦給一個局部變量12(%esp)
orl $-2147483648, 12(%esp) //或操作
movl 12(%esp), %eax //再給eax
movl %eax, %cr0 //再把eax寄存器里面的內容賦給cr0
GCC內聯匯編-Example3
Inline assembly(*.c)
long _res, arg1 = 2, arg2 = 22, arg3 = 222, arg4 = 233;
_asm_volatile("int $0x80"
:"=a"(_res)
:"0"(11), "b"(arg1), "c"(arg2), "d"(arg3), "S"(arg4)); //把arg1給ebx, arg2給ecx,arg3給edx, arg4給esi
在內聯匯編當中
a = %eax, b = %ebx, c = %ecx, d = %edx, S = %esi, D = %edi, 0 = same as the first 第一個出現的寄存器
Generated assembly code(*.s):
mov $11, %eax
movl-28(%ebp), %ebx
movl-24(%ebp), %ecx
movl-20(%ebp), %edx
movl-16(%ebp), %esi
int $0x80
movl %edi, -12(%ebp)
如果想要了解GCC內聯匯編更多的知識,請訪問
Inline assembly for x86 in Linux
http://www.ibm.com/developerworks/library/l-ia/index.html