大神洗礼第四讲——函数相关及编程技巧
2012-11-02 22:47
225 查看
Author:bakari Date:2012.11.2
1、参数传递问题:
< 1 >、堆栈传参
< 2 >、寄存器传参(利用通用寄存器进行函数参数传递的方法)
< 3 >、全局变量或静态变量传参
2、 Call Convention(函数调用约定)
< 1 >、_cdecl
a、 参数从右向左压入堆栈
b、 函数被调用者修改堆栈
c、 在win32应用程序里,宏APIENTRY,WINAPI,都表示_stdcall,非常常见.
d、 C和C++程序的缺省调用方式。每一个调用它的函数都包含清空堆栈的代码,所以产生的可执行文件大小会比调用_stdcall函数的大。
< 2 >、_stdcall
a、 压栈方式与_cdecl一样,与之不一样的是堆栈的平衡不是由函数调用者完成,而是自身完成,在退出时自己清空堆栈。
b、 此种方式在函数返回是以 ret 8 指令来平衡堆栈,此处:ret 8 = add esp , 8。
< 3 >、上两种方式最为常用,此外还有fastcall ,thiscall, naked call,_pascal等 _pascal 入栈方式是从左到右。
下面通过一些例子来深入理解。
3、 跟踪汇编代码看函数参数的调用机制 我们看这样一个简单的函数,
编译器翻译的汇编指令如下:
< 1 >、void Test1(){}
据此画出内存布局图为:
< 2 >、有参数的情况
内存布布局如下:
4、 编写裸函数(不让系统加汇编的代码,而是人为的加上去)
比如:
在main函数调用的结果printf("%d\n", MyFunc());
练习:
< 1 >、无参数的情况(不在堆栈上展开)
< 2 >、有参数的情况(在堆栈上展开)
1、参数传递问题:
< 1 >、堆栈传参
< 2 >、寄存器传参(利用通用寄存器进行函数参数传递的方法)
< 3 >、全局变量或静态变量传参
2、 Call Convention(函数调用约定)
< 1 >、_cdecl
a、 参数从右向左压入堆栈
b、 函数被调用者修改堆栈
c、 在win32应用程序里,宏APIENTRY,WINAPI,都表示_stdcall,非常常见.
d、 C和C++程序的缺省调用方式。每一个调用它的函数都包含清空堆栈的代码,所以产生的可执行文件大小会比调用_stdcall函数的大。
< 2 >、_stdcall
a、 压栈方式与_cdecl一样,与之不一样的是堆栈的平衡不是由函数调用者完成,而是自身完成,在退出时自己清空堆栈。
b、 此种方式在函数返回是以 ret 8 指令来平衡堆栈,此处:ret 8 = add esp , 8。
< 3 >、上两种方式最为常用,此外还有fastcall ,thiscall, naked call,_pascal等 _pascal 入栈方式是从左到右。
下面通过一些例子来深入理解。
3、 跟踪汇编代码看函数参数的调用机制 我们看这样一个简单的函数,
编译器翻译的汇编指令如下:
< 1 >、void Test1(){}
void Test1() { 013516E0 push ebp 013516E1 mov ebp,esp 013516E3 sub esp,0C0h 013516E9 push ebx 013516EA push esi 013516EB push edi 013516EC lea edi,[ebp-0C0h] 013516F2 mov ecx,30h ;每次移四个字节,30h * 4 = 0C0h 013516F7 mov eax,0CCCCCCCCh 013516FC rep stos dword ptr es:[edi] ;将开辟的内存赋值为cc } 013516FE pop edi 013516FF pop esi 01351700 pop ebx 01351701 mov esp,ebp 01351703 pop ebp 01351704 ret ;--->编译器默认为_cdecl
据此画出内存布局图为:
< 2 >、有参数的情况
int _cdecl Test (int i, int j) { return j + i ++; } int _cdecl Test (int i, int j) { 01311690 push ebp 01311691 mov ebp,esp 01311693 sub esp,0C4h 01311699 push ebx 0131169A push esi 0131169B push edi 0131169C lea edi,[ebp-0C4h] 013116A2 mov ecx,31h ;31h * 4 = 0C4h 013116A7 mov eax,0CCCCCCCCh 013116AC rep stos dword ptr es:[edi] ;和上面无参的类型一样 return j + i ++; 013116AE mov eax,dword ptr [j] 013116B1 add eax,dword ptr [i] 013116B4 mov dword ptr [ebp-0C4h],eax 013116BA mov ecx,dword ptr [i] 013116BD add ecx,1 013116C0 mov dword ptr [i],ecx 013116C3 mov eax,dword ptr [ebp-0C4h] } 013116C9 pop edi 013116CA pop esi 013116CB pop ebx 013116CC mov esp,ebp 013116CE pop ebp 013116CF ret 34 00D21D88 push 2 ;在调用函数之前先将参数从右往左压入堆栈 35 00D21D8A mov eax,dword ptr [i] 36 00D21D8D push eax 00D21D8E call Test (0D211F4h) ;函数调用 38 00D21D93 add esp,8 ;平衡堆栈 39 00D21D96 mov dword ptr [i],eax
内存布布局如下:
4、 编写裸函数(不让系统加汇编的代码,而是人为的加上去)
比如:
int _declspec (naked) MyFunc() { _asm { push ebp mov ebp, esp sub esp, 0C0h push ebx push esi push edi lea edi, dword ptr [ebp - 0C0h] mov ecx, 30h mov eax, 0cccccccch rep stos dword ptr [edi] } _asm { mov eax, 8 ;返回值为8 } _asm { pop edi pop esi pop ebx mov esp, ebp ;平衡堆栈 pop ebp ret ;记得一定要返回 } }
在main函数调用的结果printf("%d\n", MyFunc());
练习:
< 1 >、无参数的情况(不在堆栈上展开)
void _declspec (naked) BlankFunc(void) { _asm { push ebp mov ebp, esp pushad popad mov esp, ebp pop ebp } }
< 2 >、有参数的情况(在堆栈上展开)
int Nest (int a, int b) { int nValue_1 = a; int nValue_2 = b; return nValue_1 + nValue_2; } int _declspec (naked) myFunc(int a, int b) { _asm { push ebp mov ebp, esp sub esp, 8 push edi push ebx push ecx lea edi, dword ptr [ebp - 8] mov ecx, 2 mov eax, 0cccccccch rep stos dword ptr [edi] } _asm { mov eax, dword ptr[ebp + 8] //有了上面的知识,这里就不难理解了。 mov dword ptr [ebp - 4], eax mov ebx, dword ptr[ebp + 12] mov dword ptr [ebp - 8], ebx add eax, ebx } _asm { pop edi pop ebx pop ecx mov esp, ebp pop ebp ret } }
相关文章推荐
- 大神洗礼第一讲——防御性编程相关
- Android 编程技巧之 ----- 不同情景 Activity 生命周期函数回调
- 网络(2):网络配置&socket编程相关的函数选项及异常处理
- 大神洗礼第二讲——内存对齐相关
- C语言编程技巧——signal(信号) 函数、信号机制及软中断详解
- C语言编程中分配内存空间的相关函数
- Javascript学习总结-技巧、实用函数、简介方法、编程细
- Linuxc网络编程的相关函数
- 理解socket与tcp/ip编程相关函数
- 以实例全面讲解PHP中多进程编程的相关函数的使用
- WordPress开发中短代码的实现及相关函数使用技巧
- const类对象和const成员函数的用法及编程技巧
- linux系统编程之进程(二):fork函数相关总结
- 网络socket编程相关函数
- VC++的Unicode编程--以及相关函数
- 用Windows API进行串口编程的一般步骤及相关函数讲解
- linux 时间编程相关函数
- 用Windows API进行串口编程的一般步骤及相关函数讲解
- java编程心得(十八)——关于日期的相关处理技巧
- C++ eof()函数相关应用技巧分享