一. 概述
彙編通過call指令調用C函數,call指令主要有兩個功能:1.將下一條指令的地址儲存在棧頂;2.設定eip指向被調用程式碼的開始處。彙編使用ret指令返回,ret的功能是把返回地址從桟裡彈出,並轉到該地址去執行。
組譯工具調用C函數時,函數的入口參數使用堆棧來傳送。
C函數調用時,輸入參數採用堆棧方式傳遞,參數的行程順序是從右至左,調用者負責清除參數佔用的堆棧空間。
C函數的傳回值如果是32位整數則存在eax寄存器,如果是64位整數,則存在edx:eax寄存器。
二. 實現
下面的程式由2個檔案組成,一個是assembly.s,另外一個是gnuc.c。程式的功能是:在gnuc.c裡定義一個全域變數i,在main()函數裡調用assembly.s檔案裡的a_add()函數,將變數i的地址作為參數傳進去,在a_add()函數裡將變數i的值加1,然後調用gnuc.c檔案裡的c_add()函數,參數也是變數i的地址,在c_add()函數裡將參數所指的值加1,最後main()裡列印變數i的值。
gnuc.c的代碼:
1 #include<stdio.h> 2 3 static int i = 0; 4 5 6 void c_add(int *k) 7 { 8 (*k)++; 9 } 10 11 int main(void)12 { 13 a_add(&i);14 printf("%d\n",i);15 16 return 0;17 }
assembly.s的代碼:
1 .section .text 2 .type a_add,@function 3 .globl a_add 4 a_add: 5 pushl %ebp #現場保護 6 movl %esp,%ebp 7 8 movl 8(%ebp),%eax #取得C函數傳過來的參數 9 pushl %ecx #保護ecx,用作臨時變數10 movl (%eax),%ecx #取得指標所指的內容11 addl $1,%ecx #將內容+112 movl %ecx,(%eax) #將內容放回指標所指的地方13 popl %ecx #恢複ecx14 pushl %eax #壓桟,以便傳參給C函數15 call c_add #調用C函數16 17 addl $4,%esp #清理局部變數18 popl %ebp #恢複現場19 ret #返回
運行結果:
可見程式輸出2,符合預期效果。