C语言基础-函数调用栈

来源:互联网 发布:昆山远洋数据怎么样 编辑:程序博客网 时间:2024/05/17 04:25

        程序的执行流程,实际是连续的函数调用。函数调用通常使用堆栈实现,每个用户进程对应一个调用栈(call stack)结构。编译器使用堆栈传递函数参数、保存返回地址、临时保存寄存器原有值(即函数调用的上下文)以备恢复以及存储本地局部变量。

1 寄存器

         寄存器用于存放程序执行中用到的数据和指令 EAX(Return value of function) EBX(Local variables) ECX(counter for shifting and string operation) EDX(Dividend for division operation) ESI(store local variables) EDI(store local variables) (通用寄存器),ESP(stack pointer) EBP(base pointer)。在X86处理器中,EIP是特殊寄存器,指向处理器下条等待执行的指令地址(代码段内偏移量),每次执行完相应汇编指令EIP值就会增加,因而不能像访问通用寄存器一样访问他,EIP可以被jmp, call, ret等指令隐含改变。ESP存放堆栈指针寄存器,存放执行函数对应栈帧的栈顶地址(系统栈顶部),且始终指向栈顶;EBP是栈帧基址指针寄存器,存放执行函数对应栈帧的栈底地址,用于C运行库访问栈中共的局部变量和参数。

       栈寄存器是唯一能被所有函数共享的资源,虽然某一时刻只有一个函数在执行,但需要保证当某个函数调用其他函数时,被调用的函数不会修改或覆盖主调函数稍后会使用的寄存器值。主调函数保存寄存器(eax, ecx, edx )。

2 栈帧结构

        栈帧(stack frame)指每个未完成运行函数占用的一个独立连续区域。函数调用经常是嵌套的,同一时刻,堆栈中会有多个函数信息。栈帧是堆栈的逻辑片段,当调用函数时逻辑栈被压入堆栈,当函数返回时逻辑栈从堆栈弹出。堆栈存放着函数参数、局部变量和恢复前一栈需要的数据。

        编译器将控制权交给函数,将函数参数压入栈帧,并分配足够的内存空间用于存放函数中的局部变量。使用栈帧好处之一就是使递归变为可能,对函数的每次递归调用,都分配给函数一个新的栈帧,将当前调用和上次调用隔开。栈帧边界有栈帧基址指针和堆栈指针界定,函数中对大部分数据的访问都基于EBP进行。

      高地址是栈帧基址,压栈就是把ESP指针逐渐往低地址移动的过程。结构体成员变量的入栈顺序与其在结构体中声明顺序相反。函数调用以值传递时,传入的实参和被调函数内操作的形参两者存储地址不同,因而被调函数无法直接修改主调函数实参值,为达到修改目的,需要向被调函数传递实参变量的指针(变量地址)。

0 0