1.gcc編譯程序支持的另一種編碼形式是內聯彙編(inline assembly)代碼。內聯彙編不需要調用單獨編譯的彙編程序。我們可以通過特定的結構告訴編譯程序將代碼組合到一起,而不是要編譯該代碼塊。雖然這樣做會生成體系結構相關的文件,但能大大提高C函數的可讀性並提高其執行效率。
內聯彙編程序的結構:
asm ( assembler instruction (s)
:output operands (optional)
:input operands(optioanl)
: clobbered registers (optional)
);
內聯彙編程序最基本的形式是:
asm ("movl %eax,%ebx");
也可以寫成:
asm ("movl %eax,%ebx" : : :);
輸出操作數:是一個C表達式列表,其後的圓括號中是約束條件。約束條件通常用“=”來表示,表示“只寫”;“&”表示這是一個已經被修改過的操作數
輸入操作數:語法同上,只是不用“=”修飾
修改過的寄存器:列出修改過的寄存器和內存
2.參數的編號方式
所有參數從0開始統一編號
例如,若有一個輸出參數和2個輸入參數,則%0是輸出參數,%1和%2都是輸入參數
3.約束條件
a:寄存器eax
b:寄存器ebx
c:寄存器ecx
d: 寄存器edx
S:寄存器esi
D:寄存器edi
I:常數(0....31)
q:從eax,ebx,ecx,edx動態分配一個寄存器
r:與q+esi,edi一樣
m:內存定位
A:與a+b的作用一樣。同時分配eax和ebx,形成一個64位寄存器
。。。。。
_volatile_:不要優化
例1:
int foo(void)
{
int ee=0x4000,ce=0x8000,reg;
_asm_ _volatile_("movl %1,%%eax",//將ce的值傳給eax
"movl %2,%%ebx";//將ee的值傳給ebx
"call setbits";//在彙編程序中調用函數
"movl %%eax,%0"//將返回值存儲到eax中,並將其複製給reg
: "=r"(reg)//輸出參數列表,reg屬性爲只寫
: "r"(ce),"r"(ee)//輸入參數列表,ce和ee是寄存器變量
: "%eax","%ebx"//寄存器修改列表,
)
printf("reg=%x",reg);
}
例2:
#define switch_to(prev,next,last) do{
unsigned long esi,edi;//局部變量
asm volatile(
"pushfl /n/t"
"pushl %%ebp/n/t"
"movl %%esp,%0/n/t"//把esp值複製給prev->thread.esp
" movl %5,%%esp/n/t"//將next->thread.esp賦值給esp
" movl $1f,%1/n/t"//保存eip的值
"pushl %6/n/t"//重新給eip賦值
"jmp _switch_to /n"
"1:/t"//參數被用作返回地址
"popl %%ebp/n/t"
"popfl"
:"=m" (prev->thread.esp),"=m"(prev->thread.eip),"=a"(last),"=S"(esi),"=D"(edi)//輸出參數列表
:"m"(next->thread.esp),"m"(next->thread.eip),"2"(prev),"d"(next)//輸入參數列表
);
}while(0)
/n/t與彙編程序的接口有關。每條彙編指令都應該在各自的線路上運行
輸出參數列表:
[%0]=(prev->thread.esp),只寫內存
[%1]=(prev->thread.eip),只寫內存
[%2]=(last),對寄存器eax只寫
[%3]=(esi),對寄存器esi只寫
[%4]=(edi),對寄存器edi只寫
輸入參數列表:
[%5]=(next->thread.esp),內存
[%6]=(next->thread.eip),內存
[%7]=(prev),重新使用2號參數(寄存器eax)作爲輸入
[%8]=(next),是賦給寄存器edx的一個輸入
此處沒有已修改寄存器列表