一. 概述
匯編通過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的代碼:
#include<stdio.h>
static int i = 0;
void c_add(int *k)
{
(*k)++;
}
int main(void)
{
a_add(&i);
printf("%d\n",i);
return 0;
}
assembly.s的代碼:
.section .text
.type a_add,@function
.globl a_add
a_add:
pushl %ebp #現場保護
movl %esp,%ebp
movl 8(%ebp),%eax #取得C函數傳過來的參數
pushl %ecx #保護ecx,用作臨時變量
movl (%eax),%ecx #取得指針所指的內容
addl $1,%ecx #將內容+1
movl %ecx,(%eax) #將內容放回指針所指的地方
popl %ecx #恢復ecx
pushl %eax #壓桟,以便傳參給C函數
call c_add #調用C函數
addl $4,%esp #清理局部變量
popl %ebp #恢復現場
ret #返回
運行結果:
可見程序輸出2,符合預期效果。