C语言程序的机器级表示

过程调用的机器级表示

特别说明该表示是基于IA-32指令系统,x86 64指令系统不同于IA-32

机器级表示

可执行文件的存储器映像

调用过程

 

IA-32的寄存器使用约定
– 调用者保存寄存器:EAX、EDX、ECX
    当过程P调用过程Q时,Q可以直接使用这三个寄存器,不用
    将它们的值保存到栈中。如果P在从Q返回后还要用这三个寄
    存器的话,P应在转到Q之前先保存,并在从Q返回后先恢复
    它们的值再使用。
– 被调用者保存寄存器:EBX、ESI、EDI
    Q必须先将它们的值保存到栈中再使用它们,并在返回P之前
    恢复它们的值。
– EBP和ESP分别是帧指针寄存器和栈指针寄存器,分别用来指
    向当前栈帧的底部和顶部。

过程调用过程中栈和栈帧的变化 (Q为被调用过程)

看一个简单的例子

 

过程解析

一个C过程的大致结构如下:
– 准备阶段
    • 形成帧底:push指令 和 mov指令
    • 生成栈帧(如果需要的话):sub指令 或 and指令
    • 保存现场(如果有被调用者保存寄存器) :mov指令
– 过程(函数)体
    • 分配局部变量空间,并赋值
    • 具体处理逻辑,如果遇到函数调用时
        – 准备参数:将实参送栈帧入口参数处
        – CALL指令:保存返回地址并转被调用函数
    • 在EAX中准备返回参数
– 结束阶段
    • 退栈:leave指令 或 pop指令
    • 取返回地址返回:ret指令

过程调用参数传递举例

 看一个递归函数的例子

int nn_sum ( int n)
{
    int result;
    if (n<=0 )
        result=0;
    else
        result=n+nn_sum(n-1);
    return result;
}

我们可以看出来,递归函数在不断的压栈生成栈帧,且没有到达最后一个递归的函数,他的栈帧并没有进行释放,所以

递归函数的空间和时间的开销都非常大(当达到他的极限值就会出现暴栈的情况)我们可以尽量不适用递归函数

猜你喜欢

转载自www.cnblogs.com/chenxuming/p/9689119.html