现象
首先我们运行下面一段代码:
从以上程序中我们可以知道,main函数调用函数fun1,函数fun1和main函数都没有调用函数fun,因此,我们认为函数fun中的"fun is run.."和 "you are done.."都不会被打印。
且main函数中的打印语句“begin run..”和“main: you should run here”都应该被打印
让我们来看看运行结果:
很明显,运行结果和我们预想的完全不同,这是为什么呢?
想要知道这其中的原因,让我们先回忆一下函数调用过程的栈帧:
栈帧
一个过程调用包括将数据(以过程参数和返回值的形式)和控制从代码的一部分传递到另一部分。另外,它还必须在进入时为过程的局部变量分配空间,并在退出时释放空间。
大多数机器,只提供转移控制到过程和从过程中转移出控制这种简单的指令。数据传递,局部变量的分配和释放通过操纵栈来实现的。为单个过程分配的那部分栈称为栈帧
下图是函数调用过程中的栈帧结构:
了解了栈帧的结构,让我们分析为什么没有被调用的函数会被执行?
原因分析
让我们根据汇编代码分析该程序
根据汇编指令,我们知道可以知道,main函数中调用函数fun时,将fun函数参数b,a压栈,返回地址0x080484b5压栈。
根据汇编代码,我们可以大致构建出main函数的栈帧:
查看fun1汇编代码:
通过读取fun1函数的代码,
int *p=&a;
p中保存的是a的地址p=ebp+8
--p;
p中保存a的空间的前一个空间的地址,为p=ebp+4,是函数调用后的返回地址
*p=fun;
将ebp+4空间中的值置为0x8048414(fun函数的地址)
总结原因
因此,函数调用的返回地址本应该是main函数中call指令的下一条指令的地址,而fun1函数中将函数调用后的返回地址修改为fun函数的地址,那么,当fun1函数调用完成后将跳转到返回地址处,该返回地址是fun函数的地址,那么,自然而然fun函数中的代码就被执行