A: 在C代码中调用汇编程序
1..如果遵守C 调用约定 FOR C
global _add ;全局函数声明,表示这个函数要被外部文件调用 _add: 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 ;调用者平衡堆栈
在C文件中声明函数 extern "C" int _cdecl add(int a,int b);
最主要的是要在ASM的函数名称的前面加上一个 _(下划线) ,但是在C文件中声明的函数不用加下划线,并且一定要加上extern "C",并且用_cdecl 声明,这样以后就可以在C中调用ASM中的函数了。
2.如果遵守stdcall 调用约定 FOR C++
还用上面的那个两个数相加的例子
global _add@8 ;全局函数声明,表示这个函数要被外部文件调用 _add@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 ;被调用者平衡堆栈
在ASM文件的开头写上 global _myaddstdcall@8
在C文件中声明函数 extern "C" int _stdcall myaddstdcall(int a,int b);
这里要注意的是函数的名称问题,一般是_XXX@N ,也就是在开头加上一个下划线,@N中的N就是参数的大小。
B: 在汇编中调用C中的函数
1.遵守C调用约定
举个例子:
extern "C" void _cdecl myprint(int a) { printf("myprint %d\n",a); }
在ASM中声明 extern _myprint ,然后就可以用 push xxx ,call myprint , add esp ,4 调用了
。要注意的是call 调用完后,一定要加上add esp ,X 来平衡堆栈,应为C调用约定规定是调用者平衡堆栈.
;extern _myprint global _myprint_asm _myprint_asm: push ebp ;保护ebp指针 mov ebp,esp mov eax,[ebp+8] ;第一个入口参数int VAR1 push eax ;保护ebp指针 call _myprint add esp ,4 调用了 pop ebp ;恢复ebp指针 ret ;调用者平衡堆栈
2.遵守stdcall 调用约定
extern "C" void _stdcall myprintstdcall(int a) { printf("myprintstdcall %d\n",a); }
在ASM中声明extern _myprintstdcall@4 ,然后用push xxx ,call _myprintstdcall@4 调动,这里就不用再加add esp,X了,有函数本身平衡堆栈.
extern _myprintstdcall@4 global _myprint_asm@4 _myprint_asm@4: push ebp ;保护ebp指针 mov ebp,esp mov eax,[ebp+8] ;第一个入口参数int VAR1 push eax ;保护ebp指针 call _myprintstdcall@4 pop ebp ;恢复ebp指针 ret 4 ;调用者平衡堆栈
这个就是入门的学习,非常简单的环境学习X86汇编。
入门回了,后面就是开始学习X86的基本指令,调试,以及学习MMX,.SSE!
下面是一个最简单的例子: Hello world
data segment ;数据段开始 str db 'Hello world. ', '$ ' ;字符串声明,以字节的存储形式,以‘$’结尾 data ends ;数据段结束 code segment ;代码段开始 assume cs:code,ds:data ;进行段的说明,说明一个对应的关系,之后再把段的首地址赋值给段寄存器,这样定义过的段才能被找到并被使用 main: ;程序代码段的开始标号 mov ax,data ;段段寄存器不能直接赋值,用ax做桥梁 mov ds,ax ;数据段寄存器 lea dx,str ;取str的有效地址 mov ah,09h ;中断调用入口参数 int 21h ;调用21h中断的09h号功能显示字符串 mov ah,4ch ;调用中断入口参数 int 21h ;调用21h中断的4ch功能功退出 code ends ;代码段结束 end main ;程序结束