linux c 中嵌入彙編
爲了提高代碼的執行效率,有時程序中需要使用彙編語言來編制源代碼。這就涉及在兩種語言的相互調用問題,而且linux 使用的是 AT&T 的彙編語言格式,與 INTEL 彙編的有所區別,詳細可以參考相關書籍。
在彙編應用程序中調用 C 函數主要涉及彙編程序如何向 C 函數傳遞參數以及相關寄存器的保存,我們先看一個將C 程序轉換編譯成彙編程序的代碼,看看彙編程序調用函數時所做的處理:
/* 交換 a 和 b 的值 */
void swap(int *a, int *b, int d, int e, int f, int g, int h, int m, int n)
{
int c;
c = *a; *a = *b; *b = c;
}
int main(void)
{
int a, b;
a = 16; b = 32;
swap(&a, &b, 0, 0, 0, 0, 0, 0, 0);
return (a - b);
}
將文件保存爲 swap.c,這裏將 swap.c 文件中加入了多餘的幾個參數,來說明彙編程序的傳遞參數機制。
使用命令 gcc -Wall -S -o swap.s swap.c 生成該 C 語言程序的彙編程序 swap.s
swap:
pushl %ebp
movl %esp, %ebp
subl $16, %esp
movl 8(%ebp), %eax
movl (%eax), %eax
movl %eax, -4(%ebp)
movl 12(%ebp), %eax
movl (%eax), %edx
movl 8(%ebp), %eax
movl %edx, (%eax)
movl 12(%ebp), %edx
movl -4(%ebp), %eax
movl %eax, (%edx)
leave
ret
main:
leal 4(%esp), %ecx
andl $-16, %esp
pushl -4(%ecx)
pushl %ebp
movl %esp, %ebp
pushl %ecx
subl $52, %esp
movl $16, -8(%ebp)
movl $32, -12(%ebp)
movl $0, 32(%esp)
movl $0, 28(%esp)
movl $0, 24(%esp)
movl $0, 20(%esp)
movl $0, 16(%esp)
movl $0, 12(%esp)
movl $0, 8(%esp)
leal -12(%ebp), %eax
movl %eax, 4(%esp)
leal -8(%ebp), %eax
movl %eax, (%esp)
call swap
movl -8(%ebp), %edx
movl -12(%ebp), %eax
movl %edx, %ecx
subl %eax, %ecx
movl %ecx, %eax
addl $52, %esp
popl %ecx
popl %ebp
leal -4(%ecx), %esp
ret
在 swap 中可以看出彙編程序從 main 的棧中取出參數 a 和 b,然後進行交換,並返回;而在 main 程序中,調用 swap 之前爲它的參數分配了 52 字節的空間,顯然我們這裏只是使用了9個參數需要的空間爲 4*9=36 字節的空間就夠使用,那麼額外的 52-36=16 字節用作什麼用途呢?另外在 main 的開始處的 andl 指令我覺得應該是使棧空間16字節對齊的操作;當將 C 程序中 swap 函數的參數改變時,可以看出其對應的彙編程序中也總是有16字節的額外空間,留作疑問。
C 語言中嵌入彙編的操作,只需要遵循一定的格式,然後使用匯編指令就可以,如下面代碼
char* strcpy(char *dest, const char *src)
{
__asm__
("cld/n"
"1:/tloadsb/n/t"
"stosb/n/t"
"testb %%al, %%al/n/t"
"jne 1b"
::"S"(src),"D"(dest)//:"si","di","ax"/* 可能是應用程序中不用指出變化的寄存器 */
/* 否則將 gcc 報錯: can't find a register in class ‘SIREG’ while reloading ‘asm’ */
);
return dest;
}
上面的/n/t轉換是爲了彙編代碼整齊,沒有特殊的含義。可以看出,嵌入彙編時需要使用 __asm__(); 嵌入彙編代碼,也可以使用 asm(); 但是爲了向前兼容最好使用前面的格式。
而在C程序調用匯編函數過程中,只要遵循參數的反向壓入棧,而且彙編程序按照依次取出參數就可以了,從上面的幾個例子中不難寫出一個C函數調用純彙編過程的源程序,不再示例。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.