上一篇讲解了 C 函数调用原理的一些基本概念,如果还没有完全理解可以回过头多看两遍。技术知识总需要反反复复回过头理解,每一次反复都能得到新的理解。
关于栈帧的建立和删除,下面用一个简单 C 程序实例来进行说明。
int add(int a,int b)
{
int result=a+b;
return result;
}
int main(int argc)
{
int answer;
answer=add(40,2);
return 0;
}
时刻保持持续学习的状态,每天会过得越来越充实。能坚持看到这里的读者朋友已经非常不容易了,每天多进步一点点,差距就会慢慢拉开的,加油!
言归正传,要了解 C 函数内部调用原理是离不开汇编代码的,下面列举了一些基础汇编代码,加上注释和配图就比较好理解其调用过程。
注:汇编代码框能够左右滑动,可左滑查看被隐藏部分。
call main #push return address into stack,jump into main
push %ebp #save current ebp register value
mov %esp,%ebp #copy esp to ebp
sub $12,%esp #make room for stack data
步骤 1 到 4 是调用 main 函数时建立栈帧的过程:
main 函数调用过程是通用的,基本上每个函数都要执行这个调用过程。调用过程可以简单理解为:如步骤 2 到步骤 4 所示,ebp 的当前值被保存到了栈的顶部,然后,将 esp 的内容拷贝到 ebp,esp 再指向新的栈顶,以建立一个新的栈帧。
mov $2,4(%esp) #set b to 22mov $40,(%esp) #set a to 40
call add #push return address into stack,jump into add
push %ebp #save current ebp register valve
mov %esp,%ebp #copy esp to ebp
sub $4,%esp #make room for result
mov 12(%ebp),%eax #move b to eax
mov 8(%ebp),%edx #move a to edx
add %edx,%eax #add edx into eax,total is 42
mov %eax,-4(%ebp) #copy eax to result
如步骤 11 所示,主调函数(main 函数)栈帧范围从 argc 到 answer,而被调函数(add 函数)栈帧范围从 b 到 result。至此,add 函数的调用过程结束,紧接着是 C 函数的返回过程。返回过程就下篇文章再讲解,敬请期待!