c++之于80X86汇编之stdcall,cdecl调用

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qingshuiaishui/article/details/83692102

stdcall:windows API调用方式,即WINAPI。

cdecl:c语言默认调用方式。

问题的由来。不同的调用方式,包括其它调用方式,fastcall,thiscall等等,主要是为了解决函数调用中,参数的传递问题。stdcall和cdecl调用都是通过栈来传递参数。调用之前先将参数入栈,再调用函数,调用后再清理栈。由此就有了不同的调用方式约定,这些调用方式决定了参数的传递方式及清理栈的负责方(调用方或被调用方)。

具体表现。在asm层面,两者表现为ESP指针的调整对象为调用方或被调用方。stdcall,ESP由被调用方,即函数本身来调整栈顶指针(ESP).;cdecl,ESP由调用方调整ESP。最终使执行下一条语句之前名ESP指针恢复到原来的值。在asm代码层面表现为:stdcall 调用 方式最后ret 指令为 ret x; 意义为函数调用结束,并且执行add esp,x。而cdecl调用方式,只是最后简单执行ret指令,因为由调用方来平衡栈。

那么为什么非要使调用后的ESP与调用之前一致呢?其中最重要的一点就是节省内存空间。若是不恢复ESP,则会一直增大,最后会使栈本身很大,没有内存可分配。

例:

c/c++代码:

int _stdcall add_stdcall(int m,int n)
{
    return m+n;
}
int _cdecl add_cdecl(int m,int n)
{
    return m+n;
}

等效的80x86 ASM代码:

add_stdcall proc
	push ebp
	mov ebp,esp
	
	mov eax,DWORD PTR [ebp+8]
	add eax,DWORD PTR [ebp+12]
	
	mov esp,ebp
	pop ebp
	ret 8
add_stdcall endp

add_cdecl proc
	push ebp
	mov ebp,esp
	
	mov eax,DWORD PTR [ebp+8]
	add eax,DWORD PTR [ebp+12]
	
	mov esp,ebp
	pop ebp
	ret
add_cdecl endp    

调用方式如下:

;szfmt db 'result=%u',13,10,0 

;stdcall
push 100
push 200
call add_stdcall

push eax
push offset szfmt
call crt_printf
add esp,8
;cdecl
push 300
push 400
call add_cdecl
add esp,8

push eax
push offset szfmt
call crt_printf
add esp,8

猜你喜欢

转载自blog.csdn.net/qingshuiaishui/article/details/83692102
今日推荐