利用yasm在vs2008中進行X86彙編與C/C++相互調用

1.工具的下載以及環境的搭建

    yasm的下載

    在http://yasm.tortall.net/Download.html選擇win32.exe,將其改名爲yasm.exe,並將其添加至D:\Program Files\Microsoft Visual Studio 9.0\VC\bin下(安裝目錄不同的對應更改)

    yasm.rules文件下載

    在https://github.com/yasm/yasm/blob/master/Mkfiles/vc9/yasm.rules上覆制yasm.rules的內容到記事本,另存爲yasm.rules,將其添加至D:\Program Files\Microsoft Visual Studio 9.0\VC\VCProjectDefaults下,此文件夾下還有兩個masm.rules(ml.exe的編譯規則)和lc.rules

    環境搭建

    新建項目後,右擊項目, 選擇自定義生成規則,查找現有的,找到剛剛的yasm.rules,選擇添加,OK,然後在對話框中就可以看到Yasm彙編器選項,勾上,確定。

2.不同調用約定下C或Cpp調用匯編

_cdecl調用約定

彙編編寫的sum函數

global _sum  ;全局函數聲明,表示這個函數要被外部文件調用,注意下劃線,c文件或cpp文件中相應函數去掉下劃線

_sum:

 push ebp        ;保護ebp指針

 mov ebp,esp

 mov eax,[ebp+8] ;第一個入口參數int a

 mov ebx,[ebp+12];第二個入口參數int b

 add eax,ebx

 pop ebp         ;恢復ebp指針

 ret            ;調用者平衡堆棧

    在工程中添加項sum_asm.asm,將內容寫入即可

c文件調用匯編sum函數

//ctest.c
#include <stdio.h>

int sum(int, int);//函數聲明

int main()
{
	int c;
	c = sum(2,5);
	printf("%3d\n",c);
	return 0;
}


cpp文件調用匯編sum函數

//ctest.cpp
#include <stdio.h>

//int sum(int, int);
extern "C" int _cdecl sum(int, int);//函數聲明

int main()
{
	int c;
	c = sum(2,5);
	printf("%3d\n",c);
	return 0;
}

_stdcall調用約定

彙編函數不一樣了注意函數名_sum@8和ret 8都表示參數的大小(字節數),_stdcall和_cdecl的區別是_stdcall是被調用者也就是這邊的sum函數平衡堆棧(ret 8的作用),

而_cdecl是調用者也就是這邊的main函數平衡堆棧,被調用者(sum函數)不需要自己平衡堆棧,所以只需要ret即可。

global _sum@8  ;全局函數聲明,表示這個函數要被外部文件調用

_sum@8:

 push ebp        ;保護ebp指針

 mov ebp,esp

 mov eax,[ebp+8] ;第一個入口參數int a

 mov ebx,[ebp+12];第二個入口參數int b

 add eax,ebx

 pop ebp         ;恢復ebp指針

ret 8            ;被調用者平衡堆棧

c文件調用sum函數

//ctest.c
#include <stdio.h>

int _stdcall sum(int, int);
//extern "C" int _stdcall sum(int, int);


int main()
{
	int c;
	c = sum(2,5);
	printf("%3d\n",c);
	return 0;
}

cpp文件調用sum函數

//ctest.cpp
#include <stdio.h>

//int _stdcall sum(int, int);
extern "C" int _stdcall sum(int, int);


int main()
{
	int c;
	c = sum(2,5);
	printf("%3d\n",c);
	return 0;
}


3.不同調用約定下彙編中調用C或Cpp

_cdecl調用約定

extern _myprint
global _myprint_asm
_myprint_asm:
	 push ebp        ;保護ebp指針
	 mov ebp,esp
	 mov eax,[ebp+8] ;第一個入口參數int VAR1
	 push eax       ;保護ebp指針	
	 call _myprint  ;調用C函數myprint
	 add esp ,4      ;調用者平衡堆棧
	 pop ebp         ;恢復ebp指針
	 ret            ;

觀察上面可以看到在_cdecl調用約定下,由調用者(此處是彙編語言中的_myprint_asm函數)平衡堆棧(add esp,4)

#include <stdio.h>

extern "C" void _cdecl myprint(int a) //此處爲cpp時,若是c時可以將extern "C"去掉
{
	printf("myprint %d\n",a); 
}

extern "C" void _cdecl myprint_asm(int);//同上

void main()
{
	myprint_asm(16);
}

_stdcall調用約定

extern _myprint@4
global _myprint_asm@4
_myprint_asm@4:
	 push ebp        ;保護ebp指針
	 mov ebp,esp
	 mov eax,[ebp+8] ;第一個入口參數int VAR1
	 push eax       ;保護ebp指針	
	 call _myprint@4  
	 pop ebp         ;恢復ebp指針
	 ret  4          ;調用者平衡堆棧
注意其中的幾處@4以及最後的ret4(相對於main函數,_myprint_asm是被調用者)
#include <stdio.h>

extern "C" void _stdcall myprint(int a)
{
	printf("myprint %d\n",a); 
}

extern "C" void _stdcall myprint_asm(int);

void main()
{
	myprint_asm(16);
}



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章