函数
来源:互联网 发布:淘宝客微信淘口令 编辑:程序博客网 时间:2024/06/05 05:39
调用约定和返回值
void __cdecl fun1(int a){ printf("%d", a);}__int64 __stdcall fun2(__int64 a){ printf("%d", a); return a;}double __fastcall fun3(int a){ printf("%d", a); return (double)a;}int main(int argc, char* argv[]){ fun1(1); fun2(1); fun3(1); return 0;}
调用约定
__cdecl
C 调用约定在函数外有平栈的动作,不定参数的函数可以使用
___stdcall
标准调用约定在函数内平栈,不定参数的函数无法使用
___fastcall
由寄存器传参,被调方平栈,不定参数的函数无法使用
返回值
无返回值
在函数末尾没有对 eax 重新定义,且出函数后 eax 没有使用即被覆盖,可判断该函数无返回值。
如果函数的返回值是一个函数,函数的末尾也不会对 eax 重新定义
有返回值
返回值为 int
返回值存储在在 eax 中
返回值为 ___int64
返回值存储在 edx 和 eax 中
返回值为 float 或者 double
double 和 float 作为返回值时通过浮点栈顶传参。double 和 float 都是使用的 fld 操作符
参数
void __cdecl fun1(char c, float f, int i, double dbl, __int64 i64){ printf("%d", c + f + i + dbl + i64);}int main(int argc, char* argv[]){ fun1(1, 1.0f, 2, 2.0, 2); return 0;}
判断传入参数的个数
从经验而言,在函数调用前,有多少 push,即是调用了几个参数。但并不是正确的判断的方法,受调用约定和参数的类型影响,需要根据 引用参数 的个数来决定传入的参数个数。
传入 8 字节的参数
会分别 push 两次
char 有无符号的判断
由于使用了操作符 movsx 进行了符号扩展,所以可以判断传入得参数是有符号得 char。
函数作为参数
void __cdecl fun1(char c, int i, float f){ printf("%d", c + f + i);}int __cdecl fun2( int i, double dbl){ printf("%d", i + dbl); return i;}int main(int argc, char* argv[]){ fun1(1, fun2(1, 2.0), 1.0f); return 0;}
如果参数中包含函数,反汇编看起来会比较琐乱。此时,先分析第一个 call 中传入了几个参数,根据参数传入的个数往上划定 push 的个数,依次划定…
其他
寄存器的保存
再进入函数前为局部变量开辟空间时,有时为了减少指令周期,sub esp, 4 指令会优化为 push 指令。如图中的 push ecx 并非保存寄存器环境,而是为局部变量 var_4 开辟空间。