设为首页 加入收藏

TOP

VC++函数调用过程汇编分析(基于vs2012)
2014-11-23 18:54:30 】 浏览:3065
Tags:函数 调用 过程 汇编 分析 基于 vs2012

本文将在VS2012环境下对函数调用过程的汇编代码进行分析。分析不到位或者存在错误的地方请批评指正,请与作者联系。

#include 
  
   
#include 
   
     #include 
    
      #include 
     
       #include 
      
        #include 
       
         #include 
        
          using namespace std; int test(int a,int b){ int c; c = a + b; return c; } int main(){ int a =3,b =5; test(a,b); system("pause"); }
        
       
      
     
    
   
  

我们在main函数第一行代码处开始单步调试。

\

ebp寄存器通常指向栈底,常用来寻址当前函数内的局部变量等。esp是指向堆栈栈顶的指针。X86/64 vc++的堆栈是从高地址向低地址生长,比如push一个32位寄存器入栈后,esp - 04H。

第一行是push ebp,意思是将ebp入栈保护起来,虽然这个函数是main函数,但是流程和一般函数调用一样,都是先将ebp入栈保护。

mov ebp,esp 是将当前栈顶指针给ebp,使其能够寻址局部变量。

sub esp,0D8H 把栈顶指针esp移动到0D8H之后,这样留出一块隔离的空间,这个隔离空间的大小是由编译器决定的。默认的隔离空间是192字节。如果定义一个int会在栈空间里面占用12字节?局部变量也是存在隔离取内部的。< http://www.2cto.com/kf/ware/vc/" target="_blank" class="keylink">vcD4KPHA+cHVzaCBlc2k8L3A+CjxwPnB1c2ggZWR1PC9wPgo8cD5wdXNoIGVieDwvcD4KPHA+ysexo7ukz9azobXEM8z1u+Ox4Na4we6hozwvcD4KPHA+0qrA7b3ibGVhIGVkaSxbZWJwLTBEOEhdILXE0uLLvKOsz8jSqrjjx+Wz/mxlYbXE0uLLvKGjPC9wPgo8cD682cnoo7pTST0xMDAwSCAsIERTPTUwMDBILCAoNTEwMDBIKT0xMjM0SDwvcD4KCqGhoaHWtNDQ1rjB7iBMRUEgQlggLCBbU0lduvOjrEJYPTEwMDBICgqhoaGh1rTQ0Na4we4gTU9WIEJYICwgW1NJXbrzo6xCWD0xMjM0SDxicj4KPHA+PC9wPgo8cD7KtbzKyc++zcrHyKFbXcTase3KvrXEyv2+3bXExqvSxrXY1rehozwvcD4KPHA+PC9wPgo8cD4gbGVhICAgICAgICAgZWRpLFtlYnAtMTA4aF0gIDwvcD4KPHA+IG1vdiAgICAgICAgIGVjeCw0MmggIDwvcD4KPHA+IG1vdiAgICAgICAgIGVheCwwQ0NDQ0NDQ0NoICA8L3A+CjxwPjwvcD4KPHA+cmVwIHN0b3MgICAgZHdvcmQgcHRyIGVzOltlZGldPC9wPgo8cD48YnI+CjwvcD4KPHA+1eLLxL7kveG6z9Ta0rvG8L7Nyse21MH0s/a1xLj0wOvH+NPyus2+1rK/seTBv8v51by1xL/VvOS9+NDQx+W/1aOs1sPOqjB4Q0NDQ0NDQ0NIoaO9q8O/uPbX1r3a1sPOqjB4Q0NIysfT0NSt0vK1xKOsMHhDQ0jKx2ludCAztcTX1r3awuujrGludCAzyrG2z7Xj1tC2z9a4we6ho7Wx0uLN4rXE1rTQ0MHL1bvW0LXExNrI3cqxo6y74daxvdPM4cq+tO3O86GjPC9wPgo8cD7KtbzKyc/Kx1NUT1PWuMHutcTX99PDyse9q2VheNbQtcQmIzIwNTQwO7+9sbS1vUVTOkVESda4z/K1xLXY1reho3JlcNa4we7Kx9bYuLTWuMHuo6zW2Li0tM7K/bTm1Nq8xLTmxvdlY3jW0KGjNDJIyscxML341sa1xDY2o6y+zcrH1ti4tDY2tM6ho8O/tM69q9K7uPbX1rXEv9W85NbDzqplYXi1xCYjMjA1NDA7o6zW2Li0Nja0zr7Nx+W/1cHLMjY019a92qGj1f26w72ruPTA68f4us2+1rK/seTBv8v51by/1bzkx+W/1aGjPC9wPgo8YnI+CjxpbWcgc3JjPQ=="https://www.cppentry.com/upload_files/article/55/1_t6ddn__.png" alt="\">

mov dword ptr [a],3

mov dword ptr [b],5

将立即数写入栈空间。


下面是内存状况。

\

图1


\

因为下面要调用test函数,所以将a,b两个int型变量入栈。

入栈顺序为:

1.cdecl方式:C语言方式,参数从右边开始入栈。

2.winapi方式:参数还是从右边入栈。

\

上图是test函数的汇编代码。可以看出,与main函数的过程十分相似。首先也是将ebp入栈保存,因为这个时候的ebp还是main函数的,所以保存起来,然后把栈顶指针esp给ebp。现场保护和清空栈区域的代码与main函数中的几乎相同。

下一句是获取参数信息的。

mov eax,dword ptr [ebp+8]

这句ebp+8,实际上就是当前栈顶往栈底移动8个字节。从这里开始往后的4个字节放入eax。下面那句汇编意思相同。

ebp+8的原因是,在调用call命令的时候会将当前的EIP指针入栈。所以,这里后移8字节就能访问到参数了。

mov dword ptr [ebp-8],eax 这句将计算结果放入ebp-8的位置,也就是局部变量c所在的栈空间。

mov eax,dword ptr [ebp-8] 这句将[ebp - 8]栈的内容放入eax。函数的返回值就是通过eax寄存器返回的。


下面是内存状况:


图2

下面几句恢复现场。

pop edi

pop esi

pop ebx

mov esp,ebp

pop ebp

ret


mov esp,ebp 这句将当前基指传给栈顶指针。因为在test函数调用时,堆栈已经生长到这个地方了。

RET指令的内部操作是:栈顶字单元出栈,其值赋给IP寄存器。此时,IP指针就回到main函数继续执行了。

最后返回main函数后会执行一句

add esp,8 这句的意思是平衡刚才有传参占用的堆栈空间。从图2中可知,ret后,esp会回到参数b的下面。此时,+8会使esp回到调用test前的位置,即恢复了栈顶指针。


简单函数调用的汇编分析到此结束。下次分析new、malloc的区别。以及不同段的区别。


】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇vc中ASSERT()和VERIFY()区别 下一篇[VC++]003绘制连续线条-扇形线条

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目