Jim Chan

摘要:本文说明高级语言编译成汇编语言后,高级语言中函数调用的汇编程序过程。

正文:高级语言编译成汇编程序以后,在高级语言中的函数调用的汇编程序过程如下:

1.将函数参数入栈,第一个参数在栈顶,最后一个参数在栈底。

2.执行CALL指令,调用该函数,进入该函数代码空间。
a.执行CALL指令,将CALL指令下一行代码的地址入栈。
b.进入函数代码空间后,将基址指针EBP入栈,然后让基址指针EBP指向当前堆栈栈顶,并使用它访问存在堆栈中的函数输入参数及堆栈中的其他数据。
c.堆栈指针ESP减少一个值,如44H,向上移动一个距离,留出一个空间给该函数作为临时存储区。
{
   // 以上准备工作做好后,函数正式被执行,如下所示。
   d.将其他指针或寄存器中的值入栈,以便在函数中使用这些寄存器。
   e.执行代码。
   f.执行return()返回执行结果,将要返回的值存入EAX中。
   g.步骤2.d中的指针出栈。
}
h.将EBP的值传给堆栈指针ESP,使ESP复原为2.c之前的值。此时进入函数时EBP的值在栈顶。
i.基址指针EBP出栈,复原为2.b之前的EBP的值。
j.执行RET指令,“调用函数”的地址出栈,本函数返回到CALL指令的下一行。

3.函数返回到CALL指令下一行,将堆栈指针加一个数值,以使堆栈指针恢复到以上步骤1执行之前的值。该数值是上面第一步入栈参数的总长度。

注意:
1.堆栈指针ESP指向栈顶的新入栈数据的最低位。
2.MOV指令中偏移指针指向被“MOV”的数据的最低位。如下面指令是将ebp+8到ebp+11四个字节的内容传到eax寄存器中。
00402048   mov         eax,dword ptr [ebp+8]

一个例子如下:

高级语言代码中的函数调用如下:

117:      bR = t1(p);

汇编代码如下:

00401FB8   mov         ecx,dword ptr [ebp-8]   ;将参数放入ecx寄存器
00401FBB   push        ecx                     ;参数入栈
00401FBC   call        @ILT+10(t1) (0040100f)  ;函数调用,下一行地址00401FC1入栈
00401FC1   add         esp,4                   ;函数返回,堆栈指针加4,复原为00401FB8时的值
00401FC4   mov         dword ptr [ebp-10h],eax ;从eax中取出高级语言中的函数返回值,放入bR变量中

其中t1函数如下:

125:  BOOL t1(void* p)
126:  {
00402030   push        ebp                    ;ebp入栈
00402031   mov         ebp,esp                ;ebp指向此时堆栈的栈顶
00402033   sub         esp,44h                ;esp减少一个值,空出一段存储区
00402036   push        ebx                    ;将三个寄存器的值入栈,以便在函数中使用它
00402037   push        esi                    ;
00402038   push        edi                    ;
00402039   lea         edi,[ebp-44h]          ;
0040203C   mov         ecx,11h                ;
00402041   mov         eax,0CCCCCCCCh         ;
00402046   rep stos    dword ptr [edi]        ;
127:      int* q = (int*)p;                   ;
00402048   mov         eax,dword ptr [ebp+8]  ;ebp+8指向函数输入参数的最低位地址;
;如果是ebp+4则指向函数返回地址00401FC1的最低位,值为C1
0040204B   mov         dword ptr [ebp-4],eax  ;
128:      return 0;                           ;
0040204E   xor         eax,eax                ;返回值放入eax寄存器中
129:  }
00402050   pop         edi                    ;三个寄存器出栈
00402051   pop         esi                    ;
00402052   pop         ebx                    ;
00402053   mov         esp,ebp                ;esp复原
00402055   pop         ebp                    ;ebp出栈,它的值也复原了
00402056   ret                                ;返回到此时栈顶存储的代码地址:00401FC1
;故而如果不幸被修改了返回地址,程序就会出现意外

以上汇编代码由VC++6.0编译得到。

堆栈在EBP入栈后的情况:

低位          高位
        ↓            ↓
内存地址      堆栈
        ┆            ┆
0012F600├──────┤← edi = 0012F600
        │            │
0012F604├─┄┄┄┄─┤
        │            │
        │            │
        ┆ 44h的空间  ┆
        ┆            ┆
        │            │
        │            │
0012F640├─┄┄┄┄─┤
        │            │
0012F644├──────┤← ebp被赋值后指向该单元,此时ebp=0012F644
        │AC F6 12 00 │ebp赋值为esp之前的值
0012F648├──────┤
        │C1 1F 40 00 │返回地址
0012F64C├──────┤← ebp + 8
        │A0 F6 12 00 │函数实参p的值
0012F650├──────┤
        │            │
        ├──────┤
        ┆            ┆

