|
本節(jié)是對(duì)前文的代碼說明,代碼再貼過來,C_with_S_c.c如下: 1 extern void asm_print(char*,int); 2 void c_print(char* str) { 3 int len=0; 4 while(str[len++]); 5 asm_print(str, len); 6 } 代碼C_with_S_c.c的第1行是聲明外部函數(shù)asm_print,通知編譯器這個(gè)函數(shù)并不在當(dāng)前文件中定義。我們知道它定義在文件C_with_S_S.S中,但編譯器是不知道的,所以只能在鏈接階段將此函數(shù)重新定位,編排地址。 第2~6行是c_print的實(shí)現(xiàn),在它的內(nèi)部,它又調(diào)用了匯編代碼C_with_S_S.S中的函數(shù)asm_print,經(jīng)過第1行的聲明,我們要給它提供兩個(gè)參數(shù):字符串的起始地址及長(zhǎng)度。 特別強(qiáng)調(diào)一下,由于這里并不打算把c標(biāo)準(zhǔn)庫也鏈接進(jìn)來,所以在求字符串長(zhǎng)度時(shí),我們不能用string.h中的strlen函數(shù)。也就是說即使include <string.h>將其strlen的聲明加進(jìn)來,沒有strlen實(shí)現(xiàn)本身所在的.o文件也是不行的。函數(shù)聲明的作用是:一方面是告訴編譯器該函數(shù)的參數(shù)所需要的??臻g大小及返回值,這樣編譯器能為其準(zhǔn)備好執(zhí)行環(huán)境,另一方面是如果該函數(shù)是在外部文件中定義的,一定要在鏈接階段時(shí)將其對(duì)應(yīng)的目標(biāo)文件一塊鏈接進(jìn)來。所以這里第3~4行通過while循環(huán)求字符串的長(zhǎng)度。字符串結(jié)尾必須是空字符’\0’才行,否則while就是死循環(huán)了。這個(gè)字符串是代碼C_with_S_S.S提供的,我們轉(zhuǎn)過去看看。 1 section .data 2 str: db 'asm_print says hello world!', 0xa, 0 3 ;0xa是換行符,0是手工加上的字符串結(jié)束符的ascii碼。 4 str_len equ $-str 5 6 section .text 7 extern c_print 8 global _start 9 _start: 10 ;;;;;;;;;;;; 調(diào)用c代碼中的函數(shù)c_print ;;;;;;;;;;; 11 push str ;傳入?yún)?shù) 12 call c_print ;調(diào)用c函數(shù) 13 add esp,4 ;回收??臻g 14 15 ;;;;;;;;;;;;;;;;;;; 退出程序 ;;;;;;;;;;;;;;;;;;;; 16 mov eax,1 ;第1號(hào)子功能是exit系統(tǒng)調(diào)用 17 int 0x80 ;發(fā)起中斷,通知linux完成請(qǐng)求的功能。 18 19 global asm_print ;相當(dāng)于asm_print(str,size) 20 asm_print: 21 push ebp ;備份ebp 22 mov ebp,esp 23 mov eax,4 ;第4號(hào)子功能是write系統(tǒng)調(diào)用 24 mov ebx, 1 ;此項(xiàng)固定為文件描述符1,標(biāo)準(zhǔn)輸出(stdout)指向屏幕 25 mov ecx, [ebp+8] ;第1個(gè)參數(shù) 26 mov edx, [ebp+12] ;第2個(gè)參數(shù) 27 int 0x80 ;發(fā)起中斷,通知linux完成請(qǐng)求的功能。 28 pop ebp ;恢復(fù)ebp 29 ret 在代碼C_with_S_S.S的第2行,定義待打印的字符串時(shí),在結(jié)尾人為的加了個(gè)0,它就是空字符’\0’的ascii碼。 第8~9行是將_start導(dǎo)出為全局符號(hào),為的是給鏈接器用的,之前解釋過了。 為了在匯編文件中引用外部的函數(shù)(未必是c代碼中的),需要用extern來聲明所需要的函數(shù)名。 由于我們用到了外部的函數(shù)c_print,所以在第7行用extern c_print來聲明c_print函數(shù)是外部的。第11~13行是為外部函數(shù)c_print壓棧傳參,調(diào)用它后清理?xiàng)?臻g。 第16~17行是調(diào)用exit系統(tǒng)調(diào)用告訴linux我要正常退出。 在匯編語言中導(dǎo)出符號(hào)名是用global關(guān)鍵字,這在之前說_start時(shí)大伙已有所耳聞,global是將符號(hào)導(dǎo)出為全局屬性,對(duì)程序中的所有文件可見,這樣其它外部文件中也可以引用被global導(dǎo)出的符號(hào)啦,無論該符號(hào)是函數(shù)還是變量。 由于在c代碼文件C_with_S_c.c中也調(diào)用了這里的asm_print函數(shù),所以為了讓外部代碼可以引用asm_print。我們?cè)诘?9行用global asm_print將其導(dǎo)出。 第20行之后是asm_print的實(shí)現(xiàn),相信大家已經(jīng)非常明白了,不解釋。 好啦,通過這兩個(gè)例子我相信大伙兒已經(jīng)掌握c和匯編混合編程的方法啦,確切說是方法之一。對(duì)于這種匯編代碼和C代碼單獨(dú)編譯的方式還是較容易的,以后咱們會(huì)講C內(nèi)聯(lián)匯編的方式難為難為大家的,玩笑玩笑,只要用心沒有學(xué)不會(huì)的(聽上去似乎覺得更難了^_^,沒事沒事)。 有關(guān)混合編程的部分就說完了,總結(jié)一下:
|
|
|