欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

程序员应了解的那些事(17)C语言过程活动记录(Active Record)/ ESP、EBP寄存器

程序员文章站 2022-03-06 19:04:22
...

【AR-1】

       活动记录,就是在程序执行的过程中函数调用时栈上的内容变化。一个函数被调用,反映在栈上的与之相关的内容被称为一帧,其中包含了参数、返回地址、老ebp值、局部变量以及esp和ebp。
       C语言默认的调用规约为cdecl,参数从右往左依次入栈,之后是函数的返回地址入栈,接着是老ebp入栈。
       ESP是栈顶指针,EBP就基指针寄存器,用它可以存取栈中的数据,向上(栈底方向)可以获取返回地址、参数值, 向下(栈顶方向)可以获取函数局部变量值。一般而言,SS:[ebp+4]处为返回地址;SS:[ebp+8]处为第一个参数值,SS:[ebp+0Ch]为第二个参数值;SS:[ebp-4]为第一个局部变量,SS:[ebp]处为上一层ebp值。

程序员应了解的那些事(17)C语言过程活动记录(Active Record)/ ESP、EBP寄存器

注1:__cdecl 是C Declaration的缩写(declaration,声明),表示C语言默认的函数调用方法:所有参数从右到左依次入栈,这些参数由调用者清除,称为手动清栈。 

注2:esp是栈指针,是cpu机制决定的,push、pop指令会自动调整esp的值;
         ebp只是存取某时刻的esp,这个时刻就是进入一个函数内后,cpu会将esp的值赋给ebp,此时就可以通过ebp对栈进行操作,比如获取函数参数,局部变量等,实际上使用esp也可以;

       既然使用esp也可以,那么为什么要设定ebp呢?答案是为了方便程序员。因为esp在函数运行时会不断的变化,所以保存一个一进入某个函数的esp到ebp中会方便程序员访问参数和局部变量,而且还方便调试器分析函数调用过程中的堆栈情况。前面说了,这个ebp不是必须要有的,你非要使用esp来访问函数参数和局部变量也是可行的,只不过这样会麻烦一些。

【AR-2】(参考C专家编程 6.5节)

       C 语言自动提供的服务之一就是跟踪调用链——哪些函数调用了哪些函数,当下一个return语句执行后,控制将返回何处等。解决这个问题的经典机制是堆栈中的活动记录。
       当每个函数被调用时,都会产生一个过程记录(或者类似的结构)。过程活动记录是一种数据结构,用于支持过程调用,并记录调用结束以后返回调用点所需要的全部信息。

程序员应了解的那些事(17)C语言过程活动记录(Active Record)/ ESP、EBP寄存器

         每当有一个函数调用时,就会在堆栈(Stack)上准备一个被称为AR(activation recored)的结构,抛开具体编译器实现细节的不同,这个AR基本结构如下所示。

程序员应了解的那些事(17)C语言过程活动记录(Active Record)/ ESP、EBP寄存器

每当遇到一次函数调用的语句,C编译器都会产生出汇编代码来在堆栈上分配这个AR。分析下面代码:
void a(int i)
{
    if(i > 0){
        a(--i);
    }
    else
    {
        printf("i = %d \n", i);
    }
}
int main(int argc, char** argv)
{
    a(1);
}

        在这一段代码中调用的顺序如下:

程序员应了解的那些事(17)C语言过程活动记录(Active Record)/ ESP、EBP寄存器

程序员应了解的那些事(17)C语言过程活动记录(Active Record)/ ESP、EBP寄存器

 

程序员应了解的那些事(17)C语言过程活动记录(Active Record)/ ESP、EBP寄存器

程序员应了解的那些事(17)C语言过程活动记录(Active Record)/ ESP、EBP寄存器

 

相关标签: 程序员应知应会