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);
}