注:存储器存储空间堆栈按从高到低的排列,左边标注的地址是其右下方存储单元的最低位地址。如0012F644指向0012F6AC的AC字节,AC在栈顶。图中存储器中的内容按从低到高位书写,“AC F6 12 00”= 0x0012F6AC

转载于:https://blog.51cto.com/yushangyong/747376

高级语言反汇编程序的函数调用过程相关推荐

  1. 函数调用过程详解:函数栈帧的创建与销毁

    前言:我们在学习C语言的过程中,可以会产生很多疑问,比如: 局部变量是怎么创建的 为什么局部变量的值不做初始化就是随机值 函数是怎么传参的?传参的顺序是怎么样的? 形参和实参是什么关系? 函数调用是怎 ...

  2. 从函数调用过程中的堆栈变化理解缓冲区溢出

    一.说明 本来是想直接写一个缓冲区溢出的例子,但是一是当前编译器和操作系统有溢出的保护措施没有完全弄清怎么取消,二是strcpy等遇到00会截断需要进行编码这比较难搞,所以最终没有实现. 但已经双看了 ...

  3. 37.Linux驱动调试-根据oops的栈信息,确定函数调用过程

    上章链接入口: http://www.cnblogs.com/lifexy/p/8006748.html 在上章里,我们分析了oops的PC值在哪个函数出错的 本章便通过栈信息来分析函数调用过程 1. ...

  4. C语言的函数调用过程(栈帧的创建与销毁)

    从汇编的角度解析函数调用过程 看看下面这个简单函数的调用过程: 1 int Add(int x,int y)2 {3 int sum = 0;4 sum = x + y;5 return sum;6 ...

  5. Windows系统调用学习笔记(一)—— API函数调用过程

    Windows系统调用学习笔记(一)-- API函数调用过程 Windows API 实验1:分析ReadProcessMemory 第一步:定位函数 第二步:开始分析 总结 实验2:分析NtRead ...

  6. 深入理解C语言的函数调用过程

    深入理解C语言的函数调用过程 本文主要从进程栈空间的层面复习一下C语言中函数调用的具体过程,以加深对一些基础知识的理解.     先看一个最简单的程序: 点击(此处)折叠或打开 /*test.c*/ ...

  7. 深入浅出根据函数调用过程谈栈回溯原理

                通过分析函数调用过程的堆栈变化,可以看出在被调函数的EBP寄存器地址存放的是调用函数的EBP寄存器地址,EBP地址+4存放的是函数调用完成后的下一条指令存放地址,该指令的前一条 ...

  8. 函数调用过程简单分析

    C/C++函数调用过程分析 这里以一个简单的C语言代码为例,来分析函数调用过程 代码: 1 #include <stdio.h> 2 3 int func(int param1 ,int ...

  9. 函数调用过程实例详解

    原文标题:<函数调用过程探究> 引言 如何定义函数.调用函数,是每个程序员学习编程的入门课.调用函数(caller)向被调函数(callee)传入参数,被调函数返回结果,看似简单的过程,其 ...

最新文章

  1. PyTorch核心开发者灵魂发问:我们怎么越来越像Julia了?
  2. 大科学时代,指数级增长的科学仍然拥有前所未有的朝气与活力
  3. pycharm 运行celery_在 Pycharm 安装使用black的方法详解
  4. android edittext不可复制_Android EditText禁止复制粘贴
  5. linux收发十六进制工具,linux下的十六进制编辑器---wxHexEdit
  6. 200+猫在线待撸!来pick你最爱的那只!
  7. 10万元奖金语音识别赛进行中!CTC 模型 Baseline 助你轻松上分
  8. 最近开始接触网络电话
  9. 剑指offer之 旋转数组的最小数字
  10. python安装sqap_python文件I/O
  11. 做产品经理的第1年、第5年和第10年...
  12. 用c语言设计程序设计查表温度传感器,基于18B20温度传感器+1602液晶显示器的C语言程序设计开发...
  13. 查看在Ubuntu上打印的大型JSON文件
  14. C++实现复制文本粘贴文本功能
  15. mysql deadlock 记录_MySQL DeadLock故障排查全过程记录
  16. 事业单位考试计算机专业知识题库,计算机考试题库:计算机考试练习题(29)...
  17. 最全面的PS快捷键使用指南(图文演示)
  18. 考研408.计算机网络.特殊IP地址的记忆方法
  19. SQL获取当天0点0分0秒和23点59分59秒方法
  20. 2019/3/20统计单词数

热门文章

  1. Visual Studio 2010中的UML
  2. Java多线程初学者指南(12):使用Synchronized块同步变量
  3. 索引使用原则-联合索引最左匹配
  4. Spring IOC 容器根据Bean 名称或者类型进行autowiring 自动依赖注入
  5. 简单分析EnableAutoConfiguration
  6. maven的java工程取mysql数据库数据
  7. DataURL:实现原理及优缺点分析
  8. 数据库-聚合函数-count-sum
  9. ModelAttribute注解
  10. python操作php文件,python怎么操作文件