在http://yasm.tortall.net/Download.html选择win32.exe,将其改名为yasm.exe,并将其添加至D:\Program Files\Microsoft Visual Studio 9.0\VC\bin下(安装目录不同的对应更改)
在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汇编器选项,勾上,确定。
汇编编写的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
int sum(int, int);//函数声明
int main()
{
int c;
c = sum(2,5);
printf("%3d\n",c);
return 0;
}
cpp文件调用汇编sum函数
//ctest.cpp
#include
//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;
}
汇编函数不一样了注意函数名_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 ;被调用者平衡堆栈
//ctest.c
#include
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;
}
//ctest.cpp
#include
//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;
}
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
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);
}
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
extern "C" void _stdcall myprint(int a)
{
printf("myprint %d\n",a);
}
extern "C" void _stdcall myprint_asm(int);
void main()
{
myprint_asm(16);
}