函数

来源:互联网 发布:淘宝客微信淘口令 编辑:程序博客网 时间: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 开辟空间。

这里写图片描述

原创粉丝点击