Friday, February 19, 2010

Function-call Conventions

Ref:
Assembly view:http://unixwiz.net/techtips/win32-callconv-asm.html
C view:http://unixwiz.net/techtips/win32-callconv.html

code from MS VS:

1.1 cdecl callee
void __cdecl ccall(int arg1)
{
004115A0 push ebp
004115A1 mov ebp,esp //前面2行是标准的函数入口开头,LINUX也这样
004115A3 sub esp,0C0h //留一段STACK空间
004115A9 push ebx
004115AA push esi
004115AB push edi //前面3行以前总是不明白。现在清楚了,因为后面要用到那些寄存器,所以这里先保存到堆栈上。
004115AC lea edi,[ebp-0C0h]
004115B2 mov ecx,30h
004115B7 mov eax,0CCCCCCCCh //这个 CCCCCCCC 是不是很熟悉?如果是,那么说明你经常犯没有初始话局部变量的错误
004115BC rep stos dword ptr es:[edi] //到这里,目的就是把堆栈上的局部变量设定一个初始值 CCCCCCCCh ,这样出了问题好查。 这些是WINDOWS特有的。或者是MS VS 特有的。
arg1++;
004115BE mov eax,dword ptr [arg1]
004115C1 add eax,1
004115C4 mov dword ptr [arg1],eax
}
004115C7 pop edi
004115C8 pop esi
004115C9 pop ebx //一堆POP,把之前保存的寄存器恢复。注意顺序很重要。
004115CA mov esp,ebp
004115CC pop ebp
004115CD ret //终于返回了。

1.2 cdecl 的caller
ccall(2);
00411670 push 2
00411672 call ccall (41114Ah)
00411677 add esp,4
很明显的可以看到 1.2 里的最后一行,就是caller在清堆栈。

下面再看看stdcall的例子
2.1 stdcall callee
void __stdcall stcall(int arg1)
{
004115E0 push ebp
004115E1 mov ebp,esp
004115E3 sub esp,0C0h
004115E9 push ebx
004115EA push esi
004115EB push edi
004115EC lea edi,[ebp-0C0h]
004115F2 mov ecx,30h
004115F7 mov eax,0CCCCCCCCh
004115FC rep stos dword ptr es:[edi]
arg1++;
004115FE mov eax,dword ptr [arg1]
00411601 add eax,1
00411604 mov dword ptr [arg1],eax
}
00411607 pop edi
00411608 pop esi
00411609 pop ebx
0041160A mov esp,ebp
0041160C pop ebp
0041160D ret 4 //这个地方和前面的CDECL CALL不一样了。终于发现你了!

2.2 stdcall caller
stcall(3);
0041167A push 3
0041167C call stcall (411203h)

No comments: