唐建 + 《Linux内核分析》MOOC课程http://mooc.study.163.com/course/USTC-1000029000
一、本文目的
将自己跟踪linux c程序函数调用栈帧的情况mark 一下,以便后续可以查阅。网友们发现有误的,请直接指正。同时此文为我向孟宁老师学习内核的课间作业
二、函数原型
为了更加直观的描述栈帧,所以写了一个非常简单的函数调用例子,这样便于理解栈帧的情况。
三个函数连续调用,同时直接进行值传递和返回,并进行加法运算。
三、下面将函数汇编出来的汇编代码也贴出来以便。
从上往下分别是main() 、f()、g()三个函数。
从上面的汇编代码我们可以简单总结一下:
1、函数开始都是进行本函数的栈准备。
push %ebp——保存上一个函数的栈现场
push %esp,%ebp——开启当前函数的栈
2、函数调用前,会先将参数入栈,然后调用call
3、函数调用 call 实际上相当于 push %eip 和 goto 。保存当前函数的执行点,跳转到被调函数。
4、函数结束,都是回复上一个函数的栈
leave = mov %ebp,%esp 和 pop %ebp,这就是恢复上一个函数的栈
ret = pop %eip ——恢复上一个函数的执行点,就是该执行哪条指令了。
四、下面我们看一下通过汇编调试得到的栈帧
1、调用
Call 函数时会将跳转的下一条指令压栈:
于是我们贴出来调用f函数时的栈帧
上述红圈,栈底是到栈顶分别是入参(11)、下一条指令(0x8048406=134513670)、
f()调用g()函数一样,我们下面贴出g()函数被调用后整体的栈帧。
2、返回
ret指令就是讲下一条指令出栈给eip,下图贴出的是f函数ret 返回时的情况
Ret 完成后就回到了f函数的栈区了。同时大家可以下图看到,回到f函数后,会马上将之前的调用g函数的入栈的调用参数出栈——“add $0x4,%esp”
Leave 相当于
mov ebp ,esp
pop ebp
大家看下图,就是f函数返回时,栈帧的变换,栈变回了main函数的栈顶和栈底
函数的返回值是通过eax寄存器传递的