在/linux0.11/kernel/trap.c文件中,第一次接觸到C語言中的嵌入式彙編代碼。詳細的使用說明可以參考GNUgcc手冊中第4章的內容或者參考文獻《using assembly with gcc》。
具有輸入和輸出參數的嵌入式彙編的基本格式爲:
在/linux0.11/kernel/trap.c文件中,第一次接觸到C語言中的嵌入式彙編代碼。詳細的使用說明可以參考GNUgcc手冊中第4章的內容或者參考文獻《using assembly with gcc》。
具有輸入和輸出參數的嵌入式彙編的基本格式爲:
asm("彙編語句“
asm("彙編語句“
: 輸出寄存器
: 輸入寄存器
: 會被修改的寄存器);
其中,”彙編語句“是你寫彙編指令的地方;”輸出寄存器“表示當這段嵌入彙編執行完之後,哪些寄存器用於存放輸出數據。”輸入寄存器“表示在執行彙編代碼時,這裏指定的一些寄存器中應該存放的輸入值,他們分別對應着一C變量或者常數值。下面將舉例說明嵌入式彙編的具體因使用方法。
例如1:
#define get_seg_byte(seg,addr)\
({\
register char _res;\
__asm__("push %% fs; \
mov %%ax,%%fs;\
movb %%fs:%2,%%al;\
pop %%fs\
:"=a"(_res) \
:"0"(seg),"m"(*(addr)));\
_res;})
這段代碼定義了1個嵌入式彙編函數。因爲是宏語句,需要在一行上定義,因此這裏使用反斜行‘\’將這些語句連成1行。第1行定義了宏的名稱,即宏函數名稱爲get_seg_byte(seg,addr)。第3行定義了一個寄存器變量_reg 。 第4行上的_asm_表示嵌入彙編語句開始。從第4行到第7行的4條AT&T 格式的彙編語句。
第8行是輸出寄存器,這句話的含義是在這段代碼運行結束後將eax所代表的寄存器中的值放入_res 變量中,作爲本函數的輸出值。爲了在上面彙編語句中使用該地址值,嵌入彙編程序規定把輸入和輸出寄存器統一按順序編號,順序是從輸出寄存器序列從左到右從上到下以%0 開始,分別記爲%0,%1,%2....%9。因此,輸出寄存器編號爲%0 輸入寄存器前一部分""(seg)的編號爲%1,而後一部分的編號爲%2. 上面第6行上的%2代表(*(addr))這個內存偏移量。
現在分析4-7行上代碼的具體作用。第1句將fs段寄存器的內容入棧;第2句將eax中的段值賦給fs段寄存器;第3句是把fs:(*addr))所制定的字節放入al寄存器。當執行完彙編語句後,輸出寄存器eax的值將被放入_res。
經過上面的分析,我們知道宏名稱中的seg代表一指定的內存段值,而addr表示一內存偏移地址量。到現在爲止,我們應該很清楚這段程序的功能。該宏函數是從指定的段和偏移量的內存地址處取一個字節。
例如2:
asm("cld\n\t"
"rep\n\t"
"stol"
:
:"c"(count-1),"a"(fill_value),"D"(des)
:"%ecx","%edi");
1-3行這三句是常用的彙編語句,用以清方向標識位,城府保存值。第四行說明沒有用到輸出寄存器。第5行的含義是將count-1的值將在到ecx寄存器中(加載碼是“c“)fill_value 加載到eax中,dest放到edi中。 爲什們要讓gcc編譯程序去做這樣的加載,而不讓我們自己做呢?因爲gcc在它進行寄存器分配時可以進行某些優化工作。例如fill_value值可能已經加載到eax中。如果在一個循環語句中的話,gcc可能在整個循環操作中保存eax,這樣就可以在每次循環中少用1個movl語句。
最後1行是告訴gcc這些寄存器中的值已經改變了。很奇怪吧?不過,gcc知道你拿這些寄存器做了什麼後,這確實能夠對gcc的優化操作有所幫助。
下面是可能會用的寄存器加載碼及其具體含義:
代碼 說明
a 使用寄存器eax
b 使用寄存器ebx
c 使用寄存器ecx
d 使用寄存器edx
S 使用寄存器esi
D 使用寄存器edi
q 使用動態分配字節可尋址寄存器 (eax、ebx、ecx或edx)
r 使用任意動態分配的寄存器
g 使用通用有效的地址即可(eax、ebx、edx、ecx 或者內存變量)
A 使用eax和edx聯合(64bit)
m 使用內存地址
o 使用內存地址,並可以加載偏移值
I 使用常數0-31
J 使用常數0-63
K 使用常數0-255
L 使用常數0-65536
M 使用常數0-3
N 使用1字節常數(0-255)
O 使用常數0-31
下面的例子不是讓自己制定那個變量使用那個寄存器,而是讓gcc爲你選擇
asm("leal(%1,%1,4),%0"
:"r"(y)
:"0"(x));
第1句leal(r1,r2,4),r3 語句表示r3=r1+r2×4。這個例子可以非常快的將x成5.其中"%0","%1" 是指gcc自動分配的寄存器。這裏%1 代表輸入值x要放入的寄存器,”%0“表示輸出寄存器。所以如果gcc將r指定爲eax的話,那麼上面彙編語句的含義爲”leal(eax,eax,4),eax" 注意 如果不希望彙編語句被gcc優化而挪動地方,就需要在asm符號後面添加volatile關鍵字
asm volatile();或者
__asm__ __volatile__();