在linux/include/unistd.h中定義的系統調用嵌入彙編宏函數_syscall0。
其實展開不難發現就是一個函數,只不過用宏定義了。其中關鍵的是怎麼理解 __asm__ volatile這個文法。對於__asm__ volatile這個固定形式,我們暫且不理會它(可參考http://blog.csdn.net/robbie1314/archive/2011/04/17/6329880.aspx),關鍵看懂()裡面的含義。
以下面這個為例子先簡要介紹一下這個用法。
插入C語言的一個組合語言程式碼片段可以分成4部分,以“:”號加以分隔,其一般形式為:
指令部:輸出部:輸入部:損壞部
static __inline__ void atomic_add(int i, atomic_t *v)
{
__asm_volatile__(
LOCK "addl %1, %0"
: "=m" (v->counter)
: "ir" (i), "m" (v->counter));
}
當組合語言代碼嵌入到C代碼時,解決運算元和C代碼中的變數結合是一個問題。我們無法確切知道gcc在嵌入點的前後會把哪個寄存器分配給哪個變數等,所以gcc採用一種方法:程式員只提供具體的指令,而對寄存器的使用則一般只提供一個“樣板”和一些約束條件,而到底如何把變數和運算元結合的問題留給gcc和gas去處理。
指令部
數字加上首碼%,如%1、%0等,表示需要使用寄存器的樣板運算元。可以使用的此類運算元的總數取決於具體CPU中通用寄存器的數量。
輸出部
規定對輸出變數,即目標運算元如何結合的約束條件。每個這樣的條件稱為一個“約束條件”。必要時輸出部可以有多個約束條件,互相以逗號分隔。每個輸出約束以“=”號開頭,然後是一個字母表示對運算元類型的說明,然後是關於變數結合的約束。例子中:
: “=m” (v->counter)
這裡只有一個約束條件,“=m”表示相應的目標運算元(指令中的%0)是一個記憶體單元v->counter。
輸入部
輸入部約束的格式和輸出約束相似,但不帶“=”號。例子中:
第1個為"ir" (i),表示指令中的%1可以是一個在寄存器中的“直接運算元”(i表示immediate),並且該運算元來自於C代碼中的變數名(這裡是調用參數)i。
第2個約束條件“m” (v->counter)意義與輸入約束相同。
損壞部
有些操作中,除了用於輸入運算元和輸出運算元的寄存器外,還要將若干個寄存器用於計算或者操作的中間結果。這樣,這些寄存器原有的內容就損壞了,所以要在損壞部對操作的副作用加以說明,讓gcc採取相應的措施。不過,有的時候就直接把這些說明放在輸出部了,那也並無不可。
運算元的編號從輸出部的第一個約束(序號為0)開始,順序數下來,每個約束計數加1次。在指令部中引用這些運算元或分配用於這些運算元的寄存器時,就在序號前面加上%號。
表示約束條件的字母有很多,主要有:
"m"、"v"和"o" ---- 表示記憶體單元
"r" ---- 表示任何寄存器
"q" ---- 表示寄存器eax,ebx,ecx,edx之一
"i"和"h" ---- 表示直接運算元
"E"和"F" ---- 表示浮點數
"g" ---- 表示任意
"a","b", "c" "d" ---- 分別表示要使用寄存器eax ebx ecx和edx
"S"和"D" ---- 分別表示要使用寄存器esi和edi
"I" ---- 表示常數(0至31)
回到上面的例子,這段代碼的作用是將參數i的值加到v->counter上。代碼的關鍵字LOCK表示在執行addl指令時要把系統匯流排鎖住,不讓別的CPU打擾,以保證原子性操作。
下面就可以照著上面的說明把下面代碼看懂吧。
代碼:
/* 以下定義系統調用嵌入式彙編宏函數 */
/* 不帶參數的系統調用宏函數。type name(void)。
* %0 -eax(__res), %1 - eax(__NR_##name)。其中name是系統調用的名稱
* 與 __NR_ 組合形成上面的系統調用符號常用,從而用來對系統調用表中函數指標定址
* 調用系統中斷0x80,傳回值->eax(_res), 輸入為系統中斷調用號__NR_name
* 返回: 如果傳回值大於等於0,則返回該值,否則置出錯號errno,並返回-1
*/
#define _syscall0(type, name)/
type name(void)/
{/
long __res;/
__asm__ volatile ("int $0x80" /
: "=a" (__res) /
: "" (__NR_##name));/
if (__res >= 0)/
{/
return (type)__res;/
}/
errno = -__res;/
return -1;/
}
/* 有1個參數的系統調用宏函數。type name(atype a)
* %0 - eax(__res), %1 - eax(__NR_name), %2 - ebx(a)
*/
#define _syscall1(type, name, atype, a) /
type name(atype a)/
{/
long __res;/
__asm__ volatile ("int $0x80"/
: "=a" (_res)/
: "" (__NR_#name), "b" ((long)(a)));/
if (__res >= 0)/
{/
return (type)__res;/
}/
errno = -__res;/
return -1;/
}
/* 有2個參數的系統調用宏函數。type name(atype a, btype b)
* %0 - eax(__res), %1 - eax(__NR_name), %2 - ebx(a), %3 - ecx(b)
*/
#define _syscall2(type, name, atype, a, btype, b)/
type name(atype a, btype b)/
{/
long __res;/
__asm__ volatile ("int $0x80"/
: "=a" (__res)/
: "" (__NR_##name), "b" ((long)(a)), "c" ((long)(b)));/
if (__res >= 0)/
{/
return (type)__res;/
}/
errno = -__res;/
return -1/
}
/* 有3個參數的系統調用宏函數。type name(atype a, btype b, ctype c)
* %0 - eax(__res), %1 - eax(__NR_name), %2 - ebx(a), %3 - ecx(b), %4 - edx(c)
*/
#define _syscall3(type, name, atype, a, btype, b, ctype, c) /
type name(atype a, btype b, ctype c)/
{/
long __res;/
__asm__ volatile ("int $0x80"/
: "=a" (__res) /
: "" (__NR_##name), "b" ((long)(a)), /
"c" ((long)(b)), "d" ((long)(c)));/
if (__res >= 0)/
{/
return (type)__res;/
}/
errno = -__res;/
return -1;/
}