米虚 2020-05-19
对函数调用时如何传递参数的一种约定,我们知道调用函数前需要将参数压入栈然后再传递给函数,栈就是定义在进程中的一段内存,向下扩展,大小记录在PE头中,运行时确定栈的大小
函数执行完毕后,ESP的值如何变化?
ESP的值恢复到函数调用之前,这样可引用的栈大小不会缩减
int function(int a, int b) { return a + b; } void main() { function(10, 20); }
主要函数约定如下:
__cdecl函数调用约定是我们最长见的一种约定,我们平时在写程序的时候默认会使用该种约定,其特点如下:
_function push ebp mov ebp, esp mov eax, [ebp+8] ;参数1 add eax, [ebp+C] ;加上参数2 pop ebp retn _main push ebp mov ebp, esp push 14h ;参数 2入栈 push 0Ah ;参数 1入栈 call _function ;调用函数 add esp, 8 ;修正栈 xor eax, eax pop ebp retn
__stdcall约定是我们在写WinAPI的时候经常用的约定,很多windows下面的API都是该种调用约定,其特点如下:
8 push ebp mov ebp, esp mov eax, [ebp] ;参数 1 add eax, [ebp+C] ;加上参数 2 pop ebp retn 8 ;修复栈 _main push ebp mov ebp, esp push 14h ;参数 2入栈 push 0Ah ;参数 1入栈 call 8 ;函数调用 xor eax, eax pop ebp retn
从名称上可以看出是速度快,因为其参数是可以放在寄存器中传递的,通常需要在要求高效率的函数中使用此约定,其特点如下:
该约定是高效率的调用约定,和另外两种约定最大的区别就是参数的传递方式,利用了寄存器来快速的传递
@8 push ebp mov ebp, esp ;保存栈指针 sub esp, 8 ;多了两个局部变量 mov [ebp-8], edx ;保存参数 2 mov [ebp-4], ecx ;保存参数 1 mov eax, [ebp-4] ;参数 1 add eax, [ebp-8] ;加上参数 2 mov esp, ebp ;修正栈 pop ebp retn _main push ebp mov ebp, esp mov edx, 14h ;参数 2给EDX mov ecx, 0Ah ;参数 1给ECX call @8 ;调用函数 xor eax, eax pop ebp retn