函数调用栈比较有意思

转载 2007年09月25日 14:49:00

函数调用栈比较有意思
作者:liigo

原文链接:http://blog.csdn.net/liigo/archive/2006/12/23/1456938.aspx

转载请注明出处:http://blog.csdn.net/liigo

 

昨天和海洋一块研究了下函数调用栈,顺便写两句。不足或错误之处请包涵!

理解调用栈最重要的两点是:栈的结构,EBP寄存器的作用。

首先要认识到这样两个事实:

1、一个函数调用动作可分解为:零到多个PUSH指令(用于参数入栈),一个CALL指令。CALL指令内部其实还暗含了一个将返回地址(即CALL指令下一条指令的地址)压栈的动作。

2、几乎所有本地编译器都会在每个函数体之前插入类似如下指令:PUSH EBP; MOV EBP ESP;

即,在程序执行到一个函数的真正函数体时,已经有以下数据顺序入栈:参数,返回地址,EBP。
由此得到类似如下的栈结构(参数入栈顺序跟调用方式有关,这里以C语言默认的CDECL为例):

+| (栈底方向,高位地址) |
 | .................... |
 | .................... |
 | 参数3                |
 | 参数2                |
 | 参数1                |
 | 返回地址             |
-| 上一层[EBP]          | <-------- [EBP]

“PUSH EBP”“MOV EBP ESP”这两条指令实在大有深意:首先将EBP入栈,然后将栈顶指针ESP赋值给EBP。“MOV EBP ESP”这条指令表面上看是用ESP把EBP原来的值覆盖了,其实不然——因为给EBP赋值之前,原EBP值已经被压栈(位于栈顶),而新的EBP又恰恰指向栈顶。

此时EBP寄存器就已经处于一个非常重要的地位,该寄存器中存储着栈中的一个地址(原EBP入栈后的栈顶),从该地址为基准,向上(栈底方向)能获取返回地址、参数值,向下(栈顶方向)能获取函数局部变量值,而该地址处又存储着上一层函数调用时的EBP值!

一般而言,ss:[ebp+4]处为返回地址,ss:[ebp+8]处为第一个参数值(最后一个入栈的参数值,此处假设其占用4字节内存),ss:[ebp-4]处为第一个局部变量,ss:[ebp]处为上一层EBP值。

由于EBP中的地址处总是“上一层函数调用时的EBP值”,而在每一层函数调用中,都能通过当时的EBP值“向上(栈底方向)能获取返回地址、参数值,向下(栈顶方向)能获取函数局部变量值”。
如此形成递归,直至到达栈底。这就是函数调用栈。

编译器对EBP的使用实在太精妙了。

从当前EBP出发,逐层向上找到所有的EBP是非常容易的:

unsigned int _ebp;
__asm _ebp, ebp;
while (not stack bottom)
{
    //...
    _ebp = *(unsigned int*)_ebp;
}

如果要写一个简单的调试器的话,注意需在被调试进程(而非当前进程——调试器进程)中读取内存数据。
 

函数调用栈比较有意思

函数调用栈比较有意思作者:liigo原文链接:http://blog.csdn.net/liigo/archive/2006/12/23/1456938.aspx转载请注明出处:http://blog...
  • liigo
  • liigo
  • 2006年12月23日 22:44
  • 8848

函数调用栈比较有意思

理解调用栈最重要的两点是:栈的结构,EBP寄存器的作用。首先要认识到这样两个事实:1、一个函数调用动作可分解为:零到多个PUSH指令(用于参数入栈),一个CALL指令。CALL指令内部其实还暗含了一个...
  • tanliyoung
  • tanliyoung
  • 2007年01月15日 10:19
  • 725

函数调用栈的获取原理分析

上一篇文章《在Linux程序中输出函数调用栈》,讲述了在Linux中如何利用backtrace获取调用栈,本篇文章主要介绍一下获取函数调用栈的原理,并给出相应的实现方式。 要了解调用栈,首先需要...
  • study_live
  • study_live
  • 2015年01月29日 17:56
  • 1512

显示函数调用栈

本文讲解如何在调试器中显示函数调用栈,如下图所示:   原理 首先我们来看一下显示调用栈所依据的原理。每个线程都有一个栈结构,用来记录函数的调用过程,这个栈是由高地址向低地址增长的,即栈底的地址比...
  • whatday
  • whatday
  • 2015年07月17日 10:52
  • 1580

比较有意思的Sql语句

1、分组取前N条数据select  * from 表 awhere 主键 in ( select top 3 主键 from 表 where 类别=a.类别order by 排序方式 )order b...
  • bendan999999999
  • bendan999999999
  • 2007年12月26日 15:28
  • 465

一个有趣的问题——根式

我很久之前就思考过这个问题,但没有多想。 今天重新想起这个问题觉得非常有趣。问题是这样的: 给你一个不超过六位小数的x,求a√b + c = x 使其满足0 ≤ a√b,c < 1e9,误差不超...
  • Keloyyc
  • Keloyyc
  • 2017年07月27日 07:48
  • 72

比较有意思的问题

1、不使用if else判断两个数的大小;(a*a/b+b*b/a)/(a/b+b/a) 2、不使用sizeof判断一个变量的所占的字节数; 3、不使用printf只用putchar输出int型的...
  • txgc0
  • txgc0
  • 2013年03月09日 15:05
  • 501

C函数调用与栈

3.4  C与汇编程序的相互调用为了提高代码执行效率,内核源代码中有的地方直接使用了汇编语言编制。这就会涉及在两种语言编制的程序之间的相互调用问题。本节首先说明C语言函数的调用机制,然后举例说明两者函...
  • zhaoneiep
  • zhaoneiep
  • 2010年08月09日 00:14
  • 6113

函数调用栈 剖析+图解

栈: 在函数调用时,第一个进栈的是主函数中函数调用后的下一条指令(函数调用语句的下一条可执行语句)的地址,然后是函数的各个参数,在大多数的C编译器中,参数是由右往左入栈的,然后是函数中的局部变量。注意...
  • wangyezi19930928
  • wangyezi19930928
  • 2013年11月25日 16:12
  • 19236

蛮有意思另类交友网

怎么找在火车上遇到的人?怎么找在地铁里遇到的人?在吗寻找一见钟情的人?等等,这也许是很多人遇到的问题。现在有一个网站专门用于寻找遇见过的人,名字叫昨天故事,地址http://www.zuotiangu...
  • hhsh123hhsh
  • hhsh123hhsh
  • 2016年11月08日 23:47
  • 181
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:函数调用栈比较有意思
举报原因:
原因补充:

(最多只允许输入30个字)